Home | History | Annotate | Download | only in X86
      1 ; RUN: llc -mtriple=x86_64-pc-windows-coreclr -verify-machineinstrs < %s | FileCheck %s
      2 
      3 declare void @ProcessCLRException()
      4 declare void @f(i32)
      5 declare void @g(i8 addrspace(1)*)
      6 declare i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token)
      7 
      8 ; Simplified IR for pseudo-C# like the following:
      9 ; void test1() {
     10 ;   try {
     11 ;     f(1);
     12 ;     try {
     13 ;       f(2);
     14 ;     } catch (type1) {
     15 ;       f(3);
     16 ;     } catch (type2) {
     17 ;       f(4);
     18 ;       try {
     19 ;         f(5);
     20 ;       } fault {
     21 ;         f(6);
     22 ;       }
     23 ;     }
     24 ;   } finally {
     25 ;     f(7);
     26 ;   }
     27 ;   f(8);
     28 ; }
     29 
     30 ; CHECK-LABEL: test1:     # @test1
     31 ; CHECK-NEXT: [[L_begin:.*func_begin.*]]:
     32 define void @test1() personality i8* bitcast (void ()* @ProcessCLRException to i8*) {
     33 entry:
     34 ; CHECK: # %entry
     35 ; CHECK: leaq [[FPOffset:[0-9]+]](%rsp), %rbp
     36 ; CHECK: .seh_endprologue
     37 ; CHECK: movq %rsp, [[PSPSymOffset:[0-9]+]](%rsp)
     38 ; CHECK: [[L_before_f1:.+]]:
     39 ; CHECK-NEXT: movl $1, %ecx
     40 ; CHECK-NEXT: callq f
     41 ; CHECK-NEXT: [[L_after_f1:.+]]:
     42   invoke void @f(i32 1)
     43     to label %inner_try unwind label %finally.pad
     44 inner_try:
     45 ; CHECK: # %inner_try
     46 ; CHECK: [[L_before_f2:.+]]:
     47 ; CHECK-NEXT: movl $2, %ecx
     48 ; CHECK-NEXT: callq f
     49 ; CHECK-NEXT: [[L_after_f2:.+]]:
     50   invoke void @f(i32 2)
     51     to label %finally.clone unwind label %catch1.pad
     52 catch1.pad:
     53   %cs1 = catchswitch within none [label %catch1.body, label %catch2.body] unwind label %finally.pad
     54 catch1.body:
     55   %catch1 = catchpad within %cs1 [i32 1]
     56 ; CHECK: .seh_proc [[L_catch1:[^ ]+]]
     57 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
     58 ;                        ^ all funclets use the same frame size
     59 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
     60 ;                              ^ establisher frame pointer passed in rcx
     61 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
     62 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
     63 ; CHECK: .seh_endprologue
     64 ; CHECK: movq %rdx, %rcx
     65 ;             ^ exception pointer passed in rdx
     66 ; CHECK-NEXT: callq g
     67   %exn1 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch1)
     68   call void @g(i8 addrspace(1)* %exn1) [ "funclet"(token %catch1) ]
     69 ; CHECK: [[L_before_f3:.+]]:
     70 ; CHECK-NEXT: movl $3, %ecx
     71 ; CHECK-NEXT: callq f
     72 ; CHECK-NEXT: [[L_after_f3:.+]]:
     73   invoke void @f(i32 3) [ "funclet"(token %catch1) ]
     74     to label %catch1.ret unwind label %finally.pad
     75 catch1.ret:
     76   catchret from %catch1 to label %finally.clone
     77 catch2.body:
     78   %catch2 = catchpad within %cs1 [i32 2]
     79 ; CHECK: .seh_proc [[L_catch2:[^ ]+]]
     80 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
     81 ;                        ^ all funclets use the same frame size
     82 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
     83 ;                              ^ establisher frame pointer passed in rcx
     84 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
     85 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
     86 ; CHECK: .seh_endprologue
     87 ; CHECK: movq %rdx, %rcx
     88 ;             ^ exception pointer passed in rdx
     89 ; CHECK-NEXT: callq g
     90   %exn2 = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch2)
     91   call void @g(i8 addrspace(1)* %exn2) [ "funclet"(token %catch2) ]
     92 ; CHECK: [[L_before_f4:.+]]:
     93 ; CHECK-NEXT: movl $4, %ecx
     94 ; CHECK-NEXT: callq f
     95 ; CHECK-NEXT: [[L_after_f4:.+]]:
     96   invoke void @f(i32 4) [ "funclet"(token %catch2) ]
     97     to label %try_in_catch unwind label %finally.pad
     98 try_in_catch:
     99 ; CHECK: # %try_in_catch
    100 ; CHECK: [[L_before_f5:.+]]:
    101 ; CHECK-NEXT: movl $5, %ecx
    102 ; CHECK-NEXT: callq f
    103 ; CHECK-NEXT: [[L_after_f5:.+]]:
    104   invoke void @f(i32 5) [ "funclet"(token %catch2) ]
    105     to label %catch2.ret unwind label %fault.pad
    106 fault.pad:
    107 ; CHECK: .seh_proc [[L_fault:[^ ]+]]
    108   %fault = cleanuppad within none [i32 undef]
    109 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
    110 ;                        ^ all funclets use the same frame size
    111 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
    112 ;                              ^ establisher frame pointer passed in rcx
    113 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
    114 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
    115 ; CHECK: .seh_endprologue
    116 ; CHECK: [[L_before_f6:.+]]:
    117 ; CHECK-NEXT: movl $6, %ecx
    118 ; CHECK-NEXT: callq f
    119 ; CHECK-NEXT: [[L_after_f6:.+]]:
    120   invoke void @f(i32 6) [ "funclet"(token %fault) ]
    121     to label %fault.ret unwind label %finally.pad
    122 fault.ret:
    123   cleanupret from %fault unwind label %finally.pad
    124 catch2.ret:
    125   catchret from %catch2 to label %finally.clone
    126 finally.clone:
    127   call void @f(i32 7)
    128   br label %tail
    129 finally.pad:
    130 ; CHECK: .seh_proc [[L_finally:[^ ]+]]
    131   %finally = cleanuppad within none []
    132 ; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
    133 ;                        ^ all funclets use the same frame size
    134 ; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
    135 ;                              ^ establisher frame pointer passed in rcx
    136 ; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
    137 ; CHECK: leaq [[FPOffset]](%rcx), %rbp
    138 ; CHECK: .seh_endprologue
    139 ; CHECK-NEXT: movl $7, %ecx
    140 ; CHECK-NEXT: callq f
    141   call void @f(i32 7) [ "funclet"(token %finally) ]
    142   cleanupret from %finally unwind to caller
    143 tail:
    144   call void @f(i32 8)
    145   ret void
    146 ; CHECK: [[L_end:.*func_end.*]]:
    147 }
    148 
    149 ; FIXME: Verify that the new clauses are correct and re-enable these checks.
    150 
    151 ; Now check for EH table in xdata (following standard xdata)
    152 ; CHECKX-LABEL: .section .xdata
    153 ; standard xdata comes here
    154 ; CHECKX:      .long 4{{$}}
    155 ;                   ^ number of funclets
    156 ; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
    157 ;                   ^ offset from L_begin to start of 1st funclet
    158 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
    159 ;                   ^ offset from L_begin to start of 2nd funclet
    160 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
    161 ;                   ^ offset from L_begin to start of 3rd funclet
    162 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    163 ;                   ^ offset from L_begin to start of 4th funclet
    164 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
    165 ;                   ^ offset from L_begin to end of last funclet
    166 ; CHECKX-NEXT: .long 7
    167 ;                   ^ number of EH clauses
    168 ; Clause 1: call f(2) is guarded by catch1
    169 ; CHECKX-NEXT: .long 0
    170 ;                   ^ flags (0 => catch handler)
    171 ; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
    172 ;                   ^ offset of start of clause
    173 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
    174 ;                   ^ offset of end of clause
    175 ; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
    176 ;                   ^ offset of start of handler
    177 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
    178 ;                   ^ offset of end of handler
    179 ; CHECKX-NEXT: .long 1
    180 ;                   ^ type token of catch (from catchpad)
    181 ; Clause 2: call f(2) is also guarded by catch2
    182 ; CHECKX-NEXT: .long 0
    183 ;                   ^ flags (0 => catch handler)
    184 ; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
    185 ;                   ^ offset of start of clause
    186 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
    187 ;                   ^ offset of end of clause
    188 ; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
    189 ;                   ^ offset of start of handler
    190 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
    191 ;                   ^ offset of end of handler
    192 ; CHECKX-NEXT: .long 2
    193 ;                   ^ type token of catch (from catchpad)
    194 ; Clause 3: calls f(1) and f(2) are guarded by finally
    195 ; CHECKX-NEXT: .long 2
    196 ;                   ^ flags (2 => finally handler)
    197 ; CHECKX-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
    198 ;                   ^ offset of start of clause
    199 ; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
    200 ;                   ^ offset of end of clause
    201 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    202 ;                   ^ offset of start of handler
    203 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
    204 ;                   ^ offset of end of handler
    205 ; CHECKX-NEXT: .long 0
    206 ;                   ^ type token slot (null for finally)
    207 ; Clause 4: call f(3) is guarded by finally
    208 ;           This is a "duplicate" because the protected range (f(3))
    209 ;           is in funclet catch1 but the finally's immediate parent
    210 ;           is the main function, not that funclet.
    211 ; CHECKX-NEXT: .long 10
    212 ;                   ^ flags (2 => finally handler | 8 => duplicate)
    213 ; CHECKX-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
    214 ;                   ^ offset of start of clause
    215 ; CHECKX-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
    216 ;                   ^ offset of end of clause
    217 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    218 ;                   ^ offset of start of handler
    219 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
    220 ;                   ^ offset of end of handler
    221 ; CHECKX-NEXT: .long 0
    222 ;                   ^ type token slot (null for finally)
    223 ; Clause 5: call f(5) is guarded by fault
    224 ; CHECKX-NEXT: .long 4
    225 ;                   ^ flags (4 => fault handler)
    226 ; CHECKX-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
    227 ;                   ^ offset of start of clause
    228 ; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
    229 ;                   ^ offset of end of clause
    230 ; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
    231 ;                   ^ offset of start of handler
    232 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    233 ;                   ^ offset of end of handler
    234 ; CHECKX-NEXT: .long 0
    235 ;                   ^ type token slot (null for fault)
    236 ; Clause 6: calls f(4) and f(5) are guarded by finally
    237 ;           This is a "duplicate" because the protected range (f(4)-f(5))
    238 ;           is in funclet catch2 but the finally's immediate parent
    239 ;           is the main function, not that funclet.
    240 ; CHECKX-NEXT: .long 10
    241 ;                   ^ flags (2 => finally handler | 8 => duplicate)
    242 ; CHECKX-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
    243 ;                   ^ offset of start of clause
    244 ; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
    245 ;                   ^ offset of end of clause
    246 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    247 ;                   ^ offset of start of handler
    248 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
    249 ;                   ^ offset of end of handler
    250 ; CHECKX-NEXT: .long 0
    251 ;                   ^ type token slot (null for finally)
    252 ; Clause 7: call f(6) is guarded by finally
    253 ;           This is a "duplicate" because the protected range (f(3))
    254 ;           is in funclet catch1 but the finally's immediate parent
    255 ;           is the main function, not that funclet.
    256 ; CHECKX-NEXT: .long 10
    257 ;                   ^ flags (2 => finally handler | 8 => duplicate)
    258 ; CHECKX-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
    259 ;                   ^ offset of start of clause
    260 ; CHECKX-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
    261 ;                   ^ offset of end of clause
    262 ; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
    263 ;                   ^ offset of start of handler
    264 ; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
    265 ;                   ^ offset of end of handler
    266 ; CHECKX-NEXT: .long 0
    267 ;                   ^ type token slot (null for finally)
    268