Home | History | Annotate | Download | only in X86
      1 ; We specify -mcpu explicitly to avoid instruction reordering that happens on
      2 ; some setups (e.g., Atom) from affecting the output.
      3 ; RUN: llc < %s -mcpu=core2 -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN32
      4 ; RUN: llc < %s -mcpu=core2 -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X86
      5 ; RUN: llc < %s -mcpu=core2 -mtriple=i686-pc-cygwin | FileCheck %s -check-prefix=CYGWIN
      6 ; RUN: llc < %s -mcpu=core2 -mtriple=i386-pc-linux | FileCheck %s -check-prefix=LINUX
      7 ; RUN: llc < %s -mcpu=core2 -O0 -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN32
      8 ; RUN: llc < %s -mcpu=core2 -O0 -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X86
      9 ; RUN: llc < %s -mcpu=core2 -O0 -mtriple=i686-pc-cygwin | FileCheck %s -check-prefix=CYGWIN
     10 ; RUN: llc < %s -mcpu=core2 -O0 -mtriple=i386-pc-linux | FileCheck %s -check-prefix=LINUX
     11 
     12 ; The SysV ABI used by most Unixes and Mingw on x86 specifies that an sret pointer
     13 ; is callee-cleanup. However, in MSVC's cdecl calling convention, sret pointer
     14 ; arguments are caller-cleanup like normal arguments.
     15 
     16 define void @sret1(i8* sret %x) nounwind {
     17 entry:
     18 ; WIN32-LABEL:      _sret1:
     19 ; WIN32:      movb $42, (%eax)
     20 ; WIN32-NOT:  popl %eax
     21 ; WIN32:    {{retl$}}
     22 
     23 ; MINGW_X86-LABEL:  _sret1:
     24 ; MINGW_X86:  {{retl$}}
     25 
     26 ; CYGWIN-LABEL:     _sret1:
     27 ; CYGWIN:     retl $4
     28 
     29 ; LINUX-LABEL:      sret1:
     30 ; LINUX:      retl $4
     31 
     32   store i8 42, i8* %x, align 4
     33   ret void
     34 }
     35 
     36 define void @sret2(i8* sret %x, i8 %y) nounwind {
     37 entry:
     38 ; WIN32-LABEL:      _sret2:
     39 ; WIN32:      movb {{.*}}, (%eax)
     40 ; WIN32-NOT:  popl %eax
     41 ; WIN32:    {{retl$}}
     42 
     43 ; MINGW_X86-LABEL:  _sret2:
     44 ; MINGW_X86:  {{retl$}}
     45 
     46 ; CYGWIN-LABEL:     _sret2:
     47 ; CYGWIN:     retl $4
     48 
     49 ; LINUX-LABEL:      sret2:
     50 ; LINUX:      retl $4
     51 
     52   store i8 %y, i8* %x
     53   ret void
     54 }
     55 
     56 define void @sret3(i8* sret %x, i8* %y) nounwind {
     57 entry:
     58 ; WIN32-LABEL:      _sret3:
     59 ; WIN32:      movb $42, (%eax)
     60 ; WIN32-NOT:  movb $13, (%eax)
     61 ; WIN32-NOT:  popl %eax
     62 ; WIN32:    {{retl$}}
     63 
     64 ; MINGW_X86-LABEL:  _sret3:
     65 ; MINGW_X86:  {{retl$}}
     66 
     67 ; CYGWIN-LABEL:     _sret3:
     68 ; CYGWIN:     retl $4
     69 
     70 ; LINUX-LABEL:      sret3:
     71 ; LINUX:      retl $4
     72 
     73   store i8 42, i8* %x
     74   store i8 13, i8* %y
     75   ret void
     76 }
     77 
     78 ; PR15556
     79 %struct.S4 = type { i32, i32, i32 }
     80 
     81 define void @sret4(%struct.S4* noalias sret %agg.result) {
     82 entry:
     83 ; WIN32-LABEL:     _sret4:
     84 ; WIN32:     movl $42, (%eax)
     85 ; WIN32-NOT: popl %eax
     86 ; WIN32:   {{retl$}}
     87 
     88 ; MINGW_X86-LABEL: _sret4:
     89 ; MINGW_X86: {{retl$}}
     90 
     91 ; CYGWIN-LABEL:    _sret4:
     92 ; CYGWIN:    retl $4
     93 
     94 ; LINUX-LABEL:     sret4:
     95 ; LINUX:     retl $4
     96 
     97   %x = getelementptr inbounds %struct.S4, %struct.S4* %agg.result, i32 0, i32 0
     98   store i32 42, i32* %x, align 4
     99   ret void
    100 }
    101 
    102 %struct.S5 = type { i32 }
    103 %class.C5 = type { i8 }
    104 
    105 define x86_thiscallcc void @"\01?foo@C5@@QAE?AUS5@@XZ"(%struct.S5* noalias sret %agg.result, %class.C5* %this) {
    106 entry:
    107   %this.addr = alloca %class.C5*, align 4
    108   store %class.C5* %this, %class.C5** %this.addr, align 4
    109   %this1 = load %class.C5*, %class.C5** %this.addr
    110   %x = getelementptr inbounds %struct.S5, %struct.S5* %agg.result, i32 0, i32 0
    111   store i32 42, i32* %x, align 4
    112   ret void
    113 ; WIN32-LABEL:     {{^}}"?foo@C5@@QAE?AUS5@@XZ":
    114 ; MINGW_X86-LABEL: {{^}}"?foo@C5@@QAE?AUS5@@XZ":
    115 ; CYGWIN-LABEL:    {{^}}"?foo@C5@@QAE?AUS5@@XZ":
    116 ; LINUX-LABEL:     {{^}}"?foo@C5@@QAE?AUS5@@XZ":
    117 
    118 ; The address of the return structure is passed as an implicit parameter.
    119 ; In the -O0 build, %eax is spilled at the beginning of the function, hence we
    120 ; should match both 4(%esp) and 8(%esp).
    121 ; WIN32:     {{[48]}}(%esp), %eax
    122 ; WIN32:     movl $42, (%eax)
    123 ; WIN32:     retl $4
    124 }
    125 
    126 define void @call_foo5() {
    127 entry:
    128   %c = alloca %class.C5, align 1
    129   %s = alloca %struct.S5, align 4
    130   call x86_thiscallcc void @"\01?foo@C5@@QAE?AUS5@@XZ"(%struct.S5* sret %s, %class.C5* %c)
    131 ; WIN32-LABEL:      {{^}}_call_foo5:
    132 ; MINGW_X86-LABEL:  {{^}}_call_foo5:
    133 ; CYGWIN-LABEL:     {{^}}_call_foo5:
    134 ; LINUX-LABEL:      {{^}}call_foo5:
    135 
    136 
    137 ; Load the address of the result and put it onto stack
    138 ; (through %ecx in the -O0 build).
    139 ; WIN32:      leal {{[0-9]+}}(%esp), %e{{[a-d]}}x
    140 ; WIN32:      movl %e{{[a-d]}}x, (%e{{([a-d]x)|(sp)}})
    141 
    142 ; The this pointer goes to ECX.
    143 ; WIN32-NEXT: leal {{[0-9]+}}(%esp), %ecx
    144 ; WIN32-NEXT: calll "?foo@C5@@QAE?AUS5@@XZ"
    145 ; WIN32:      retl
    146   ret void
    147 }
    148 
    149 
    150 %struct.test6 = type { i32, i32, i32 }
    151 define void @test6_f(%struct.test6* %x) nounwind {
    152 ; WIN32-LABEL: _test6_f:
    153 ; MINGW_X86-LABEL: _test6_f:
    154 ; CYGWIN-LABEL: _test6_f:
    155 ; LINUX-LABEL: test6_f:
    156 
    157 ; The %x argument is moved to %ecx. It will be the this pointer.
    158 ; WIN32: movl    20(%esp), %ecx
    159 
    160 ; The %x argument is moved to (%esp). It will be the this pointer. With -O0
    161 ; we copy esp to ecx and use (ecx) instead of (esp).
    162 ; MINGW_X86: movl    20(%esp), %eax
    163 ; MINGW_X86: movl    %eax, (%e{{([a-d]x)|(sp)}})
    164 
    165 ; CYGWIN: movl    20(%esp), %eax
    166 ; CYGWIN: movl    %eax, (%e{{([a-d]x)|(sp)}})
    167 
    168 ; The sret pointer is (%esp)
    169 ; WIN32:          leal    4(%esp), %[[REG:e[a-d]x]]
    170 ; WIN32-NEXT:     movl    %[[REG]], (%e{{([a-d]x)|(sp)}})
    171 
    172 ; The sret pointer is %ecx
    173 ; MINGW_X86-NEXT: leal    4(%esp), %ecx
    174 ; MINGW_X86-NEXT: calll   _test6_g
    175 
    176 ; CYGWIN-NEXT: leal    4(%esp), %ecx
    177 ; CYGWIN-NEXT: calll   _test6_g
    178 
    179   %tmp = alloca %struct.test6, align 4
    180   call x86_thiscallcc void @test6_g(%struct.test6* sret %tmp, %struct.test6* %x)
    181   ret void
    182 }
    183 declare x86_thiscallcc void @test6_g(%struct.test6* sret, %struct.test6*)
    184 
    185 ; Flipping the parameters at the IR level generates the same code.
    186 %struct.test7 = type { i32, i32, i32 }
    187 define void @test7_f(%struct.test7* %x) nounwind {
    188 ; WIN32-LABEL: _test7_f:
    189 ; MINGW_X86-LABEL: _test7_f:
    190 ; CYGWIN-LABEL: _test7_f:
    191 ; LINUX-LABEL: test7_f:
    192 
    193 ; The %x argument is moved to %ecx on all OSs. It will be the this pointer.
    194 ; WIN32:      movl    20(%esp), %ecx
    195 ; MINGW_X86:  movl    20(%esp), %ecx
    196 ; CYGWIN:     movl    20(%esp), %ecx
    197 
    198 ; The sret pointer is (%esp)
    199 ; WIN32:          leal    4(%esp), %[[REG:e[a-d]x]]
    200 ; WIN32-NEXT:     movl    %[[REG]], (%e{{([a-d]x)|(sp)}})
    201 ; MINGW_X86:      leal    4(%esp), %[[REG:e[a-d]x]]
    202 ; MINGW_X86-NEXT: movl    %[[REG]], (%e{{([a-d]x)|(sp)}})
    203 ; CYGWIN:         leal    4(%esp), %[[REG:e[a-d]x]]
    204 ; CYGWIN-NEXT:    movl    %[[REG]], (%e{{([a-d]x)|(sp)}})
    205 
    206   %tmp = alloca %struct.test7, align 4
    207   call x86_thiscallcc void @test7_g(%struct.test7* %x, %struct.test7* sret %tmp)
    208   ret void
    209 }
    210 
    211 define x86_thiscallcc void @test7_g(%struct.test7* %in, %struct.test7* sret %out) {
    212   %s = getelementptr %struct.test7, %struct.test7* %in, i32 0, i32 0
    213   %d = getelementptr %struct.test7, %struct.test7* %out, i32 0, i32 0
    214   %v = load i32, i32* %s
    215   store i32 %v, i32* %d
    216   call void @clobber_eax()
    217   ret void
    218 
    219 ; Make sure we return the second parameter in %eax.
    220 ; WIN32-LABEL: _test7_g:
    221 ; WIN32: calll _clobber_eax
    222 ; WIN32: movl {{.*}}, %eax
    223 ; WIN32: retl
    224 }
    225 
    226 declare void @clobber_eax()
    227 
    228 ; Test what happens if the first parameter has to be split by codegen.
    229 ; Realistically, no frontend will generate code like this, but here it is for
    230 ; completeness.
    231 define void @test8_f(i64 inreg %a, i64* sret %out) {
    232   store i64 %a, i64* %out
    233   call void @clobber_eax()
    234   ret void
    235 
    236 ; WIN32-LABEL: _test8_f:
    237 ; WIN32: movl {{[0-9]+}}(%esp), %[[out:[a-z]+]]
    238 ; WIN32-DAG: movl %edx, 4(%[[out]])
    239 ; WIN32-DAG: movl %eax, (%[[out]])
    240 ; WIN32: calll _clobber_eax
    241 ; WIN32: movl {{.*}}, %eax
    242 ; WIN32: retl
    243 }
    244