brintos

brintos / llvm-project-archived public Read only

0
0
Text · 27.7 KiB · a3d0fde Raw
712 lines · plain
1; RUN: llc -mtriple=x86_64-pc-windows-coreclr -verify-machineinstrs < %s | FileCheck %s2 3declare void @ProcessCLRException()4declare void @f(i32)5declare void @g(ptr addrspace(1))6declare ptr addrspace(1) @llvm.eh.exceptionpointer.p1(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:     # @test131; CHECK-NEXT: [[test1_begin:.*func_begin.*]]:32define void @test1() personality ptr @ProcessCLRException {33entry:34; CHECK: # %entry35; CHECK: leaq [[FPOffset:[0-9]+]](%rsp), %rbp36; CHECK: .seh_endprologue37; CHECK: movq %rsp, [[PSPSymOffset:[0-9]+]](%rsp)38; CHECK: [[test1_before_f1:.+]]:39; CHECK-NEXT: movl $1, %ecx40; CHECK-NEXT: callq f41; CHECK-NEXT: nop42; CHECK-NEXT: [[test1_after_f1:.+]]:43  invoke void @f(i32 1)44    to label %inner_try unwind label %finally45inner_try:46; CHECK: # %inner_try47; CHECK: [[test1_before_f2:.+]]:48; CHECK-NEXT: movl $2, %ecx49; CHECK-NEXT: callq f50; CHECK-NEXT: nop51; CHECK-NEXT: [[test1_after_f2:.+]]:52  invoke void @f(i32 2)53    to label %finally.clone unwind label %exn.dispatch54exn.dispatch:55  %catchswitch = catchswitch within none [label %catch1, label %catch2] unwind label %finally56catch1:57  %catch.pad1 = catchpad within %catchswitch [i32 1]58; CHECK: .seh_proc [[test1_catch1:[^ ]+]]59; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]60;                        ^ all funclets use the same frame size61; CHECK: movq [[PSPSymOffset]](%rcx), %rcx62;                              ^ establisher frame pointer passed in rcx63; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)64; CHECK: leaq [[FPOffset]](%rcx), %rbp65; CHECK: .seh_endprologue66; CHECK: movq %rdx, %rcx67;             ^ exception pointer passed in rdx68; CHECK-NEXT: callq g69  %exn1 = call ptr addrspace(1) @llvm.eh.exceptionpointer.p1(token %catch.pad1)70  call void @g(ptr addrspace(1) %exn1) [ "funclet"(token %catch.pad1) ]71; CHECK: [[test1_before_f3:.+]]:72; CHECK-NEXT: movl $3, %ecx73; CHECK-NEXT: callq f74; CHECK-NEXT: nop75; CHECK-NEXT: [[test1_after_f3:.+]]:76  invoke void @f(i32 3) [ "funclet"(token %catch.pad1) ]77    to label %catch1.ret unwind label %finally78catch1.ret:79  catchret from %catch.pad1 to label %finally.clone80catch2:81  %catch.pad2 = catchpad within %catchswitch [i32 2]82; CHECK: .seh_proc [[test1_catch2:[^ ]+]]83; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]84;                        ^ all funclets use the same frame size85; CHECK: movq [[PSPSymOffset]](%rcx), %rcx86;                              ^ establisher frame pointer passed in rcx87; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)88; CHECK: leaq [[FPOffset]](%rcx), %rbp89; CHECK: .seh_endprologue90; CHECK: movq %rdx, %rcx91;             ^ exception pointer passed in rdx92; CHECK-NEXT: callq g93  %exn2 = call ptr addrspace(1) @llvm.eh.exceptionpointer.p1(token %catch.pad2)94  call void @g(ptr addrspace(1) %exn2) [ "funclet"(token %catch.pad2) ]95; CHECK: [[test1_before_f4:.+]]:96; CHECK-NEXT: movl $4, %ecx97; CHECK-NEXT: callq f98; CHECK-NEXT: nop99; CHECK-NEXT: [[test1_after_f4:.+]]:100  invoke void @f(i32 4) [ "funclet"(token %catch.pad2) ]101    to label %try_in_catch unwind label %finally102try_in_catch:103; CHECK: # %try_in_catch104; CHECK: [[test1_before_f5:.+]]:105; CHECK-NEXT: movl $5, %ecx106; CHECK-NEXT: callq f107; CHECK-NEXT: nop108; CHECK-NEXT: [[test1_after_f5:.+]]:109  invoke void @f(i32 5) [ "funclet"(token %catch.pad2) ]110    to label %catch2.ret unwind label %fault111fault:112; CHECK: .seh_proc [[test1_fault:[^ ]+]]113  %fault.pad = cleanuppad within %catch.pad2 [i32 undef]114; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]115;                        ^ all funclets use the same frame size116; CHECK: movq [[PSPSymOffset]](%rcx), %rcx117;                              ^ establisher frame pointer passed in rcx118; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)119; CHECK: leaq [[FPOffset]](%rcx), %rbp120; CHECK: .seh_endprologue121; CHECK: [[test1_before_f6:.+]]:122; CHECK-NEXT: movl $6, %ecx123; CHECK-NEXT: callq f124; CHECK-NEXT: nop125; CHECK-NEXT: [[test1_after_f6:.+]]:126  invoke void @f(i32 6) [ "funclet"(token %fault.pad) ]127    to label %fault.ret unwind label %finally128fault.ret:129  cleanupret from %fault.pad unwind label %finally130catch2.ret:131  catchret from %catch.pad2 to label %finally.clone132finally.clone:133  call void @f(i32 7)134  br label %tail135finally:136; CHECK: .seh_proc [[test1_finally:[^ ]+]]137  %finally.pad = cleanuppad within none []138; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]139;                        ^ all funclets use the same frame size140; CHECK: movq [[PSPSymOffset]](%rcx), %rcx141;                              ^ establisher frame pointer passed in rcx142; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)143; CHECK: leaq [[FPOffset]](%rcx), %rbp144; CHECK: .seh_endprologue145; CHECK-NEXT: movl $7, %ecx146; CHECK-NEXT: callq f147  call void @f(i32 7) [ "funclet"(token %finally.pad) ]148  cleanupret from %finally.pad unwind to caller149tail:150  call void @f(i32 8)151  ret void152; CHECK: [[test1_end:.*func_end.*]]:153}154 155; Now check for EH table in xdata (following standard xdata)156; CHECK-LABEL: .section .xdata157; standard xdata comes here158; CHECK:      .long 4{{$}}159;                   ^ number of funclets160; CHECK-NEXT: .long [[test1_catch1]]-[[test1_begin]]161;                   ^ offset from L_begin to start of 1st funclet162; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]163;                   ^ offset from L_begin to start of 2nd funclet164; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]165;                   ^ offset from L_begin to start of 3rd funclet166; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]167;                   ^ offset from L_begin to start of 4th funclet168; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]169;                   ^ offset from L_begin to end of last funclet170; CHECK-NEXT: .long 7171;                   ^ number of EH clauses172; Clause 1: call f(2) is guarded by catch1173; CHECK-NEXT: .long 0174;                   ^ flags (0 => catch handler)175; CHECK-NEXT: .long [[test1_before_f2]]-[[test1_begin]]+1176;                   ^ offset of start of clause177; CHECK-NEXT: .long [[test1_after_f2]]-[[test1_begin]]+1178;                   ^ offset of end of clause179; CHECK-NEXT: .long [[test1_catch1]]-[[test1_begin]]180;                   ^ offset of start of handler181; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]182;                   ^ offset of end of handler183; CHECK-NEXT: .long 1184;                   ^ type token of catch (from catchpad)185; Clause 2: call f(2) is also guarded by catch2186; CHECK-NEXT: .long 0187;                   ^ flags (0 => catch handler)188; CHECK-NEXT: .long [[test1_before_f2]]-[[test1_begin]]+1189;                   ^ offset of start of clause190; CHECK-NEXT: .long [[test1_after_f2]]-[[test1_begin]]+1191;                   ^ offset of end of clause192; CHECK-NEXT: .long [[test1_catch2]]-[[test1_begin]]193;                   ^ offset of start of handler194; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]195;                   ^ offset of end of handler196; CHECK-NEXT: .long 2197;                   ^ type token of catch (from catchpad)198; Clause 3: calls f(1) and f(2) are guarded by finally199; CHECK-NEXT: .long 2200;                   ^ flags (2 => finally handler)201; CHECK-NEXT: .long [[test1_before_f1]]-[[test1_begin]]+1202;                   ^ offset of start of clause203; CHECK-NEXT: .long [[test1_after_f2]]-[[test1_begin]]+1204;                   ^ offset of end of clause205; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]206;                   ^ offset of start of handler207; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]208;                   ^ offset of end of handler209; CHECK-NEXT: .long 0210;                   ^ type token slot (null for finally)211; Clause 4: call f(3) is guarded by finally212;           This is a "duplicate" because the protected range (f(3))213;           is in funclet catch1 but the finally's immediate parent214;           is the main function, not that funclet.215; CHECK-NEXT: .long 10216;                   ^ flags (2 => finally handler | 8 => duplicate)217; CHECK-NEXT: .long [[test1_before_f3]]-[[test1_begin]]+1218;                   ^ offset of start of clause219; CHECK-NEXT: .long [[test1_after_f3]]-[[test1_begin]]+1220;                   ^ offset of end of clause221; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]222;                   ^ offset of start of handler223; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]224;                   ^ offset of end of handler225; CHECK-NEXT: .long 0226;                   ^ type token slot (null for finally)227; Clause 5: call f(5) is guarded by fault228; CHECK-NEXT: .long 4229;                   ^ flags (4 => fault handler)230; CHECK-NEXT: .long [[test1_before_f5]]-[[test1_begin]]+1231;                   ^ offset of start of clause232; CHECK-NEXT: .long [[test1_after_f5]]-[[test1_begin]]+1233;                   ^ offset of end of clause234; CHECK-NEXT: .long [[test1_fault]]-[[test1_begin]]235;                   ^ offset of start of handler236; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]237;                   ^ offset of end of handler238; CHECK-NEXT: .long 0239;                   ^ type token slot (null for fault)240; Clause 6: calls f(4) and f(5) are guarded by finally241;           This is a "duplicate" because the protected range (f(4)-f(5))242;           is in funclet catch2 but the finally's immediate parent243;           is the main function, not that funclet.244; CHECK-NEXT: .long 10245;                   ^ flags (2 => finally handler | 8 => duplicate)246; CHECK-NEXT: .long [[test1_before_f4]]-[[test1_begin]]+1247;                   ^ offset of start of clause248; CHECK-NEXT: .long [[test1_after_f5]]-[[test1_begin]]+1249;                   ^ offset of end of clause250; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]251;                   ^ offset of start of handler252; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]253;                   ^ offset of end of handler254; CHECK-NEXT: .long 0255;                   ^ type token slot (null for finally)256; Clause 7: call f(6) is guarded by finally257;           This is a "duplicate" because the protected range (f(3))258;           is in funclet catch1 but the finally's immediate parent259;           is the main function, not that funclet.260; CHECK-NEXT: .long 10261;                   ^ flags (2 => finally handler | 8 => duplicate)262; CHECK-NEXT: .long [[test1_before_f6]]-[[test1_begin]]+1263;                   ^ offset of start of clause264; CHECK-NEXT: .long [[test1_after_f6]]-[[test1_begin]]+1265;                   ^ offset of end of clause266; CHECK-NEXT: .long [[test1_finally]]-[[test1_begin]]267;                   ^ offset of start of handler268; CHECK-NEXT: .long [[test1_end]]-[[test1_begin]]269;                   ^ offset of end of handler270; CHECK-NEXT: .long 0271;                   ^ type token slot (null for finally)272 273; Test with a cleanup that has no cleanupret, and thus needs its unwind dest274; inferred from an inner catchswitch275;276; corresponds to C# along the lines of:277; void test2() {278;   try {279;     try {280;       f(1);281;     } fault {282;       try {283;         f(2);284;       } catch(type1) {285;       }286;       __unreachable();287;     }288;   } catch(type2) {289;   }290; }291;292define void @test2() personality ptr @ProcessCLRException {293entry:294  invoke void @f(i32 1)295    to label %exit unwind label %fault296fault:297  %fault.pad = cleanuppad within none [i32 undef]298  invoke void @f(i32 2) ["funclet"(token %fault.pad)]299    to label %unreachable unwind label %exn.dispatch.inner300exn.dispatch.inner:301  %catchswitch.inner = catchswitch within %fault.pad [label %catch1] unwind label %exn.dispatch.outer302catch1:303  %catch.pad1 = catchpad within %catchswitch.inner [i32 1]304  catchret from %catch.pad1 to label %unreachable305exn.dispatch.outer:306  %catchswitch.outer = catchswitch within none [label %catch2] unwind to caller307catch2:308  %catch.pad2 = catchpad within %catchswitch.outer [i32 2]309  catchret from %catch.pad2 to label %exit310exit:311  ret void312unreachable:313  unreachable314}315; CHECK-LABEL: test2:     # @test2316; CHECK-NEXT: [[test2_begin:.*func_begin.*]]:317; CHECK: .seh_endprologue318; CHECK: [[test2_before_f1:.+]]:319; CHECK-NEXT: movl $1, %ecx320; CHECK-NEXT: callq f321; CHECK-NEXT: nop322; CHECK-NEXT: [[test2_after_f1:.+]]:323; CHECK: .seh_proc [[test2_catch1:[^ ]+]]324; CHECK: .seh_proc [[test2_catch2:[^ ]+]]325; CHECK: .seh_proc [[test2_fault:[^ ]+]]326; CHECK: .seh_endprologue327; CHECK: [[test2_before_f2:.+]]:328; CHECK-NEXT: movl $2, %ecx329; CHECK-NEXT: callq f330; CHECK-NEXT: nop331; CHECK-NEXT: [[test2_after_f2:.+]]:332; CHECK: int3333; CHECK: [[test2_end:.*func_end.*]]:334 335 336; Now check for EH table in xdata (following standard xdata)337; CHECK-LABEL: .section .xdata338; standard xdata comes here339; CHECK:      .long 3{{$}}340;                   ^ number of funclets341; CHECK-NEXT: .long [[test2_catch1]]-[[test2_begin]]342;                   ^ offset from L_begin to start of 2nd funclet343; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]344;                   ^ offset from L_begin to start of 3rd funclet345; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]346;                   ^ offset from L_begin to start of 1st funclet347; CHECK-NEXT: .long [[test2_end]]-[[test2_begin]]348;                   ^ offset from L_begin to end of last funclet349; CHECK-NEXT: .long 4350;                   ^ number of EH clauses351; Clause 1: call f(1) is guarded by fault352; CHECK-NEXT: .long 4353;                   ^ flags (4 => fault handler)354; CHECK-NEXT: .long [[test2_before_f1]]-[[test2_begin]]+1355;                   ^ offset of start of clause356; CHECK-NEXT: .long [[test2_after_f1]]-[[test2_begin]]+1357;                   ^ offset of end of clause358; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]359;                   ^ offset of start of handler360; CHECK-NEXT: .long [[test2_end]]-[[test2_begin]]361;                   ^ offset of end of handler362; CHECK-NEXT: .long 0363;                   ^ type token slot (null for fault)364; Clause 2: call f(1) is also guarded by catch2365; CHECK-NEXT: .long 0366;                   ^ flags (0 => catch handler)367; CHECK-NEXT: .long [[test2_before_f1]]-[[test2_begin]]+1368;                   ^ offset of start of clause369; CHECK-NEXT: .long [[test2_after_f1]]-[[test2_begin]]+1370;                   ^ offset of end of clause371; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]372;                   ^ offset of start of handler373; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]374;                   ^ offset of end of handler375; CHECK-NEXT: .long 2376;                   ^ type token of catch (from catchpad)377; Clause 3: calls f(2) is guarded by catch1378; CHECK-NEXT: .long 0379;                   ^ flags (0 => catch handler)380; CHECK-NEXT: .long [[test2_before_f2]]-[[test2_begin]]+1381;                   ^ offset of start of clause382; CHECK-NEXT: .long [[test2_after_f2]]-[[test2_begin]]+1383;                   ^ offset of end of clause384; CHECK-NEXT: .long [[test2_catch1]]-[[test2_begin]]385;                   ^ offset of start of handler386; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]387;                   ^ offset of end of handler388; CHECK-NEXT: .long 1389;                   ^ type token of catch (from catchpad)390; Clause 4: call f(2) is also guarded by catch2391;           This is a "duplicate" because the protected range (f(2))392;           is in funclet fault but catch2's immediate parent393;           is the main function, not that funclet.394; CHECK-NEXT: .long 8395;                   ^ flags (0 => catch handler | 8 => duplicate)396; CHECK-NEXT: .long [[test2_before_f2]]-[[test2_begin]]+1397;                   ^ offset of start of clause398; CHECK-NEXT: .long [[test2_after_f2]]-[[test2_begin]]+1399;                   ^ offset of end of clause400; CHECK-NEXT: .long [[test2_catch2]]-[[test2_begin]]401;                   ^ offset of start of handler402; CHECK-NEXT: .long [[test2_fault]]-[[test2_begin]]403;                   ^ offset of end of handler404; CHECK-NEXT: .long 2405;                   ^ type token of catch (from catchpad)406 407; Test with several cleanups that need to infer their unwind dests from each408; other, the inner one needing to make the inference from an invoke, ignoring409; not-really-unwinding calls/unwind-to-caller catchswitches, as well as some410; internal invokes/catchswitches411;412; Corresponds to something like:413; void test3() {414;   try {415;     f(1);416;   } fault { // fault1417;     try {418;       try {419;         f(2);420;         __unreachable();421;       } fault { // fault2422;         try {423;           f(3);424;         } fault { // fault3425;           try {426;             f(4);427;           } fault { // fault4428;             f(5); // no unwind edge (e.g. front-end knew it wouldn't throw but429;                    didn't bother to specify nounwind)430;             try {431;               try {432;                 f(6);433;               } catch(type 1) {434;                 goto __unreachable;435;               }436;             } catch (type 2) { // marked "unwinds to caller" because we allow437;                                // that if the unwind won't be taken (see438;                                // SimplifyUnreachable & RemoveUnwindEdge)439;               goto _unreachable;440;             }441;             f(7);442;             __unreachable();443;           }444;         }445;       }446;     } fault { // fault 5447;     }448;   }449; }450;451; CHECK-LABEL: test3:     # @test3452; CHECK-NEXT: [[test3_begin:.*func_begin.*]]:453define void @test3() personality ptr @ProcessCLRException {454entry:455; CHECK: .seh_endprologue456; CHECK: [[test3_before_f1:.+]]:457; CHECK-NEXT: movl $1, %ecx458; CHECK-NEXT: callq f459; CHECK-NEXT: nop460; CHECK-NEXT: [[test3_after_f1:.+]]:461  invoke void @f(i32 1)462    to label %exit unwind label %fault1463fault1:464 ; check lines below since this gets reordered to end-of-func465  %fault.pad1 = cleanuppad within none [i32 undef]466  invoke void @f(i32 2) ["funclet"(token %fault.pad1)]467    to label %unreachable unwind label %fault2468fault2:469 ; check lines below since this gets reordered to end-of-func470  %fault.pad2 = cleanuppad within %fault.pad1 [i32 undef]471  invoke void @f(i32 3) ["funclet"(token %fault.pad2)]472    to label %unreachable unwind label %fault3473fault3:474 ; check lines below since this gets reordered to end-of-func475  %fault.pad3 = cleanuppad within %fault.pad2 [i32 undef]476  invoke void @f(i32 4) ["funclet"(token %fault.pad3)]477    to label %unreachable unwind label %fault4478fault4:479; CHECK: .seh_proc [[test3_fault4:[^ ]+]]480  %fault.pad4 = cleanuppad within %fault.pad3 [i32 undef]481; CHECK: .seh_endprologue482  call void @f(i32 5) ["funclet"(token %fault.pad4)]483; CHECK: [[test3_before_f6:.+]]:484; CHECK-NEXT: movl $6, %ecx485; CHECK-NEXT: callq f486; CHECK-NEXT: nop487; CHECK-NEXT: [[test3_after_f6:.+]]:488  invoke void @f(i32 6) ["funclet"(token %fault.pad4)]489    to label %fault4.cont unwind label %exn.dispatch1490fault4.cont:491; CHECK: # %fault4.cont492; CHECK: [[test3_before_f7:.+]]:493; CHECK-NEXT: movl $7, %ecx494; CHECK-NEXT: callq f495; CHECK-NEXT: nop496; CHECK-NEXT: [[test3_after_f7:.+]]:497  invoke void @f(i32 7) ["funclet"(token %fault.pad4)]498    to label %unreachable unwind label %fault5499exn.dispatch1:500  %catchswitch1 = catchswitch within %fault.pad4 [label %catch1] unwind label %exn.dispatch2501catch1:502  %catch.pad1 = catchpad within %catchswitch1 [i32 1]503; CHECK: .seh_proc [[test3_catch1:[^ ]+]]504  catchret from %catch.pad1 to label %unreachable505exn.dispatch2:506  %catchswitch2 = catchswitch within %fault.pad4 [label %catch2] unwind to caller507catch2:508  %catch.pad2 = catchpad within %catchswitch2 [i32 2]509; CHECK: .seh_proc [[test3_catch2:[^ ]+]]510  catchret from %catch.pad2 to label %unreachable511fault5:512; CHECK: .seh_proc [[test3_fault5:[^ ]+]]513  %fault.pad5 = cleanuppad within %fault.pad1 [i32 undef]514; CHECK: .seh_endprologue515cleanupret from %fault.pad5 unwind to caller516exit:517  ret void518unreachable:519  unreachable520; CHECK: .seh_proc [[test3_fault3:[^ ]+]]521; CHECK: # %fault3522; CHECK: .seh_endprologue523; CHECK: [[test3_before_f4:.+]]:524; CHECK-NEXT: movl $4, %ecx525; CHECK-NEXT: callq f526; CHECK-NEXT: nop527; CHECK-NEXT: [[test3_after_f4:.+]]:528; CHECK: int3529; CHECK: .seh_proc [[test3_fault2:[^ ]+]]530; CHECK: # %fault2531; CHECK: .seh_endprologue532; CHECK: [[test3_before_f3:.+]]:533; CHECK-NEXT: movl $3, %ecx534; CHECK-NEXT: callq f535; CHECK-NEXT: nop536; CHECK-NEXT: [[test3_after_f3:.+]]:537; CHECK: int3538; CHECK: .seh_proc [[test3_fault1:[^ ]+]]539; CHECK: # %fault1540; CHECK: .seh_endprologue541; CHECK: [[test3_before_f2:.+]]:542; CHECK-NEXT: movl $2, %ecx543; CHECK-NEXT: callq f544; CHECK-NEXT: nop545; CHECK-NEXT: [[test3_after_f2:.+]]:546; CHECK: int3547; CHECK: [[test3_end:.*func_end.*]]:548}549 550; Now check for EH table in xdata (following standard xdata)551; CHECK-LABEL: .section .xdata552; standard xdata comes here553; CHECK:      .long 7{{$}}554;                   ^ number of funclets555; CHECK-NEXT: .long [[test3_fault4]]-[[test3_begin]]556;                   ^ offset from L_begin to start of 1st funclet557; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]558;                   ^ offset from L_begin to start of 2nd funclet559; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]560;                   ^ offset from L_begin to start of 3rd funclet561; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]562;                   ^ offset from L_begin to start of 4th funclet563; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]564;                   ^ offset from L_begin to start of 5th funclet565; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]566;                   ^ offset from L_begin to start of 6th funclet567; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]568;                   ^ offset from L_begin to start of 7th funclet569; CHECK-NEXT: .long [[test3_end]]-[[test3_begin]]570;                   ^ offset from L_begin to end of last funclet571; CHECK-NEXT: .long 10572;                   ^ number of EH clauses573; Clause 1: call f(1) is guarded by fault1574; CHECK-NEXT: .long 4575;                   ^ flags (4 => fault handler)576; CHECK-NEXT: .long [[test3_before_f1]]-[[test3_begin]]+1577;                   ^ offset of start of clause578; CHECK-NEXT: .long [[test3_after_f1]]-[[test3_begin]]+1579;                   ^ offset of end of clause580; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]581;                   ^ offset of start of handler582; CHECK-NEXT: .long [[test3_end]]-[[test3_begin]]583;                   ^ offset of end of handler584; CHECK-NEXT: .long 0585;                   ^ type token slot (null for fault)586; Clause 3: call f(6) is guarded by catch1587; CHECK-NEXT: .long 0588;                   ^ flags (0 => catch handler)589; CHECK-NEXT: .long [[test3_before_f6]]-[[test3_begin]]+1590;                   ^ offset of start of clause591; CHECK-NEXT: .long [[test3_after_f6]]-[[test3_begin]]+1592;                   ^ offset of end of clause593; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]594;                   ^ offset of start of handler595; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]596;                   ^ offset of end of handler597; CHECK-NEXT: .long 1598;                   ^ type token of catch (from catchpad)599; Clause 3: call f(6) is also guarded by catch2600; CHECK-NEXT: .long 0601;                   ^ flags (0 => catch handler)602; CHECK-NEXT: .long [[test3_before_f6]]-[[test3_begin]]+1603;                   ^ offset of start of clause604; CHECK-NEXT: .long [[test3_after_f6]]-[[test3_begin]]+1605;                   ^ offset of end of clause606; CHECK-NEXT: .long [[test3_catch2]]-[[test3_begin]]607;                   ^ offset of start of handler608; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]609;                   ^ offset of end of handler610; CHECK-NEXT: .long 2611;                   ^ type token of catch (from catchpad)612; Clause 4: call f(7) is guarded by fault5613;           This is a "duplicate" because the protected range (f(6)-f(7))614;           is in funclet fault4 but fault5's immediate parent615;           is fault1, not that funclet.616; CHECK-NEXT: .long 12617;                   ^ flags (4 => fault handler | 8 => duplicate)618; CHECK-NEXT: .long [[test3_before_f7]]-[[test3_begin]]+1619;                   ^ offset of start of clause620; CHECK-NEXT: .long [[test3_after_f7]]-[[test3_begin]]+1621;                   ^ offset of end of clause622; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]623;                   ^ offset of start of handler624; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]625;                   ^ offset of end of handler626; CHECK-NEXT: .long 0627;                   ^ type token slot (null for fault)628; Clause 5: call f(4) is guarded by fault4629; CHECK-NEXT: .long 4630;                   ^ flags (4 => fault handler)631; CHECK-NEXT: .long [[test3_before_f4]]-[[test3_begin]]+1632;                   ^ offset of start of clause633; CHECK-NEXT: .long [[test3_after_f4]]-[[test3_begin]]+1634;                   ^ offset of end of clause635; CHECK-NEXT: .long [[test3_fault4]]-[[test3_begin]]636;                   ^ offset of start of handler637; CHECK-NEXT: .long [[test3_catch1]]-[[test3_begin]]638;                   ^ offset of end of handler639; CHECK-NEXT: .long 0640;                   ^ type token slot (null for fault)641; Clause 6: call f(4) is also guarded by fault5642;           This is a "duplicate" because the protected range (f(4))643;           is in funclet fault3 but fault5's immediate parent644;           is fault1, not that funclet.645; CHECK-NEXT: .long 12646;                   ^ flags (4 => fault handler)647; CHECK-NEXT: .long [[test3_before_f4]]-[[test3_begin]]+1648;                   ^ offset of start of clause649; CHECK-NEXT: .long [[test3_after_f4]]-[[test3_begin]]+1650;                   ^ offset of end of clause651; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]652;                   ^ offset of start of handler653; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]654;                   ^ offset of end of handler655; CHECK-NEXT: .long 0656;                   ^ type token slot (null for fault)657; Clause 7: call f(3) is guarded by fault3658; CHECK-NEXT: .long 4659;                   ^ flags (4 => fault handler)660; CHECK-NEXT: .long [[test3_before_f3]]-[[test3_begin]]+1661;                   ^ offset of start of clause662; CHECK-NEXT: .long [[test3_after_f3]]-[[test3_begin]]+1663;                   ^ offset of end of clause664; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]665;                   ^ offset of start of handler666; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]667;                   ^ offset of end of handler668; CHECK-NEXT: .long 0669;                   ^ type token slot (null for fault)670; Clause 8: call f(3) is guarded by fault5671;           This is a "duplicate" because the protected range (f(3))672;           is in funclet fault2 but fault5's immediate parent673;           is fault1, not that funclet.674; CHECK-NEXT: .long 12675;                   ^ flags (4 => fault handler | 8 => duplicate)676; CHECK-NEXT: .long [[test3_before_f3]]-[[test3_begin]]+1677;                   ^ offset of start of clause678; CHECK-NEXT: .long [[test3_after_f3]]-[[test3_begin]]+1679;                   ^ offset of end of clause680; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]681;                   ^ offset of start of handler682; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]683;                   ^ offset of end of handler684; CHECK-NEXT: .long 0685;                   ^ type token slot (null for fault)686; Clause 9: call f(2) is guarded by fault2687; CHECK-NEXT: .long 4688;                   ^ flags (4 => fault handler)689; CHECK-NEXT: .long [[test3_before_f2]]-[[test3_begin]]+1690;                   ^ offset of start of clause691; CHECK-NEXT: .long [[test3_after_f2]]-[[test3_begin]]+1692;                   ^ offset of end of clause693; CHECK-NEXT: .long [[test3_fault2]]-[[test3_begin]]694;                   ^ offset of start of handler695; CHECK-NEXT: .long [[test3_fault1]]-[[test3_begin]]696;                   ^ offset of end of handler697; CHECK-NEXT: .long 0698;                   ^ type token slot (null for fault)699; Clause 10: call f(2) is guarded by fault5700; CHECK-NEXT: .long 4701;                   ^ flags (4 => fault handler)702; CHECK-NEXT: .long [[test3_before_f2]]-[[test3_begin]]+1703;                   ^ offset of start of clause704; CHECK-NEXT: .long [[test3_after_f2]]-[[test3_begin]]+1705;                   ^ offset of end of clause706; CHECK-NEXT: .long [[test3_fault5]]-[[test3_begin]]707;                   ^ offset of start of handler708; CHECK-NEXT: .long [[test3_fault3]]-[[test3_begin]]709;                   ^ offset of end of handler710; CHECK-NEXT: .long 0711;                   ^ type token slot (null for fault)712