brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.6 KiB · b831737 Raw
210 lines · cpp
1// REQUIRES: x86-registered-target2 3// RUN: %clang_cl -c --target=x86_64-windows-msvc /EHa -O2 /GS- \4// RUN:   -Xclang=-import-call-optimization \5// RUN:   /clang:-S /clang:-o- -- %s 2>&1 \6// RUN:   | FileCheck %s7 8#ifdef __clang__9#define NO_TAIL __attribute((disable_tail_calls))10#else11#define NO_TAIL12#endif13 14void might_throw();15void other_func(int x);16 17void does_not_throw() noexcept(true);18 19extern "C" void __declspec(dllimport) some_dll_import();20 21class HasDtor {22    int x;23    char foo[40];24 25public:26    explicit HasDtor(int x);27    ~HasDtor();28};29 30class BadError {31public:32    int errorCode;33};34 35void normal_has_regions() {36    // CHECK-LABEL: .def "?normal_has_regions@@YAXXZ"37    // CHECK: .seh_endprologue38 39    // <-- state -1 (none)40    {41        HasDtor hd{42};42 43        // <-- state goes from -1 to 044        // because state changes, we expect the HasDtor::HasDtor() call to have a NOP45        // CHECK: call "??0HasDtor@@QEAA@H@Z"46        // CHECK-NEXT: nop47 48        might_throw();49        // CHECK: call "?might_throw@@YAXXZ"50        // CHECK-NEXT: nop51 52        // <-- state goes from 0 to -1 because we're about to call HasDtor::~HasDtor()53        // CHECK: call "??1HasDtor@@QEAA@XZ"54        // <-- state -155    }56 57    // <-- state -158    other_func(10);59    // CHECK: call "?other_func@@YAXH@Z"60    // CHECK-NEXT: nop61    // CHECK: .seh_startepilogue62 63    // <-- state -164}65 66// This tests a tail call to a destructor.67void case_dtor_arg_empty_body(HasDtor x)68{69    // CHECK-LABEL: .def "?case_dtor_arg_empty_body@@YAXVHasDtor@@@Z"70    // CHECK: jmp "??1HasDtor@@QEAA@XZ"71}72 73int case_dtor_arg_empty_with_ret(HasDtor x)74{75    // CHECK-LABEL: .def "?case_dtor_arg_empty_with_ret@@YAHVHasDtor@@@Z"76    // CHECK: .seh_endprologue77 78    // CHECK: call "??1HasDtor@@QEAA@XZ"79    // CHECK-NOT: nop80 81    // The call to HasDtor::~HasDtor() should NOT have a NOP because the82    // following "mov eax, 100" instruction is in the same EH state.83 84    return 100;85 86    // CHECK: mov eax, 10087    // CHECK: .seh_startepilogue88    // CHECK: .seh_endepilogue89    // CHECK: .seh_endproc90}91 92int case_noexcept_dtor(HasDtor x) noexcept(true)93{94    // CHECK: .def "?case_noexcept_dtor@@YAHVHasDtor@@@Z"95    // CHECK: call "??1HasDtor@@QEAA@XZ"96    // CHECK-NEXT: mov eax, 10097    // CHECK: .seh_startepilogue98    return 100;99}100 101void case_except_simple_call() NO_TAIL102{103    does_not_throw();104}105// CHECK-LABEL: .def "?case_except_simple_call@@YAXXZ"106// CHECK: .seh_endprologue107// CHECK-NEXT: call "?does_not_throw@@YAXXZ"108// CHECK-NEXT: nop109// CHECK-NEXT: .seh_startepilogue110// CHECK: .seh_endproc111 112void case_noexcept_simple_call() noexcept(true) NO_TAIL113{114    does_not_throw();115}116// CHECK-LABEL: .def "?case_noexcept_simple_call@@YAXXZ"117// CHECK: .seh_endprologue118// CHECK-NEXT: call "?does_not_throw@@YAXXZ"119// CHECK-NEXT: nop120// CHECK-NEXT: .seh_startepilogue121// CHECK: .seh_endepilogue122// CHECK-NEXT: ret123// CHECK-NEXT: .seh_endproc124 125// This tests that the destructor is called right before SEH_BeginEpilogue,126// but in a function that has a return value. Loading the return value127// counts as a real instruction, so there is no need for a NOP after the128// dtor call.129int case_dtor_arg_calls_no_throw(HasDtor x)130{131    does_not_throw(); // no NOP expected132    return 100;133}134// CHECK-LABEL: .def "?case_dtor_arg_calls_no_throw@@YAHVHasDtor@@@Z"135// CHECK: .seh_endprologue136// CHECK: "?does_not_throw@@YAXXZ"137// CHECK-NEXT: nop138// CHECK: "??1HasDtor@@QEAA@XZ"139// CHECK-NEXT: mov eax, 100140// CHECK: .seh_startepilogue141// CHECK: .seh_endproc142 143// Check the behavior of CALLs that are at the end of MBBs. If a CALL is within144// a non-null EH state (state -1) and is at the end of an MBB, then we expect145// to find an EH_LABEL after the CALL. This causes us to insert a NOP, which146// is the desired result.147void case_dtor_runs_after_join(int x) {148    // CHECK-LABEL: .def "?case_dtor_runs_after_join@@YAXH@Z"149    // CHECK: .seh_endprologue150 151    // <-- EH state -1152 153    // ctor call does not need a NOP, because it has real instructions after it154    HasDtor hd{42};155    // CHECK: call "??0HasDtor@@QEAA@H@Z"156    // CHECK-NEXT: nop157    // CHECK: test158 159    // <-- EH state transition from -1 0160    if (x) {161        might_throw(); // <-- NOP expected (at end of BB w/ EH_LABEL)162        // CHECK: call "?might_throw@@YAXXZ"163        // CHECK-NEXT: nop164    } else {165        other_func(10); // <-- NOP expected (at end of BB w/ EH_LABEL)166        // CHECK: call "?other_func@@YAXH@Z"167        // CHECK-NEXT: nop168    }169    does_not_throw();170    // <-- EH state transition 0 to -1171    // ~HasDtor() runs172 173    // CHECK: .seh_endproc174 175    // CHECK: "$ip2state$?case_dtor_runs_after_join@@YAXH@Z":176    // CHECK-NEXT: .long [[func_begin:.Lfunc_begin([0-9]+)@IMGREL]]177    // CHECK-NEXT: .long -1178    // CHECK-NEXT: .long [[tmp1:.Ltmp([0-9]+)]]@IMGREL179    // CHECK-NEXT: .long 0180    // CHECK-NEXT: .long [[tmp2:.Ltmp([0-9]+)]]@IMGREL181    // CHECK-NEXT: .long -1182}183 184 185// Check the behavior of NOP padding around tail calls.186// We do not expect to insert NOPs around tail calls.187// However, the first call (to other_func()) does get a NOP188// because it comes before .seh_startepilogue.189void case_tail_call_no_eh(bool b) {190    // tail call; no NOP padding after JMP191    if (b) {192        does_not_throw();193        // <-- no NOP here194        return;195    }196 197    other_func(20);198    // <-- NOP does get inserted here199}200// CHECK-LABEL: .def "?case_tail_call_no_eh@@YAX_N@Z"201// CHECK: test202// CHECK-NEXT: je .LBB203// CHECK: jmp "?does_not_throw@@YAXXZ"204// CHECK-SAME: TAILCALL205// CHECK-NEXT: .LBB206// CHECK-NEXT: mov ecx, 20207// CHECK-NEXT: jmp "?other_func@@YAXH@Z"208// CHECK-SAME: TAILCALL209// CHECK-NEXT: # -- End function210