brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.7 KiB · 4977758 Raw
518 lines · cpp
1// RUN: %clang_cc1 -no-enable-noundef-analysis -emit-llvm -fno-rtti %s -std=c++11 -o - -mconstructor-aliases -triple=i386-pc-win32 -fno-rtti > %t2// RUN: FileCheck --check-prefixes CHECK,CLANG22 %s < %t3// vftables are emitted very late, so do another pass to try to keep the checks4// in source order.5// RUN: FileCheck --check-prefix DTORS %s < %t6// RUN: FileCheck --check-prefix DTORS2 %s < %t7// RUN: FileCheck --check-prefix DTORS3 %s < %t8// RUN: FileCheck --check-prefix DTORS4 %s < %t9//10// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti -std=c++11 | FileCheck --check-prefix DTORS-X64 %s11// RUN: %clang_cc1 -no-enable-noundef-analysis -emit-llvm -fno-rtti %s -std=c++11 -o - -mconstructor-aliases -triple=i386-pc-win32 -fclang-abi-compat=20 | FileCheck --check-prefixes CHECK,CLANG21 %s12 13namespace basic {14 15class A {16 public:17  A() { }18  ~A();19};20 21void no_constructor_destructor_infinite_recursion() {22  A a;23 24// CHECK:      define linkonce_odr dso_local x86_thiscallcc ptr @"??0A@basic@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this) {{.*}} comdat {{.*}} {25// CHECK:        [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca ptr, align 426// CHECK-NEXT:   store ptr %this, ptr [[THIS_ADDR]], align 427// CHECK-NEXT:   [[T1:%[.0-9A-Z_a-z]+]] = load ptr, ptr [[THIS_ADDR]]28// CHECK-NEXT:   ret ptr [[T1]]29// CHECK-NEXT: }30}31 32A::~A() {33// Make sure that the destructor doesn't call itself:34// CHECK: define {{.*}} @"??1A@basic@@QAE@XZ"35// CHECK-NOT: call void @"??1A@basic@@QAE@XZ"36// CHECK: ret37}38 39struct B {40  B();41};42 43// Tests that we can define constructors outside the class (PR12784).44B::B() {45  // CHECK: define dso_local x86_thiscallcc ptr @"??0B@basic@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this)46  // CHECK: ret47}48 49struct C {50  virtual ~C() {51// DTORS:      define linkonce_odr dso_local x86_thiscallcc ptr @"??_GC@basic@@UAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {52// DTORS:        store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 453// DTORS:        store ptr %{{.*}}, ptr %[[RETVAL:retval]]54// DTORS:        %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]55// DTORS:        call x86_thiscallcc void @"??1C@basic@@UAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])56// DTORS-NEXT:   %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 157// DTORS-NEXT:   %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 058// DTORS-NEXT:   br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]59//60// DTORS:      [[CALL_DELETE_LABEL]]61// DTORS-NEXT:   call void @"??3@YAXPAX@Z"(ptr %[[THIS]])62// DTORS-NEXT:   br label %[[CONTINUE_LABEL]]63//64// DTORS:      [[CONTINUE_LABEL]]65// DTORS-NEXT:   %[[RET:.*]] = load ptr, ptr %[[RETVAL]]66// DTORS-NEXT:   ret ptr %[[RET]]67 68// Check that we do the mangling correctly on x64.69// DTORS-X64:  @"??_GC@basic@@UEAAPEAXI@Z"70  }71  virtual void foo();72};73 74// Emits the vftable in the output.75void C::foo() {}76 77void check_vftable_offset() {78  C c;79// The vftable pointer should point at the beginning of the vftable.80// CHECK: store ptr @"??_7C@basic@@6B@", ptr {{.*}}81}82 83void call_complete_dtor(C *obj_ptr) {84// CHECK: define dso_local void @"?call_complete_dtor@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)85  obj_ptr->~C();86// CHECK: %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 487// CHECK-NEXT: %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]88// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 089// CHECK-NEXT: %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]90// CHECK-NEXT: call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 0)91// CHECK-NEXT: ret void92}93 94void call_deleting_dtor(C *obj_ptr) {95// CHECK: define dso_local void @"?call_deleting_dtor@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)96  delete obj_ptr;97// CHECK:      %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 498// CHECK:      br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]99 100// CHECK:      [[DELETE_NOTNULL]]101// CHECK-NEXT:   %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]102// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0103// CHECK-NEXT:   %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]104// CHECK-NEXT:   call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 1)105// CHECK:      ret void106}107 108void call_deleting_dtor_and_global_delete(C *obj_ptr) {109// CHECK: define dso_local void @"?call_deleting_dtor_and_global_delete@basic@@YAXPAUC@1@@Z"(ptr %obj_ptr)110  ::delete obj_ptr;111// CHECK:      %[[OBJ_PTR_VALUE:.*]] = load ptr, ptr %{{.*}}, align 4112// CHECK:      br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]113 114// CHECK:      [[DELETE_NOTNULL]]115// CHECK-NEXT:   %[[VTABLE:.*]] = load ptr, ptr %[[OBJ_PTR_VALUE]]116// CHECK-NEXT:   %[[PVDTOR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i64 0117// CHECK-NEXT:   %[[VDTOR:.*]] = load ptr, ptr %[[PVDTOR]]118// CLANG22-NEXT:   %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 5)119// CLANG21-NEXT:   %[[CALL:.*]] = call x86_thiscallcc ptr %[[VDTOR]](ptr {{[^,]*}} %[[OBJ_PTR_VALUE]], i32 0)120// CLANG21-NEXT: call void @"??3@YAXPAX@Z"(ptr %[[CALL]])121// CHECK:      ret void122}123 124struct D {125  static int foo();126 127  D() {128    static int ctor_static = foo();129    // CHECK that the static in the ctor gets mangled correctly:130    // CHECK: @"?ctor_static@?1???0D@basic@@QAE@XZ@4HA"131  }132  ~D() {133    static int dtor_static = foo();134    // CHECK that the static in the dtor gets mangled correctly:135    // CHECK: @"?dtor_static@?1???1D@basic@@QAE@XZ@4HA"136  }137};138 139void use_D() { D c; }140 141} // end namespace basic142 143namespace dtor_in_second_nvbase {144 145struct A {146  virtual void f();  // A needs vftable to be primary.147};148struct B {149  virtual ~B();150};151struct C : A, B {152  virtual ~C();153};154 155C::~C() {156// CHECK-LABEL: define dso_local x86_thiscallcc void @"??1C@dtor_in_second_nvbase@@UAE@XZ"(ptr{{[^,]*}} %this)157//      No this adjustment!158// CHECK-NOT: getelementptr159// CHECK:   load ptr, ptr %{{.*}}160//      Now we this-adjust before calling ~B.161// CHECK:   getelementptr inbounds i8, ptr %{{.*}}, i32 4162// CHECK:   call x86_thiscallcc void @"??1B@dtor_in_second_nvbase@@UAE@XZ"(ptr{{[^,]*}} %{{.*}})163// CHECK:   ret void164}165 166void foo() {167  C c;168}169// DTORS2-LABEL: define linkonce_odr dso_local x86_thiscallcc ptr @"??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"(ptr %this, i32 %should_call_delete)170//      Do an adjustment from B* to C*.171// DTORS2:   getelementptr i8, ptr %{{.*}}, i32 -4172// DTORS2:   %[[CALL:.*]] = tail call x86_thiscallcc ptr @"??_GC@dtor_in_second_nvbase@@UAEPAXI@Z"173// DTORS2:   ret ptr %[[CALL]]174}175 176namespace test2 {177// Just like dtor_in_second_nvbase, except put that in a vbase of a diamond.178 179// C's dtor is in the non-primary base.180struct A { virtual void f(); };181struct B { virtual ~B(); };182struct C : A, B { virtual ~C(); int c; };183 184// Diamond hierarchy, with C as the shared vbase.185struct D : virtual C { int d; };186struct E : virtual C { int e; };187struct F : D, E { ~F(); int f; };188 189F::~F() {190// CHECK-LABEL: define dso_local x86_thiscallcc void @"??1F@test2@@UAE@XZ"(ptr{{[^,]*}})191//      Do an adjustment from C vbase subobject to F as though F was the192//      complete type.193// CHECK:   getelementptr inbounds i8, ptr %{{.*}}, i32 -20194// CHECK:   store ptr195}196 197void foo() {198  F f;199}200// DTORS3-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"??_DF@test2@@QAEXXZ"({{.*}} {{.*}} comdat201//      Do an adjustment from C* to F*.202// DTORS3:   getelementptr i8, ptr %{{.*}}, i32 20203// DTORS3:   call x86_thiscallcc void @"??1F@test2@@UAE@XZ"204// DTORS3:   ret void205 206}207 208namespace constructors {209 210struct A {211  A() {}212};213 214struct B : A {215  B();216  ~B();217};218 219B::B() {220  // CHECK: define dso_local x86_thiscallcc ptr @"??0B@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this)221  // CHECK: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})222  // CHECK: ret223}224 225struct C : virtual A {226  C();227};228 229C::C() {230  // CHECK: define dso_local x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived)231  // TODO: make sure this works in the Release build too;232  // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4233  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]234  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0235  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]236  //237  // CHECK: [[INIT_VBASES]]238  // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0239  // CHECK-NEXT: store ptr @"??_8C@constructors@@7B@", ptr %[[vbptr_off]]240  // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4241  // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})242  // CHECK-NEXT: br label %[[SKIP_VBASES]]243  //244  // CHECK: [[SKIP_VBASES]]245  // Class C does not define or override methods, so shouldn't change the vfptr.246  // CHECK-NOT: @"??_7C@constructors@@6B@"247  // CHECK: ret248}249 250void create_C() {251  C c;252  // CHECK: define dso_local void @"?create_C@constructors@@YAXXZ"()253  // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %c, i32 1)254  // CHECK: ret255}256 257struct D : C {258  D();259};260 261D::D() {262  // CHECK: define dso_local x86_thiscallcc ptr @"??0D@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived) unnamed_addr263  // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4264  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]265  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0266  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]267  //268  // CHECK: [[INIT_VBASES]]269  // CHECK-NEXT: %[[vbptr_off:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0270  // CHECK-NEXT: store ptr @"??_8D@constructors@@7B@", ptr %[[vbptr_off]]271  // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4272  // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})273  // CHECK-NEXT: br label %[[SKIP_VBASES]]274  //275  // CHECK: [[SKIP_VBASES]]276  // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}, i32 0)277  // CHECK: ret278}279 280struct E : virtual C {281  E();282};283 284E::E() {285  // CHECK: define dso_local x86_thiscallcc ptr @"??0E@constructors@@QAE@XZ"(ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived) unnamed_addr286  // CHECK: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4287  // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]288  // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0289  // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]290  //291  // CHECK: [[INIT_VBASES]]292  // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0293  // CHECK-NEXT: store ptr @"??_8E@constructors@@7B01@@", ptr %[[offs]]294  // CHECK-NEXT: %[[offs:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 4295  // CHECK-NEXT: store ptr @"??_8E@constructors@@7BC@1@@", ptr %[[offs]]296  // CHECK-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i32 4297  // CHECK-NEXT: call x86_thiscallcc ptr @"??0A@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})298  // CHECK: call x86_thiscallcc ptr @"??0C@constructors@@QAE@XZ"(ptr {{[^,]*}} %{{.*}}, i32 0)299  // CHECK-NEXT: br label %[[SKIP_VBASES]]300  //301  // CHECK: [[SKIP_VBASES]]302  // CHECK: ret303}304 305// PR16735 - even abstract classes should have a constructor emitted.306struct F {307  F();308  virtual void f() = 0;309};310 311F::F() {}312// CHECK: define dso_local x86_thiscallcc ptr @"??0F@constructors@@QAE@XZ"313 314} // end namespace constructors315 316namespace dtors {317 318struct A {319  ~A();320};321 322void call_nv_complete(A *a) {323  a->~A();324// CHECK: define dso_local void @"?call_nv_complete@dtors@@YAXPAUA@1@@Z"325// CHECK: call x86_thiscallcc void @"??1A@dtors@@QAE@XZ"326// CHECK: ret327}328 329// CHECK: declare dso_local x86_thiscallcc void @"??1A@dtors@@QAE@XZ"330 331// Now try some virtual bases, where we need the complete dtor.332 333struct B : virtual A { ~B(); };334struct C : virtual A { ~C(); };335struct D : B, C { ~D(); };336 337void call_vbase_complete(D *d) {338  d->~D();339// CHECK: define dso_local void @"?call_vbase_complete@dtors@@YAXPAUD@1@@Z"340// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})341// CHECK: ret342}343 344// The complete dtor should call the base dtors for D and the vbase A (once).345// CHECK: define linkonce_odr dso_local x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"({{.*}}) {{.*}} comdat346// CHECK-NOT: call347// CHECK: call x86_thiscallcc void @"??1D@dtors@@QAE@XZ"348// CHECK-NOT: call349// CHECK: call x86_thiscallcc void @"??1A@dtors@@QAE@XZ"350// CHECK-NOT: call351// CHECK: ret352 353void destroy_d_complete() {354  D d;355// CHECK: define dso_local void @"?destroy_d_complete@dtors@@YAXXZ"356// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})357// CHECK: ret358}359 360// FIXME: Clang manually inlines the deletion, so we don't get a call to the361// deleting dtor (_G).  The only way to call deleting dtors currently is through362// a vftable.363void call_nv_deleting_dtor(D *d) {364  delete d;365// CHECK: define dso_local void @"?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z"366// CHECK: call x86_thiscallcc void @"??_DD@dtors@@QAEXXZ"(ptr {{[^,]*}} %{{[^,]+}})367// CHECK: call void @"??3@YAXPAX@Z"368// CHECK: ret369}370 371}372 373namespace test1 {374struct A { };375struct B : virtual A {376  B(int *a);377  B(const char *a, ...);378  __cdecl B(short *a);379};380B::B(int *a) {}381B::B(const char *a, ...) {}382B::B(short *a) {}383// CHECK: define dso_local x86_thiscallcc ptr @"??0B@test1@@QAE@PAH@Z"384// CHECK:               (ptr {{[^,]*}} returned {{[^,]*}} %this, ptr %a, i32 %is_most_derived)385// CHECK: define dso_local ptr @"??0B@test1@@QAA@PBDZZ"386// CHECK:               (ptr {{[^,]*}} returned {{[^,]*}} %this, i32 %is_most_derived, ptr %a, ...)387// CHECK: define dso_local x86_thiscallcc ptr @"??0B@test1@@QAE@PAF@Z"388// CHECK:               (ptr {{[^,]*}} returned {{[^,]*}} %this, ptr %a, i32 %is_most_derived)389 390void construct_b() {391  int a;392  B b1(&a);393  B b2("%d %d", 1, 2);394}395// CHECK-LABEL: define dso_local void @"?construct_b@test1@@YAXXZ"()396// CHECK: call x86_thiscallcc ptr @"??0B@test1@@QAE@PAH@Z"397// CHECK:               (ptr {{.*}}, ptr {{.*}}, i32 1)398// CHECK: call ptr (ptr, i32, ptr, ...) @"??0B@test1@@QAA@PBDZZ"399// CHECK:               (ptr {{.*}}, i32 1, ptr {{.*}}, i32 1, i32 2)400}401 402namespace implicit_copy_vtable {403// This was a crash that only reproduced in ABIs without key functions.404struct ImplicitCopy {405  // implicit copy ctor406  virtual ~ImplicitCopy();407};408void CreateCopy(ImplicitCopy *a) {409  new ImplicitCopy(*a);410}411// CHECK: store {{.*}} @"??_7ImplicitCopy@implicit_copy_vtable@@6B@"412 413struct MoveOnly {414  MoveOnly(MoveOnly &&o) = default;415  virtual ~MoveOnly();416};417MoveOnly &&f();418void g() { new MoveOnly(f()); }419// CHECK: store {{.*}} @"??_7MoveOnly@implicit_copy_vtable@@6B@"420}421 422namespace delegating_ctor {423struct Y {};424struct X : virtual Y {425  X(int);426  X();427};428X::X(int) : X() {}429}430// CHECK: define dso_local x86_thiscallcc ptr @"??0X@delegating_ctor@@QAE@H@Z"(431// CHECK:  %[[is_most_derived_addr:.*]] = alloca i32, align 4432// CHECK:  store i32 %is_most_derived, ptr %[[is_most_derived_addr]]433// CHECK:  %[[is_most_derived:.*]] = load i32, ptr %[[is_most_derived_addr]]434// CHECK:  call x86_thiscallcc ptr @"??0X@delegating_ctor@@QAE@XZ"({{.*}} i32 %[[is_most_derived]])435 436// Dtor thunks for classes in anonymous namespaces should be internal, not437// linkonce_odr.438namespace {439struct A {440  virtual ~A() { }441};442}443void *getA() {444  return (void*)new A();445}446// CHECK: define internal x86_thiscallcc ptr @"??_GA@?A0x{{[^@]*}}@@UAEPAXI@Z"447// CHECK:               (ptr {{[^,]*}} %this, i32 %should_call_delete)448// CHECK: define internal x86_thiscallcc void @"??1A@?A0x{{[^@]*}}@@UAE@XZ"449// CHECK:               (ptr {{[^,]*}} %this)450 451// Check that we correctly transform __stdcall to __thiscall for ctors and452// dtors.453class G {454 public:455  __stdcall G() {};456// DTORS4: define linkonce_odr dso_local x86_thiscallcc ptr @"??0G@@QAE@XZ"457  __stdcall ~G() {};458// DTORS4: define linkonce_odr dso_local x86_thiscallcc void @"??1G@@QAE@XZ"459};460 461extern void testG() {462  G g;463}464 465namespace operator_delete {466 467class H { virtual ~H();468  void operator delete(void *);469};470H::~H() { }471 472void checkH() {473  new H();474}475// DTORS:      define linkonce_odr dso_local x86_thiscallcc ptr @"??_GH@operator_delete@@EAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {476// DTORS:        store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4477// DTORS:        store ptr %{{.*}}, ptr %[[RETVAL:retval]]478// DTORS:        %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]479// DTORS:        call x86_thiscallcc void @"??1H@operator_delete@@EAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])480// DTORS-NEXT:   %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1481// DTORS-NEXT:   %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0482// DTORS-NEXT:   br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]483//484// DTORS:      [[CALL_DELETE_LABEL]]485// DTORS-NEXT:   %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 4486// DTORS-NEXT:   %[[CONDITION1:[0-9]+]] = icmp eq i32 %[[AND]], 0487// DTORS-NEXT:   br i1 %[[CONDITION1]], label %[[CALL_CLASS_DELETE:[0-9a-z._]+]], label %[[CALL_GLOB_DELETE:[0-9a-z._]+]]488//489// DTORS:      [[CALL_GLOB_DELETE]]490// DTORS-NEXT:   call void @"??3@YAXPAX@Z"(ptr %[[THIS]])491// DTORS-NEXT:   br label %[[CONTINUE_LABEL]]492//493// DTORS:      [[CALL_CLASS_DELETE]]494// DTORS-NEXT:   call void @"??3H@operator_delete@@CAXPAX@Z"(ptr %[[THIS]])495// DTORS-NEXT:   br label %[[CONTINUE_LABEL]]496//497// DTORS:      [[CONTINUE_LABEL]]498// DTORS-NEXT:   %[[RET:.*]] = load ptr, ptr %[[RETVAL]]499// DTORS-NEXT:   ret ptr %[[RET]]500 501// CLANG21:      define linkonce_odr dso_local x86_thiscallcc ptr @"??_GH@operator_delete@@EAEPAXI@Z"(ptr {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat {{.*}} {502// CLANG21:        store i32 %should_call_delete, ptr %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 4503// CLANG21:        store ptr %{{.*}}, ptr %[[RETVAL:retval]]504// CLANG21:        %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i32, ptr %[[SHOULD_DELETE_VAR]]505// CLANG21:        call x86_thiscallcc void @"??1H@operator_delete@@EAE@XZ"(ptr {{[^,]*}} %[[THIS:[0-9a-z]+]])506// CLANG21-NEXT:   %[[AND:[0-9]+]] = and i32 %[[SHOULD_DELETE_VALUE]], 1507// CLANG21-NEXT:   %[[CONDITION:[0-9]+]] = icmp eq i32 %[[AND]], 0508// CLANG21-NEXT:   br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]509//510// CLANG21:      [[CALL_DELETE_LABEL]]511// CLANG21-NEXT:   call void @"??3H@operator_delete@@CAXPAX@Z"(ptr %[[THIS:[0-9a-z]+]])512// CLANG21-NEXT:   br label %[[CONTINUE_LABEL]]513//514// CLANG21:      [[CONTINUE_LABEL]]515// CLANG21-NEXT:   %[[RET:.*]] = load ptr, ptr %[[RETVAL]]516// CLANG21-NEXT:   ret ptr %[[RET]]517}518