182 changes: 80 additions & 102 deletions clang/test/CodeGenCXX/strict-vtable-pointers.cpp

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions clang/test/CodeGenCXX/tail-padding.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s

// PR36992
namespace Implicit {
Expand All @@ -11,8 +11,8 @@ namespace Implicit {
// CHECK: define {{.*}} @_ZN8Implicit1CC1EOS0_
// CHECK: call {{.*}} @_ZN8Implicit1AC2ERKS0_(
// Note: this must memcpy 7 bytes, not 8, to avoid trampling over the virtual base class.
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 7, i1 false)
// CHECK: store i32 {{.*}} @_ZTVN8Implicit1CE
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 7, i1 false)
// CHECK: store ptr {{.*}} @_ZTVN8Implicit1CE
}

namespace InitWithinNVSize {
Expand All @@ -28,8 +28,8 @@ namespace InitWithinNVSize {
// CHECK: define {{.*}} @_ZN16InitWithinNVSize1CC1EOS0_
// CHECK: call {{.*}} @_ZN16InitWithinNVSize1AC2ERKS0_(
// This copies over the 'C::x' member, but that's OK because we've not initialized it yet.
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 8, i1 false)
// CHECK: store i32 {{.*}} @_ZTVN16InitWithinNVSize1CE
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 8, i1 false)
// CHECK: store ptr {{.*}} @_ZTVN16InitWithinNVSize1CE
// CHECK: store i8
}

Expand All @@ -45,24 +45,24 @@ namespace NoUniqueAddr {

// CHECK: define {{.*}} @_ZN12NoUniqueAddr1CC1EOS0_
// CHECK: call {{.*}} @_ZN12NoUniqueAddr1AC2ERKS0_(
// CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1CE
// CHECK: store ptr {{.*}} @_ZTVN12NoUniqueAddr1CE
// Copy the full size of B.
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 8, i1 false)
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 8, i1 false)
C f(C c) { return c; }

// CHECK: define {{.*}} @_ZN12NoUniqueAddr1DC1EOS0_
// CHECK: call {{.*}} @_ZN12NoUniqueAddr1AC2ERKS0_(
// CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1DE
// CHECK: store ptr {{.*}} @_ZTVN12NoUniqueAddr1DE
// Copy just the data size of B, to avoid overwriting the A base class.
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 7, i1 false)
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 7, i1 false)
D f(D d) { return d; }

// CHECK: define {{.*}} @_ZN12NoUniqueAddr1EC1EOS0_
// CHECK: call {{.*}} @_ZN12NoUniqueAddr1AC2ERKS0_(
// CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1EE
// CHECK: store ptr {{.*}} @_ZTVN12NoUniqueAddr1EE
// We can copy the full size of B here. (As it happens, we fold the copy of 'x' into
// this memcpy, so we're copying 8 bytes either way.)
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 8, i1 false)
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 8, i1 false)
E f(E e) { return e; }

struct F : virtual A {
Expand All @@ -72,7 +72,7 @@ namespace NoUniqueAddr {

// CHECK: define {{.*}} @_ZN12NoUniqueAddr1FC1ERKS0_
// CHECK: call {{.*}} @_ZN12NoUniqueAddr1AC2ERKS0_(
// CHECK: store i32 {{.*}} @_ZTVN12NoUniqueAddr1FE
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i{{32|64}}(i8* {{.*}}, i8* {{.*}}, i{{32|64}} 7, i1 false)
// CHECK: store ptr {{.*}} @_ZTVN12NoUniqueAddr1FE
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}}, ptr {{.*}}, i{{32|64}} 7, i1 false)
F f(F x) { return x; }
}
8 changes: 4 additions & 4 deletions clang/test/CodeGenCXX/template-param-objects.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK
// RUN: %clang_cc1 -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK

struct S { char buf[32]; };
template<S s> constexpr const char *begin() { return s.buf; }
Expand All @@ -11,9 +11,9 @@ template<S s> constexpr const char *end() { return s.buf + __builtin_strlen(s.bu

// ITANIUM: @p
// MSABI: @"?p@@3PEBDEB"
// CHECK-SAME: global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0)
// CHECK-SAME: global ptr [[HELLO]]
const char *p = begin<S{"hello world"}>();
// ITANIUM: @q
// MSABI: @"?q@@3PEBDEB"
// CHECK-SAME: global i8* getelementptr ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i64 11)
// CHECK-SAME: global ptr getelementptr (i8, ptr [[HELLO]], i64 11)
const char *q = end<S{"hello world"}>();
240 changes: 120 additions & 120 deletions clang/test/CodeGenCXX/temporaries.cpp

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions clang/test/CodeGenCXX/throw-expressions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -fcxx-exceptions -fexceptions -Wno-unreachable-code -Werror -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -Wno-unreachable-code -Werror -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s

int val = 42;
int& test1() {
Expand Down Expand Up @@ -34,7 +34,7 @@ int test5(bool x, bool y, int z) {
// CHECK: br i1
//
// y.true:
// CHECK: load i32, i32*
// CHECK: load i32, ptr
// CHECK: br label
//
// y.false:
Expand All @@ -58,7 +58,7 @@ int test6(bool x, bool y, int z) {
// CHECK: br i1
//
// y.true:
// CHECK: load i32, i32*
// CHECK: load i32, ptr
// CHECK: br label
//
// y.false:
Expand All @@ -77,7 +77,7 @@ namespace DR1560 {
// CHECK-LABEL: @_ZN6DR15601bE
const A &r = b ? get() : throw 0;
// CHECK-NOT: call {{.*}}@_ZN6DR15601AD1Ev
// CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN6DR15601AD1Ev {{.*}} @_ZGRN6DR15601rE
// CHECK: call {{.*}} @__cxa_atexit(ptr @_ZN6DR15601AD1Ev, ptr @_ZGRN6DR15601rE
// CHECK-NOT: call {{.*}}@_ZN6DR15601AD1Ev

// PR28184
Expand All @@ -103,7 +103,7 @@ void test7(bool cond) {
cond ? throw test7 : val;
}

// CHECK-LABEL: define{{.*}} nonnull align 4 dereferenceable(4) i32* @_Z5test8b(
// CHECK-LABEL: define{{.*}} nonnull align 4 dereferenceable(4) ptr @_Z5test8b(
int &test8(bool cond) {
// CHECK: br i1
//
Expand All @@ -115,6 +115,6 @@ int &test8(bool cond) {
// CHECK-NEXT: unreachable
//
// end:
// CHECK: ret i32* @val
// CHECK: ret ptr @val
return cond ? val : ((throw "foo"));
}
82 changes: 41 additions & 41 deletions clang/test/CodeGenCXX/thunks.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Sparc64 doesn't support musttail (yet), so it uses method cloning for
// variadic thunks. Use it for testing.
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=sparc64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - \
// RUN: %clang_cc1 %s -triple=sparc64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - \
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-CLONE,CHECK-NONOPT %s
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=sparc64-pc-linux-gnu -debug-info-kind=standalone -dwarf-version=5 -funwind-tables=2 -emit-llvm -o - \
// RUN: %clang_cc1 %s -triple=sparc64-pc-linux-gnu -debug-info-kind=standalone -dwarf-version=5 -funwind-tables=2 -emit-llvm -o - \
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-CLONE,CHECK-NONOPT,CHECK-DBG %s
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=sparc64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: %clang_cc1 %s -triple=sparc64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-CLONE,CHECK-OPT %s

// Test x86_64, which uses musttail for variadic thunks.
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=x86_64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-TAIL,CHECK-OPT %s

// Finally, reuse these tests for the MS ABI.
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=x86_64-windows-msvc -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: %clang_cc1 %s -triple=x86_64-windows-msvc -funwind-tables=2 -emit-llvm -o - -O1 -disable-llvm-passes \
// RUN: | FileCheck --check-prefixes=WIN64 %s


Expand Down Expand Up @@ -40,7 +40,7 @@ struct C : A, B {
//
// WIN64-LABEL: define dso_local void @"?f@C@Test1@@UEAAXXZ"(
// WIN64-LABEL: define linkonce_odr dso_local void @"?f@C@Test1@@W7EAAXXZ"(
// WIN64: getelementptr i8, i8* {{.*}}, i32 -8
// WIN64: getelementptr i8, ptr {{.*}}, i32 -8
// WIN64: ret void
void C::f() { }

Expand Down Expand Up @@ -87,8 +87,8 @@ struct B : A {
virtual V2 *f();
};

// CHECK: define{{.*}} %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv(
// WIN64: define weak_odr dso_local noundef %{{.*}} @"?f@B@Test3@@QEAAPEAUV1@2@XZ"(
// CHECK: define{{.*}} ptr @_ZTch0_v0_n24_N5Test31B1fEv(
// WIN64: define weak_odr dso_local noundef ptr @"?f@B@Test3@@QEAAPEAUV1@2@XZ"(
V2 *B::f() { return 0; }

}
Expand Down Expand Up @@ -269,12 +269,12 @@ namespace Test8 {
struct B { virtual void bar(NonPOD); };
struct C : A, B { virtual void bar(NonPOD); static void helper(NonPOD); };

// CHECK: define{{.*}} void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]*
// CHECK: define{{.*}} void @_ZN5Test81C6helperENS_6NonPODE(ptr
void C::helper(NonPOD var) {}

// CHECK-LABEL: define{{.*}} void @_ZThn8_N5Test81C3barENS_6NonPODE(
// CHECK-DBG-NOT: dbg.declare
// CHECK-NOT: load [[NONPODTYPE]], [[NONPODTYPE]]*
// CHECK-NOT: load [[NONPODTYPE:%.*]], ptr
// CHECK-NOT: memcpy
// CHECK: ret void
void C::bar(NonPOD var) {}
Expand Down Expand Up @@ -327,15 +327,15 @@ namespace Test11 {
// CHECK-DBG-NOT: dbg.declare
// CHECK: ret

// WIN64-LABEL: define dso_local noundef %{{.*}}* @"?f@C@Test11@@UEAAPEAU12@XZ"(i8*
// WIN64-LABEL: define dso_local noundef ptr @"?f@C@Test11@@UEAAPEAU12@XZ"(ptr

// WIN64-LABEL: define weak_odr dso_local noundef %{{.*}}* @"?f@C@Test11@@QEAAPEAUA@2@XZ"(i8*
// WIN64: call noundef %{{.*}}* @"?f@C@Test11@@UEAAPEAU12@XZ"(i8* noundef %{{.*}})
// WIN64-LABEL: define weak_odr dso_local noundef ptr @"?f@C@Test11@@QEAAPEAUA@2@XZ"(ptr
// WIN64: call noundef ptr @"?f@C@Test11@@UEAAPEAU12@XZ"(ptr noundef %{{.*}})
//
// Match the vbtable return adjustment.
// WIN64: load i32*, i32** %{{[^,]*}}, align 8
// WIN64: getelementptr inbounds i32, i32* %{{[^,]*}}, i32 1
// WIN64: load i32, i32* %{{[^,]*}}, align 4
// WIN64: load ptr, ptr %{{[^,]*}}, align 8
// WIN64: getelementptr inbounds i32, ptr %{{[^,]*}}, i32 1
// WIN64: load i32, ptr %{{[^,]*}}, align 4
}

// Varargs thunk test.
Expand All @@ -360,8 +360,8 @@ namespace Test12 {
// are generated.
// CHECK: define {{.*}} @_ZTchn8_h8_N6Test121C1fEiz
// CHECK-DBG-NOT: dbg.declare
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -8
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 8
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 -8
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 8

// The vtable layout goes:
// C vtable in A:
Expand All @@ -372,16 +372,16 @@ namespace Test12 {
// FIXME: The weak_odr linkage is probably not necessary and just an artifact
// of Itanium ABI details.
// WIN64-LABEL: define dso_local {{.*}} @"?f@C@Test12@@UEAAPEAU12@HZZ"(
// WIN64: call noundef %{{.*}}* @"?makeC@Test12@@YAPEAUC@1@XZ"()
// WIN64: call noundef ptr @"?makeC@Test12@@YAPEAUC@1@XZ"()
//
// This thunk needs return adjustment, clone.
// WIN64-LABEL: define weak_odr dso_local {{.*}} @"?f@C@Test12@@W7EAAPEAUB@2@HZZ"(
// WIN64: call noundef %{{.*}}* @"?makeC@Test12@@YAPEAUC@1@XZ"()
// WIN64: getelementptr inbounds i8, i8* %{{.*}}, i32 8
// WIN64: call noundef ptr @"?makeC@Test12@@YAPEAUC@1@XZ"()
// WIN64: getelementptr inbounds i8, ptr %{{.*}}, i32 8
//
// Musttail call back to the A implementation after this adjustment from B to A.
// WIN64-LABEL: define linkonce_odr dso_local noundef %{{.*}}* @"?f@C@Test12@@W7EAAPEAU12@HZZ"(
// WIN64: getelementptr i8, i8* %{{[^,]*}}, i32 -8
// WIN64-LABEL: define linkonce_odr dso_local noundef ptr @"?f@C@Test12@@W7EAAPEAU12@HZZ"(
// WIN64: getelementptr i8, ptr %{{[^,]*}}, i32 -8
// WIN64: musttail call {{.*}} @"?f@C@Test12@@UEAAPEAU12@HZZ"(
C c;
}
Expand All @@ -406,22 +406,22 @@ namespace Test13 {
}
// CHECK: define {{.*}} @_ZTcvn8_n32_v8_n24_N6Test131D4foo1Ev
// CHECK-DBG-NOT: dbg.declare
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -8
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -32
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -24
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 8
// CHECK: ret %"struct.Test13::D"*
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 -8
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 -32
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 -24
// CHECK: getelementptr inbounds i8, ptr {{.*}}, i64 8
// CHECK: ret ptr

// WIN64-LABEL: define weak_odr dso_local noundef %"struct.Test13::D"* @"?foo1@D@Test13@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"(
// WIN64-LABEL: define weak_odr dso_local noundef ptr @"?foo1@D@Test13@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"(
// This adjustment.
// WIN64: getelementptr inbounds i8, i8* {{.*}}, i64 -12
// WIN64: getelementptr inbounds i8, ptr {{.*}}, i64 -12
// Call implementation.
// WIN64: call {{.*}} @"?foo1@D@Test13@@UEAAAEAU12@XZ"(i8* {{.*}})
// WIN64: call {{.*}} @"?foo1@D@Test13@@UEAAAEAU12@XZ"(ptr {{.*}})
// Virtual + nonvirtual return adjustment.
// WIN64: load i32*, i32** %{{[^,]*}}, align 8
// WIN64: getelementptr inbounds i32, i32* %{{[^,]*}}, i32 1
// WIN64: load i32, i32* %{{[^,]*}}, align 4
// WIN64: getelementptr inbounds i8, i8* %{{[^,]*}}, i32 %{{[^,]*}}
// WIN64: load ptr, ptr %{{[^,]*}}, align 8
// WIN64: getelementptr inbounds i32, ptr %{{[^,]*}}, i32 1
// WIN64: load i32, ptr %{{[^,]*}}, align 4
// WIN64: getelementptr inbounds i8, ptr %{{[^,]*}}, i32 %{{[^,]*}}
}

namespace Test14 {
Expand Down Expand Up @@ -464,7 +464,7 @@ namespace Test15 {
// If we have musttail, then we emit the thunk as available_externally.
// CHECK-TAIL: declare void @_ZN6Test151C1fEiz
// CHECK-TAIL: define available_externally void @_ZThn8_N6Test151C1fEiz({{.*}})
// CHECK-TAIL: musttail call void (%"struct.Test15::C"*, i32, ...) @_ZN6Test151C1fEiz({{.*}}, ...)
// CHECK-TAIL: musttail call void (ptr, i32, ...) @_ZN6Test151C1fEiz({{.*}}, ...)

// MS C++ ABI doesn't use a thunk, so this case isn't interesting.
}
Expand Down Expand Up @@ -506,13 +506,13 @@ C c;
// CHECK-CLONE-LABEL: declare void @_ZThn8_N6Test171C1fEPKcz(

// CHECK-TAIL-LABEL: define available_externally void @_ZThn8_N6Test171C1fEPKcz(
// CHECK-TAIL: getelementptr inbounds i8, i8* %{{.*}}, i64 -8
// CHECK-TAIL: getelementptr inbounds i8, ptr %{{.*}}, i64 -8
// CHECK-TAIL: musttail call {{.*}} @_ZN6Test171C1fEPKcz({{.*}}, ...)

// MSVC-LABEL: define linkonce_odr dso_local void @"?f@C@Test17@@G7EAAXPEBDZZ"
// MSVC-SAME: (%"class.Test17::C"* %this, i8* %[[ARG:[^,]+]], ...)
// MSVC: getelementptr i8, i8* %{{.*}}, i32 -8
// MSVC: musttail call void (%"class.Test17::C"*, i8*, ...) @"?f@C@Test17@@EEAAXPEBDZZ"(%"class.Test17::C"* %{{.*}}, i8* noundef %[[ARG]], ...)
// MSVC-SAME: (ptr %this, ptr %[[ARG:[^,]+]], ...)
// MSVC: getelementptr i8, ptr %{{.*}}, i32 -8
// MSVC: musttail call void (ptr, ptr, ...) @"?f@C@Test17@@EEAAXPEBDZZ"(ptr %{{.*}}, ptr noundef %[[ARG]], ...)
}

/**** The following has to go at the end of the file ****/
Expand All @@ -529,7 +529,7 @@ C c;
// CHECK-NONOPT-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv

// Checking with opt
// CHECK-OPT-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(%"struct.Test4B::(anonymous namespace)::C"* noundef %this) unnamed_addr #1 align 2
// CHECK-OPT-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(ptr noundef %this) unnamed_addr #1 align 2

// This is from Test5:
// CHECK-OPT-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
Expand Down
92 changes: 45 additions & 47 deletions clang/test/CodeGenCXX/trivial-auto-var-init.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO

// None of the synthesized globals should contain `undef`.
// PATTERN-NOT: undef
Expand All @@ -12,19 +12,19 @@ extern "C" {

// UNINIT-LABEL: test_selfinit(
// ZERO-LABEL: test_selfinit(
// ZERO: store i32 0, i32* %self, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_selfinit(
// PATTERN: store i32 -1431655766, i32* %self, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
void test_selfinit() {
int self = self + 1;
used(self);
}

// UNINIT-LABEL: test_block(
// ZERO-LABEL: test_block(
// ZERO: store i32 0, i32* %block, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO: store i32 0, ptr %block, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_block(
// PATTERN: store i32 -1431655766, i32* %block, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN: store i32 -1431655766, ptr %block, align 4, !annotation [[AUTO_INIT:!.+]]
void test_block() {
__block int block;
used(block);
Expand All @@ -36,15 +36,15 @@ void test_block() {
//
// UNINIT-LABEL: test_block_self_init(
// ZERO-LABEL: test_block_self_init(
// ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// ZERO: %call = call %struct.XYZ* @create(
// ZERO: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured, ptr %captured, i32 0, i32 4
// ZERO-NEXT: store ptr null, ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// ZERO: %call = call ptr @create(
// PATTERN-LABEL: test_block_self_init(
// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// PATTERN: %call = call %struct.XYZ* @create(
// PATTERN: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, ptr %captured, i32 0, i32 4
// PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// PATTERN: %call = call ptr @create(
using Block = void (^)();
typedef struct XYZ {
Block block;
Expand All @@ -60,15 +60,15 @@ void test_block_self_init() {
//
// UNINIT-LABEL: test_block_captures_self_after_init(
// ZERO-LABEL: test_block_captures_self_after_init(
// ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// ZERO: %call = call %struct.XYZ* @create(
// ZERO: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, ptr %captured, i32 0, i32 4
// ZERO-NEXT: store ptr null, ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// ZERO: %call = call ptr @create(
// PATTERN-LABEL: test_block_captures_self_after_init(
// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// PATTERN: %call = call %struct.XYZ* @create(
// PATTERN: %block = alloca <{ ptr, i32, i32, ptr, ptr, ptr }>, align 8
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, ptr %captured, i32 0, i32 4
// PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %captured1, align 8, !annotation [[AUTO_INIT:!.+]]
// PATTERN: %call = call ptr @create(
void test_block_captures_self_after_init() {
extern xyz_t create(Block block);
__block xyz_t captured;
Expand Down Expand Up @@ -97,13 +97,13 @@ void test_goto_unreachable_value() {
// ZERO-LABEL: test_goto(
// ZERO: if.then:
// ZERO: br label %jump
// ZERO: store i32 0, i32* %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO: br label %jump
// ZERO: jump:
// PATTERN-LABEL: test_goto(
// PATTERN: if.then:
// PATTERN: br label %jump
// PATTERN: store i32 -1431655766, i32* %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN: store i32 -1431655766, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN: br label %jump
// PATTERN: jump:
void test_goto(int i) {
Expand All @@ -119,12 +119,12 @@ void test_goto(int i) {
// UNINIT-LABEL: test_switch(
// ZERO-LABEL: test_switch(
// ZERO: sw.bb:
// ZERO-NEXT: store i32 0, i32* %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO-NEXT: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// ZERO: sw.bb1:
// ZERO-NEXT: call void @{{.*}}used
// PATTERN-LABEL: test_switch(
// PATTERN: sw.bb:
// PATTERN-NEXT: store i32 -1431655766, i32* %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN-NEXT: store i32 -1431655766, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
// PATTERN: sw.bb1:
// PATTERN-NEXT: call void @{{.*}}used
void test_switch(int i) {
Expand All @@ -140,20 +140,19 @@ void test_switch(int i) {
// UNINIT-LABEL: test_vla(
// ZERO-LABEL: test_vla(
// ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4
// ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// ZERO: call void @llvm.memset{{.*}}(ptr align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_vla(
// PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0
// PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop
// PATTERN: vla-setup.loop:
// PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4
// PATTERN: %vla.begin = bitcast i32* %vla to i8*
// PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]]
// PATTERN: %vla.end = getelementptr inbounds i8, ptr %vla, i64 %[[SIZE]]
// PATTERN: br label %vla-init.loop
// PATTERN: vla-init.loop:
// PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_vla.vla {{.*}}), !annotation [[AUTO_INIT:!.+]]
// PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 4
// PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end
// PATTERN: %vla.cur = phi ptr [ %vla, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_vla.vla{{.*}}), !annotation [[AUTO_INIT:!.+]]
// PATTERN: %vla.next = getelementptr inbounds i8, ptr %vla.cur, i64 4
// PATTERN: %vla-init.isdone = icmp eq ptr %vla.next, %vla.end
// PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop
// PATTERN: vla-init.cont:
// PATTERN: call void @{{.*}}used
Expand All @@ -177,11 +176,11 @@ void test_vla(int size) {
// ZERO-LABEL: test_alloca(
// ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
// ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
// ZERO-NEXT: call void @llvm.memset{{.*}}(i8* align [[ALIGN]] %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// ZERO-NEXT: call void @llvm.memset{{.*}}(ptr align [[ALIGN]] %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_alloca(
// PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
// PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align [[ALIGN:[0-9]+]]
// PATTERN-NEXT: call void @llvm.memset{{.*}}(i8* align [[ALIGN]] %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-NEXT: call void @llvm.memset{{.*}}(ptr align [[ALIGN]] %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
void test_alloca(int size) {
void *ptr = __builtin_alloca(size);
used(ptr);
Expand All @@ -191,11 +190,11 @@ void test_alloca(int size) {
// ZERO-LABEL: test_alloca_with_align(
// ZERO: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
// ZERO-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
// ZERO-NEXT: call void @llvm.memset{{.*}}(i8* align 128 %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// ZERO-NEXT: call void @llvm.memset{{.*}}(ptr align 128 %[[ALLOCA]], i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_alloca_with_align(
// PATTERN: %[[SIZE:[a-z0-9]+]] = sext i32 %{{.*}} to i64
// PATTERN-NEXT: %[[ALLOCA:[a-z0-9]+]] = alloca i8, i64 %[[SIZE]], align 128
// PATTERN-NEXT: call void @llvm.memset{{.*}}(i8* align 128 %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-NEXT: call void @llvm.memset{{.*}}(ptr align 128 %[[ALLOCA]], i8 -86, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
void test_alloca_with_align(int size) {
void *ptr = __builtin_alloca_with_align(size, 1024);
used(ptr);
Expand Down Expand Up @@ -232,20 +231,19 @@ void test_alloca_with_align_uninitialized(int size) {
// UNINIT-LABEL: test_struct_vla(
// ZERO-LABEL: test_struct_vla(
// ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
// ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// ZERO: call void @llvm.memset{{.*}}(ptr align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false), !annotation [[AUTO_INIT:!.+]]
// PATTERN-LABEL: test_struct_vla(
// PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0
// PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop
// PATTERN: vla-setup.loop:
// PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16
// PATTERN: %vla.begin = bitcast %struct.anon* %vla to i8*
// PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]]
// PATTERN: %vla.end = getelementptr inbounds i8, ptr %vla, i64 %[[SIZE]]
// PATTERN: br label %vla-init.loop
// PATTERN: vla-init.loop:
// PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla {{.*}}), !annotation [[AUTO_INIT:!.+]]
// PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 16
// PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end
// PATTERN: %vla.cur = phi ptr [ %vla, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla{{.*}}), !annotation [[AUTO_INIT:!.+]]
// PATTERN: %vla.next = getelementptr inbounds i8, ptr %vla.cur, i64 16
// PATTERN: %vla-init.isdone = icmp eq ptr %vla.next, %vla.end
// PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop
// PATTERN: vla-init.cont:
// PATTERN: call void @{{.*}}used
Expand Down Expand Up @@ -310,10 +308,10 @@ void test_huge_small_init() {

// UNINIT-LABEL: test_huge_larger_init(
// ZERO-LABEL: test_huge_larger_init(
// ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536,
// ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, i64 65536,
// ZERO-NOT: !annotation
// PATTERN-LABEL: test_huge_larger_init(
// PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536,
// PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, i64 65536,
// PATTERN-NOT: !annotation
void test_huge_larger_init() {
char big[65536] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
Expand Down
126 changes: 62 additions & 64 deletions clang/test/CodeGenCXX/trivial_abi.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -no-opaque-pointers -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s

// CHECK: %[[STRUCT_SMALL:.*]] = type { i32* }
// CHECK: %[[STRUCT_LARGE:.*]] = type { i32*, [128 x i32] }
// CHECK: %[[STRUCT_SMALL:.*]] = type { ptr }
// CHECK: %[[STRUCT_LARGE:.*]] = type { ptr, [128 x i32] }
// CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 }
// CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32 }

Expand Down Expand Up @@ -58,22 +58,22 @@ struct D0 : B0, B1 {
// CHECK-LABEL: define{{.*}} i64 @_ZThn8_N2D02m0Ev(
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[CALL:.*]] = tail call i64 @_ZN2D02m0Ev(
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V3:.*]] = load i32*, i32** %[[COERCE_DIVE2]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V3]] to i64
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V3:.*]] = load ptr, ptr %[[COERCE_DIVE2]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V3]] to i64
// CHECK: ret i64 %[[COERCE_VAL_PI]]

Small D0::m0() { return {}; }

// CHECK: define{{.*}} void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[A]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i32*
// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[A]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[A]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[A]])
// CHECK: ret void
// CHECK: }

Expand All @@ -82,10 +82,10 @@ void testParamSmall(Small a) noexcept {

// CHECK: define{{.*}} i64 @_Z15testReturnSmallv()
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[RETVAL]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[RETVAL]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
// CHECK: ret i64 %[[COERCE_VAL_PI]]
// CHECK: }

Expand All @@ -97,13 +97,13 @@ Small testReturnSmall() {
// CHECK: define{{.*}} void @_Z14testCallSmall0v()
// CHECK: %[[T:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[T]])
// CHECK: %[[CALL1:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallC1ERKS_(%[[STRUCT_SMALL]]* {{[^,]*}} %[[AGG_TMP]], %[[STRUCT_SMALL]]* noundef nonnull align 8 dereferenceable(8) %[[T]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[T]])
// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(8) %[[T]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
// CHECK: %[[CALL2:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[T]])
// CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[T]])
// CHECK: ret void
// CHECK: }

Expand All @@ -115,12 +115,12 @@ void testCallSmall0() {
// CHECK: define{{.*}} void @_Z14testCallSmall1v()
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
// CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE1]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE1]], align 8
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
// CHECK: ret void
// CHECK: }
Expand All @@ -132,27 +132,27 @@ void testCallSmall1() {
// CHECK: define{{.*}} void @_Z16testIgnoredSmallv()
// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
// CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP_ENSURED]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
// CHECK: %[[CALL1:.*]] = call noundef %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[AGG_TMP_ENSURED]])
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], ptr %[[AGG_TMP_ENSURED]], i32 0, i32 0
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[AGG_TMP_ENSURED]])
// CHECK: ret void
// CHECK: }

void testIgnoredSmall() {
testReturnSmall();
}

// CHECK: define{{.*}} void @_Z14testParamLarge5Large(%[[STRUCT_LARGE:.*]]* noundef %[[A:.*]])
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[A]])
// CHECK: define{{.*}} void @_Z14testParamLarge5Large(ptr noundef %[[A:.*]])
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[A]])
// CHECK: ret void
// CHECK: }

void testParamLarge(Large a) noexcept {
}

// CHECK: define{{.*}} void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_RESULT:.*]])
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_RESULT]])
// CHECK: define{{.*}} void @_Z15testReturnLargev(ptr noalias sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_RESULT:.*]])
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_RESULT]])
// CHECK: ret void
// CHECK: }

Expand All @@ -164,10 +164,10 @@ Large testReturnLarge() {
// CHECK: define{{.*}} void @_Z14testCallLarge0v()
// CHECK: %[[T:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[T]])
// CHECK: %[[CALL1:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeC1ERKS_(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_TMP]], %[[STRUCT_LARGE]]* noundef nonnull align 8 dereferenceable(520) %[[T]])
// CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* noundef %[[AGG_TMP]])
// CHECK: %[[CALL2:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[T]])
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[T]])
// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5LargeC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(520) %[[T]])
// CHECK: call void @_Z14testParamLarge5Large(ptr noundef %[[AGG_TMP]])
// CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[T]])
// CHECK: ret void
// CHECK: }

Expand All @@ -178,8 +178,8 @@ void testCallLarge0() {

// CHECK: define{{.*}} void @_Z14testCallLarge1v()
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP]])
// CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* noundef %[[AGG_TMP]])
// CHECK: call void @_Z15testReturnLargev(ptr sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP]])
// CHECK: call void @_Z14testParamLarge5Large(ptr noundef %[[AGG_TMP]])
// CHECK: ret void
// CHECK: }

Expand All @@ -189,8 +189,8 @@ void testCallLarge1() {

// CHECK: define{{.*}} void @_Z16testIgnoredLargev()
// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP_ENSURED]])
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_TMP_ENSURED]])
// CHECK: call void @_Z15testReturnLargev(ptr sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP_ENSURED]])
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[AGG_TMP_ENSURED]])
// CHECK: ret void
// CHECK: }

Expand All @@ -200,8 +200,8 @@ void testIgnoredLarge() {

// CHECK: define{{.*}} i32 @_Z20testReturnHasTrivialv()
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_TRIVIAL:.*]], align 4
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_TRIVIAL]], %[[STRUCT_TRIVIAL]]* %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load i32, i32* %[[COERCE_DIVE]], align 4
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_TRIVIAL]], ptr %[[RETVAL]], i32 0, i32 0
// CHECK: %[[V0:.*]] = load i32, ptr %[[COERCE_DIVE]], align 4
// CHECK: ret i32 %[[V0]]
// CHECK: }

Expand All @@ -210,8 +210,8 @@ Trivial testReturnHasTrivial() {
return t;
}

// CHECK: define{{.*}} void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret(%[[STRUCT_NONTRIVIAL]]) align 4 %[[AGG_RESULT:.*]])
// CHECK: %[[CALL:.*]] = call noundef %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialC1Ev(%[[STRUCT_NONTRIVIAL]]* {{[^,]*}} %[[AGG_RESULT]])
// CHECK: define{{.*}} void @_Z23testReturnHasNonTrivialv(ptr noalias sret(%[[STRUCT_NONTRIVIAL:.*]]) align 4 %[[AGG_RESULT:.*]])
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10NonTrivialC1Ev(ptr {{[^,]*}} %[[AGG_RESULT]])
// CHECK: ret void
// CHECK: }

Expand All @@ -223,17 +223,17 @@ NonTrivial testReturnHasNonTrivial() {
// CHECK: define{{.*}} void @_Z18testExceptionSmallv()
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_SMALL]], align 8
// CHECK: call noundef %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[AGG_TMP]])
// CHECK: invoke noundef %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[AGG_TMP1]])
// CHECK: call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
// CHECK: invoke noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])

// CHECK: call void @_Z20calleeExceptionSmall5SmallS_(i64 %{{.*}}, i64 %{{.*}})
// CHECK-NEXT: ret void

// CHECK: landingpad { i8*, i32 }
// CHECK: call noundef %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* {{[^,]*}} %[[AGG_TMP]])
// CHECK: landingpad { ptr, i32 }
// CHECK: call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
// CHECK: br

// CHECK: resume { i8*, i32 }
// CHECK: resume { ptr, i32 }

void calleeExceptionSmall(Small, Small);

Expand All @@ -244,17 +244,17 @@ void testExceptionSmall() {
// CHECK: define{{.*}} void @_Z18testExceptionLargev()
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8
// CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_LARGE]], align 8
// CHECK: call noundef %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_TMP]])
// CHECK: invoke noundef %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_TMP1]])
// CHECK: call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
// CHECK: invoke noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])

// CHECK: call void @_Z20calleeExceptionLarge5LargeS_(%[[STRUCT_LARGE]]* noundef %[[AGG_TMP]], %[[STRUCT_LARGE]]* noundef %[[AGG_TMP1]])
// CHECK: call void @_Z20calleeExceptionLarge5LargeS_(ptr noundef %[[AGG_TMP]], ptr noundef %[[AGG_TMP1]])
// CHECK-NEXT: ret void

// CHECK: landingpad { i8*, i32 }
// CHECK: call noundef %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* {{[^,]*}} %[[AGG_TMP]])
// CHECK: landingpad { ptr, i32 }
// CHECK: call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
// CHECK: br

// CHECK: resume { i8*, i32 }
// CHECK: resume { ptr, i32 }

void calleeExceptionLarge(Large, Large);

Expand All @@ -270,9 +270,7 @@ void testExceptionLarge() {
// CHECK: %[[CALL:.*]] = call{{.*}} @"_ZNK3$_0clEv"
// CHECK: %[[COERCEDIVE:.*]] = getelementptr{{.*}} %[[COERCE]]
// CHECK: %[[COERCEVALIP:.*]] = inttoptr{{.*}} %[[CALL]]
// CHECK: %[[RETVALP:.*]] = bitcast %[[STRUCT_SMALL]]* %[[RETVAL]]
// CHECK: %[[COERCEP:.*]] = bitcast %[[STRUCT_SMALL]]* %[[COERCE]]
// CHECK: call {{.*}}memcpy{{.*}} %[[RETVALP]]{{.*}} %[[COERCEP]]
// CHECK: call {{.*}}memcpy{{.*}} %[[RETVAL]]{{.*}} %[[COERCE]]
// CHECK: %[[COERCEDIVE1:.*]] = getelementptr{{.*}} %[[RETVAL]]
// CHECK: %[[TMP:.*]] = load{{.*}} %[[COERCEDIVE1]]
// CHECK: %[[COERCEVALPI:.*]] = ptrtoint{{.*}} %[[TMP]]
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CodeGenCXX/try-catch.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s

struct X { };

Expand All @@ -7,15 +7,15 @@ const X g();
void f() {
try {
throw g();
// CHECK: @_ZTI1X to i8
// CHECK: @_ZTI1X
} catch (const X x) {
}
}

void h() {
try {
throw "ABC";
// CHECK: @_ZTIPKc to i8
// CHECK: @_ZTIPKc
} catch (char const(&)[4]) {
}
}
88 changes: 43 additions & 45 deletions clang/test/CodeGenCXX/type-metadata.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Tests for the cfi-vcall feature:
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=NDIAG %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=MS --check-prefix=TT-MS --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-NVT --check-prefix=MS --check-prefix=TT-MS --check-prefix=NDIAG %s

// Tests for the whole-program-vtables feature:
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM-DEFAULTVIS --check-prefix=TT-ITANIUM-DEFAULT %s
// RUN: %clang_cc1 -no-opaque-pointers -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM-HIDDEN %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM-DEFAULTVIS --check-prefix=TT-ITANIUM-DEFAULT %s
// RUN: %clang_cc1 -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s

// Tests for cfi + whole-program-vtables:
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM --check-prefix=TC-ITANIUM %s
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=MS --check-prefix=TC-MS %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=ITANIUM --check-prefix=TC-ITANIUM %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=CFI-VT --check-prefix=MS --check-prefix=TC-MS %s

// ITANIUM: @_ZTV1A = {{[^!]*}}, !type [[A16:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL16:![0-9]+]]
Expand All @@ -38,7 +38,7 @@

// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}type-metadata.cpp\00", align 1
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 123, i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { ptr, i32, i32 }, ptr } { i8 0, { ptr, i32, i32 } { ptr @[[SRC]], i32 123, i32 3 }, ptr @[[TYPE]] }

// ITANIUM: @_ZTVN12_GLOBAL__N_11DE = {{[^!]*}}, !type [[A32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
Expand Down Expand Up @@ -85,7 +85,7 @@
// ITANIUM-OPT: @_ZTVN5test31EE = available_externally unnamed_addr constant {{[^!]*}},
// ITANIUM-OPT-SAME: !type [[E16:![0-9]+]],
// ITANIUM-OPT-SAME: !type [[EF16:![0-9]+]]
// ITANIUM-OPT: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast ({ [3 x i8*] }* @_ZTVN5test31EE to i8*)]
// ITANIUM-OPT: @llvm.compiler.used = appending global [1 x ptr] [ptr @_ZTVN5test31EE]

// MS: comdat($"??_7A@@6B@"), !type [[A8:![0-9]+]]
// MS: comdat($"??_7B@@6B0@@"), !type [[B8:![0-9]+]]
Expand Down Expand Up @@ -141,66 +141,64 @@ void D::h() {
// ITANIUM-DEFAULTVIS: define{{.*}} void @_Z2afP1A
// MS: define dso_local void @"?af@@YAXPEAUA@@@Z"
void af(A *a) {
// TT-ITANIUM-HIDDEN: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
// TT-ITANIUM-DEFAULT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
// TT-MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
// TC-ITANIUM: [[PAIR:%[^ ]*]] = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
// TC-MS: [[PAIR:%[^ ]*]] = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
// CFI-VT: [[P:%[^ ]*]] = extractvalue { i8*, i1 } [[PAIR]], 1
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT]], metadata !"all-vtables")
// TT-ITANIUM-HIDDEN: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
// TT-ITANIUM-DEFAULT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(ptr [[VT:%[^ ]*]], metadata !"_ZTS1A")
// TT-MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata !"?AUA@@")
// TC-ITANIUM: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
// TC-MS: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
// CFI-VT: [[P:%[^ ]*]] = extractvalue { ptr, i1 } [[PAIR]], 1
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT]], metadata !"all-vtables")
// VTABLE-OPT: call void @llvm.assume(i1 [[P]])
// CFI-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
// CFI-NEXT: {{^$}}

// CFI: [[TRAPBB]]
// NDIAG-NEXT: call void @llvm.ubsantrap(i8 2)
// NDIAG-NEXT: unreachable
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint ptr [[VT]] to i64
// DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(ptr @[[BADTYPESTATIC]], i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-ABORT-NEXT: unreachable
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(ptr @[[BADTYPESTATIC]], i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]

// CFI: [[CONTBB]]
// CFI-NVT: [[PTR:%[^ ]*]] = load
// CFI-VT: [[PTRI8:%[^ ]*]] = extractvalue { i8*, i1 } [[PAIR]], 0
// CFI-VT: [[PTR:%[^ ]*]] = bitcast i8* [[PTRI8]] to
// CFI: call void [[PTR]]
// CFI-VT: [[PTRI8:%[^ ]*]] = extractvalue { ptr, i1 } [[PAIR]], 0
#line 123
a->f();
}

// ITANIUM: define internal void @_Z3df1PN12_GLOBAL__N_11DE
// MS: define internal void @"?df1@@YAXPEAUD@?A0x{{[^@]*}}@@@Z"
void df1(D *d) {
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUA@@")
// TC-ITANIUM: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
// TC-MS: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@@")
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@@")
d->f();
}

// ITANIUM: define internal void @_Z3dg1PN12_GLOBAL__N_11DE
// MS: define internal void @"?dg1@@YAXPEAUD@?A0x{{[^@]*}}@@@Z"
void dg1(D *d) {
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUB@@")
// TC-ITANIUM: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
// TC-MS: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata !"?AUB@@")
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTS1B")
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUB@@")
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUB@@")
d->g();
}

// ITANIUM: define internal void @_Z3dh1PN12_GLOBAL__N_11DE
// MS: define internal void @"?dh1@@YAXPEAUD@?A0x{{[^@]*}}@@@Z"
void dh1(D *d) {
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TC-ITANIUM: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
// TC-MS: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 8, metadata ![[DTYPE:[0-9]+]])
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE]])
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE:[0-9]+]])
d->h();
}

Expand Down Expand Up @@ -256,11 +254,11 @@ struct D : C {
// ITANIUM-DEFAULTVIS: define{{.*}} void @_ZN5test21fEPNS_1DE
// MS: define dso_local void @"?f@test2@@YAXPEAUD@1@@Z"
void f(D *d) {
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
// TC-ITANIUM: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
// TC-MS: {{%[^ ]*}} = call { i8*, i1 } @llvm.type.checked.load(i8* {{%[^ ]*}}, i32 0, metadata !"?AUA@test2@@")
// TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata !"?AUA@test2@@")
// TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
// TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"?AUA@test2@@")
d->m_fn1();
}

Expand Down
8 changes: 4 additions & 4 deletions clang/test/CodeGenCXX/typeid-cxx11.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s
// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s
#include <typeinfo>

namespace Test1 {
Expand All @@ -18,15 +18,15 @@ struct A { virtual ~A(); };
struct B : virtual A {};
struct C { int n; };

// CHECK: @_ZN5Test15itemsE ={{.*}} constant [4 x {{.*}}] [{{.*}} @_ZTIN5Test11AE {{.*}}, {{.*}}, {{.*}} @_ZN5Test19make_implINS_1AEEEPvv }, {{.*}} @_ZTIN5Test11BE {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} @_ZTIN5Test11CE {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} @_ZTIi {{.*}} @_ZN5Test19make_implIiEEPvv }]
// CHECK: @_ZN5Test15itemsE ={{.*}} constant [4 x {{.*}}] [{{.*}} @_ZTIN5Test11AE, {{.*}} @_ZN5Test19make_implINS_1AEEEPvv {{.*}} @_ZTIN5Test11BE, {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} @_ZTIN5Test11CE, {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} @_ZTIi, {{.*}} @_ZN5Test19make_implIiEEPvv }]
extern constexpr Item items[] = {
item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
};

// CHECK: @_ZN5Test11xE ={{.*}} constant %"class.std::type_info"* bitcast ({{.*}}* @_ZTIN5Test11AE to %"class.std::type_info"*), align 8
// CHECK: @_ZN5Test11xE ={{.*}} constant ptr @_ZTIN5Test11AE, align 8
constexpr auto &x = items[0].ti;

// CHECK: @_ZN5Test11yE ={{.*}} constant %"class.std::type_info"* bitcast ({{.*}}* @_ZTIN5Test11BE to %"class.std::type_info"*), align 8
// CHECK: @_ZN5Test11yE ={{.*}} constant ptr @_ZTIN5Test11BE, align 8
constexpr auto &y = typeid(B{});

}
44 changes: 22 additions & 22 deletions clang/test/CodeGenCXX/ubsan-devirtualized-calls.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple %itanium_abi_triple -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s

struct Base1 {
virtual void f1() {}
Expand All @@ -24,65 +24,65 @@ struct Derived4 final : Base1 {
void f1() override final {}
};

// CHECK: [[UBSAN_TI_DERIVED1_1:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived1 to i8*
// CHECK: [[UBSAN_TI_DERIVED2_1:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived2 to i8*
// CHECK: [[UBSAN_TI_DERIVED2_2:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived2 to i8*
// CHECK: [[UBSAN_TI_DERIVED3:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived3 to i8*
// CHECK: [[UBSAN_TI_BASE1:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI5Base1 to i8*
// CHECK: [[UBSAN_TI_DERIVED4_1:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived4 to i8*
// CHECK: [[UBSAN_TI_DERIVED4_2:@[0-9]+]] = private unnamed_addr global {{.*}} i8* bitcast {{.*}} @_ZTI8Derived4 to i8*
// CHECK: [[UBSAN_TI_DERIVED1_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived1
// CHECK: [[UBSAN_TI_DERIVED2_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived2
// CHECK: [[UBSAN_TI_DERIVED2_2:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived2
// CHECK: [[UBSAN_TI_DERIVED3:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived3
// CHECK: [[UBSAN_TI_BASE1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI5Base1
// CHECK: [[UBSAN_TI_DERIVED4_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived4
// CHECK: [[UBSAN_TI_DERIVED4_2:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived4

// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t1v
void t1() {
Derived1 d1;
static_cast<Base1 *>(&d1)->f1(); //< Devirt Base1::f1 to Derived1::f1.
// CHECK: %[[D1:[0-9]+]] = ptrtoint %struct.Derived1* %d1 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED1_1]] {{.*}}, i{{[0-9]+}} %[[D1]]
// CHECK: %[[D1:[0-9]+]] = ptrtoint ptr %d1 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED1_1]], i{{[0-9]+}} %[[D1]]
}

// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t2v
void t2() {
Derived2 d2;
static_cast<Base1 *>(&d2)->f1(); //< Devirt Base1::f1 to Derived2::f1.
// CHECK: %[[D2_1:[0-9]+]] = ptrtoint %struct.Derived2* %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_1]] {{.*}}, i{{[0-9]+}} %[[D2_1]]
// CHECK: %[[D2_1:[0-9]+]] = ptrtoint ptr %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_1]], i{{[0-9]+}} %[[D2_1]]
}

// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t3v
void t3() {
Derived2 d2;
static_cast<Base2 *>(&d2)->f1(); //< Devirt Base2::f1 to Derived2::f1.
// CHECK: %[[D2_2:[0-9]+]] = ptrtoint %struct.Derived2* %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_2]] {{.*}}, i{{[0-9]+}} %[[D2_2]]
// CHECK: %[[D2_2:[0-9]+]] = ptrtoint ptr %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_2]], i{{[0-9]+}} %[[D2_2]]
}

// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t4v
void t4() {
Base1 p;
Derived3 *badp = static_cast<Derived3 *>(&p); //< Check that &p isa Derived3.
// CHECK: %[[P1:[0-9]+]] = ptrtoint %struct.Derived3* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED3]] {{.*}}, i{{[0-9]+}} %[[P1]]
// CHECK: %[[P1:[0-9]+]] = ptrtoint ptr %p to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED3]], i{{[0-9]+}} %[[P1]]

static_cast<Base1 *>(badp)->f1(); //< No devirt, test 'badp isa Base1'.
// We were able to skip the null check on the first type check because 'p'
// is backed by an alloca. We can't skip the second null check because 'badp'
// is a (bitcast (load ...)).
// CHECK: call void @__ubsan_handle_type_mismatch
//
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint %struct.Base1* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_BASE1]] {{.*}}, i{{[0-9]+}} %[[BADP1]]
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint ptr {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_BASE1]], i{{[0-9]+}} %[[BADP1]]
}

// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t5v
void t5() {
Base1 p;
Derived4 *badp = static_cast<Derived4 *>(&p); //< Check that &p isa Derived4.
// CHECK: %[[P1:[0-9]+]] = ptrtoint %struct.Derived4* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_1]] {{.*}}, i{{[0-9]+}} %[[P1]]
// CHECK: %[[P1:[0-9]+]] = ptrtoint ptr %p to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_1]], i{{[0-9]+}} %[[P1]]

static_cast<Base1 *>(badp)->f1(); //< Devirt Base1::f1 to Derived4::f1.
// CHECK: call void @__ubsan_handle_type_mismatch
//
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint %struct.Derived4* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_2]] {{.*}}, i{{[0-9]+}} %[[BADP1]]
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint ptr {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_2]], i{{[0-9]+}} %[[BADP1]]
}
26 changes: 13 additions & 13 deletions clang/test/CodeGenCXX/ubsan-vtable-checks.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK-NULL --check-prefix=ITANIUM
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK-NULL --check-prefix=MSABI
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=MSABI --check-prefix=CHECK-VPTR-MS
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK-NULL --check-prefix=ITANIUM
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK-NULL --check-prefix=MSABI
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=MSABI --check-prefix=CHECK-VPTR-MS
struct T {
virtual ~T() {}
virtual int v() { return 1; }
Expand All @@ -20,35 +20,35 @@ U::~U() {}
// MSABI: define dso_local noundef i32 @"?get_v
int get_v(T* t) {
// First, we check that vtable is not loaded before a type check.
// CHECK-NULL-NOT: load {{.*}} (%struct.T*{{.*}})**, {{.*}} (%struct.T*{{.*}})***
// CHECK-NULL: [[UBSAN_CMP_RES:%[0-9]+]] = icmp ne %struct.T* %{{[_a-z0-9]+}}, null
// CHECK-NULL-NOT: load {{.*}} (ptr{{.*}})**, {{.*}} (ptr{{.*}})***
// CHECK-NULL: [[UBSAN_CMP_RES:%[0-9]+]] = icmp ne ptr %{{[_a-z0-9]+}}, null
// CHECK-NULL-NEXT: br i1 [[UBSAN_CMP_RES]], label %{{.*}}, label %{{.*}}
// CHECK-NULL: call void @__ubsan_handle_type_mismatch_v1_abort
// Second, we check that vtable is actually loaded once the type check is done.
// CHECK-NULL: load {{.*}} (%struct.T*{{.*}})**, {{.*}} (%struct.T*{{.*}})***
// CHECK-NULL: load ptr, ptr {{.*}}
return t->v();
}

// ITANIUM: define{{.*}} void @_Z9delete_itP1T
// MSABI: define dso_local void @"?delete_it
void delete_it(T *t) {
// First, we check that vtable is not loaded before a type check.
// CHECK-VPTR-NOT: load {{.*}} (%struct.T*{{.*}})**, {{.*}} (%struct.T*{{.*}})***
// CHECK-VPTR-NOT: load {{.*}} (ptr{{.*}})**, {{.*}} (ptr{{.*}})***
// CHECK-VPTR: br i1 {{.*}} label %{{.*}}
// CHECK-VPTR: call void @__ubsan_handle_dynamic_type_cache_miss_abort
// Second, we check that vtable is actually loaded once the type check is done.
// CHECK-VPTR: load {{.*}} (%struct.T*{{.*}})**, {{.*}} (%struct.T*{{.*}})***
// CHECK-VPTR: load ptr, ptr {{.*}}
delete t;
}

// ITANIUM: define{{.*}} %struct.U* @_Z7dyncastP1T
// MSABI: define dso_local noundef %struct.U* @"?dyncast
// ITANIUM: define{{.*}} ptr @_Z7dyncastP1T
// MSABI: define dso_local noundef ptr @"?dyncast
U* dyncast(T *t) {
// First, we check that dynamic_cast is not called before a type check.
// CHECK-VPTR-NOT: call i8* @__{{dynamic_cast|RTDynamicCast}}
// CHECK-VPTR-NOT: call ptr @__{{dynamic_cast|RTDynamicCast}}
// CHECK-VPTR: br i1 {{.*}} label %{{.*}}
// CHECK-VPTR: call void @__ubsan_handle_dynamic_type_cache_miss_abort
// Second, we check that dynamic_cast is actually called once the type check is done.
// CHECK-VPTR: call i8* @__{{dynamic_cast|RTDynamicCast}}
// CHECK-VPTR: call ptr @__{{dynamic_cast|RTDynamicCast}}
return dynamic_cast<U*>(t);
}
77 changes: 38 additions & 39 deletions clang/test/CodeGenCXX/value-init.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -no-opaque-pointers -std=c++98 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CXX98
// RUN: %clang_cc1 -no-opaque-pointers -std=c++17 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CXX17
// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CXX98
// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CXX17

struct A {
virtual ~A();
Expand All @@ -19,7 +19,7 @@ void test_value_init() {
// PR5800

// CHECK: store i32 17
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK: call void @llvm.memset.p0.i64
// CHECK: call void @_ZN1BC1Ev
C c = { 17 } ;
// CHECK: call void @_ZN1CD1Ev
Expand All @@ -44,7 +44,6 @@ struct enum_holder_and_int
// CHECK: _Z24test_enum_holder_and_intv()
void test_enum_holder_and_int() {
// CHECK: alloca
// CHECK-NEXT: bitcast
// CHECK-NEXT: call void @llvm.memset
// CHECK-NEXT: call void @_ZN19enum_holder_and_intC1Ev
enum_holder_and_int();
Expand Down Expand Up @@ -77,7 +76,7 @@ namespace ptrmem {

// CHECK-LABEL: define{{.*}} i32 @_ZN6ptrmem4testEPNS_1SE
int test(S *s) {
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
// CHECK: call void @llvm.memcpy.p0.p0.i64
// CHECK: getelementptr
// CHECK: ret
return s->*S().mem2;
Expand All @@ -102,29 +101,29 @@ struct Test3 : public Test { };

// CHECK-LABEL: define{{.*}} void @_ZN6PR98011fEv
void f() {
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK: call void @_ZN6PR98014TestC1Ei
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK: call void @_ZN6PR98014TestC1Ev
Test partial[3] = { 1 };

// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK: call void @_ZN6PR98014TestC1Ev
// CHECK-NOT: call void @_ZN6PR98014TestC1Ev
Test empty[3] = {};

// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @llvm.memset.p0.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK-CXX98: call void @_ZN6PR98015Test2C1Ev
// CHECK-CXX17: call void @_ZN6PR98014TestC1Ev
// CHECK-NOT: call void @_ZN6PR98015Test2C1Ev
Test2 empty2[3] = {};

// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK: call void @llvm.memset.p0.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK-CXX98: call void @_ZN6PR98015Test3C1Ev
// CHECK-CXX17: call void @_ZN6PR98014TestC2Ev
// CHECK-NOT: call void @llvm.memset.p0i8.i64
// CHECK-NOT: call void @llvm.memset.p0.i64
// CHECK-NOT: call void @_ZN6PR98015Test3C1Ev
Test3 empty3[3] = {};
}
Expand All @@ -136,7 +135,7 @@ namespace zeroinit {

// CHECK-LABEL: define{{.*}} i32 @_ZN8zeroinit4testEv()
int test() {
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK: call void @llvm.memset.p0.i64
// CHECK: ret i32 0
return S().i;
}
Expand All @@ -153,7 +152,7 @@ namespace zeroinit {

// CHECK-LABEL: define{{.*}} void @_ZN8zeroinit9testX0_X1Ev
void testX0_X1() {
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK: call void @llvm.memset.p0.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X1C1Ev
// CHECK-NEXT: call void @_ZN8zeroinit2X11fEv
X1().f();
Expand Down Expand Up @@ -207,35 +206,35 @@ namespace test6 {
// CHECK-LABEL: define{{.*}} void @_ZN5test64testEv()
// CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]],

// CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]], [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]], [20 x [[A]]]* [[INNER]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN5test61AC1Ei([[A]]* {{[^,]*}} [[T0]], i32 noundef 5)
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]], [[A]]* [[T0]], i64 1
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], [[A]]* [[T0]], i64 20
// CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]], ptr [[INNER]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN5test61AC1Ei(ptr {{[^,]*}} [[T0]], i32 noundef 5)
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]], ptr [[T0]], i64 1
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[T0]], i64 20
// CHECK-NEXT: br label
// CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
// CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* {{[^,]*}} [[CUR]])
// CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]], [[A]]* [[CUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]]
// CHECK: [[CUR:%.*]] = phi ptr [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
// CHECK-NEXT: call void @_ZN5test61AC1Ev(ptr {{[^,]*}} [[CUR]])
// CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]], ptr [[CUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[NEXT]], [[END]]
// CHECK-NEXT: br i1

// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]], [20 x [[A]]]* [[INNER]], i64 1
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]], [20 x [[A]]]* [[INNER]], i64 10
// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]], ptr [[INNER]], i64 1
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]], ptr [[INNER]], i64 10
// CHECK-NEXT: br label
// CHECK: [[CUR:%.*]] = phi [20 x [[A]]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
// CHECK: [[CUR:%.*]] = phi ptr [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]

// Inner loop.
// CHECK-NEXT: [[IBEGIN:%.*]] = getelementptr inbounds [20 x [[A]]], [20 x [[A]]]* [[CUR]], i{{32|64}} 0, i{{32|64}} 0
// CHECK-NEXT: [[IEND:%.*]] = getelementptr inbounds [[A]], [[A]]* [[IBEGIN]], i64 20
// CHECK-NEXT: [[IBEGIN:%.*]] = getelementptr inbounds [20 x [[A]]], ptr [[CUR]], i{{32|64}} 0, i{{32|64}} 0
// CHECK-NEXT: [[IEND:%.*]] = getelementptr inbounds [[A]], ptr [[IBEGIN]], i64 20
// CHECK-NEXT: br label
// CHECK: [[ICUR:%.*]] = phi [[A]]* [ [[IBEGIN]], {{%.*}} ], [ [[INEXT:%.*]], {{%.*}} ]
// CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* {{[^,]*}} [[ICUR]])
// CHECK-NEXT: [[INEXT:%.*]] = getelementptr inbounds [[A]], [[A]]* [[ICUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[INEXT]], [[IEND]]
// CHECK: [[ICUR:%.*]] = phi ptr [ [[IBEGIN]], {{%.*}} ], [ [[INEXT:%.*]], {{%.*}} ]
// CHECK-NEXT: call void @_ZN5test61AC1Ev(ptr {{[^,]*}} [[ICUR]])
// CHECK-NEXT: [[INEXT:%.*]] = getelementptr inbounds [[A]], ptr [[ICUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[INEXT]], [[IEND]]
// CHECK-NEXT: br i1 [[T0]],

// CHECK: [[NEXT]] = getelementptr inbounds [20 x [[A]]], [20 x [[A]]]* [[CUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq [20 x [[A]]]* [[NEXT]], [[END]]
// CHECK: [[NEXT]] = getelementptr inbounds [20 x [[A]]], ptr [[CUR]], i64 1
// CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[NEXT]], [[END]]
// CHECK-NEXT: br i1 [[T0]]
// CHECK: ret void
}
Expand All @@ -247,15 +246,15 @@ namespace PR11124 {
struct C : B { C(); };
C::C() : A(3), B() {}
// CHECK-LABEL: define{{.*}} void @_ZN7PR111241CC1Ev
// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 {{.*}}, i8 0, i64 12, i1 false)
// CHECK: call void @llvm.memset.p0.i64(ptr align 8 {{.*}}, i8 0, i64 12, i1 false)
// CHECK-NEXT: call void @_ZN7PR111241BC2Ev
// Make sure C::C doesn't overwrite parts of A while it is zero-initializing B

struct B2 : virtual A { int B::*b; };
struct C2 : B2 { C2(); };
C2::C2() : A(3), B2() {}
// CHECK-LABEL: define{{.*}} void @_ZN7PR111242C2C1Ev
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %{{.*}}, i8* align 8 {{.*}}, i64 16, i1 false)
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{.*}}, ptr align 8 {{.*}}, i64 16, i1 false)
// CHECK-NEXT: call void @_ZN7PR111242B2C2Ev
}

Expand Down Expand Up @@ -326,8 +325,8 @@ int explicitly_defaulted() {
return a.n;
} // CHECK-LABEL: }

// CHECK-LABEL: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* {{[^,]*}} %this) unnamed_addr
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-LABEL: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(ptr {{[^,]*}} %this) unnamed_addr
// CHECK: call void @llvm.memset.p0.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
// CHECK-NEXT: ret void

Expand Down
22 changes: 11 additions & 11 deletions clang/test/CodeGenCXX/vcall-visibility-metadata.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fvirtual-function-elimination -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VFE
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE
// RUN: %clang_cc1 -no-opaque-pointers -flto -flto-unit -triple x86_64-pc-windows-msvc -emit-llvm -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK-MS --check-prefix=CHECK-NOVFE
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fvirtual-function-elimination -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VFE
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -emit-llvm -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -emit-llvm -fwhole-program-vtables -o - %s | FileCheck %s --check-prefix=CHECK-MS --check-prefix=CHECK-NOVFE

// Check that in ThinLTO we also get vcall_visibility summary entries in the bitcode
// RUN: %clang_cc1 -no-opaque-pointers -flto=thin -flto-unit -triple x86_64-unknown-linux -emit-llvm-bc -fwhole-program-vtables -o - %s | llvm-dis -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE --check-prefix=CHECK-SUMMARY
// RUN: %clang_cc1 -flto=thin -flto-unit -triple x86_64-unknown-linux -emit-llvm-bc -fwhole-program-vtables -o - %s | llvm-dis -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOVFE --check-prefix=CHECK-SUMMARY


// Anonymous namespace.
namespace {
// CHECK: @_ZTVN12_GLOBAL__N_11AE = {{.*}} !vcall_visibility [[VIS_TU:![0-9]+]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.(anonymous namespace)::A{{.*}} !vcall_visibility [[VIS_TU:![0-9]+]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4A@?A{{.*}}@@6B@"{{.*}} !vcall_visibility [[VIS_TU:![0-9]+]]
struct A {
A() {}
virtual int f() { return 1; }
Expand All @@ -22,7 +22,7 @@ void *construct_A() {

// Hidden visibility.
// CHECK: @_ZTV1B = {{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.B{{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4B@@6B@"{{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]]
struct __attribute__((visibility("hidden"))) B {
B() {}
virtual int f() { return 1; }
Expand All @@ -35,7 +35,7 @@ B *construct_B() {
// Default visibility.
// CHECK-NOT: @_ZTV1C = {{.*}} !vcall_visibility
// On MS default is hidden
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.C{{.*}} !vcall_visibility [[VIS_DSO]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4C@@6B@"{{.*}} !vcall_visibility [[VIS_DSO]]
struct __attribute__((visibility("default"))) C {
C() {}
virtual int f() { return 1; }
Expand All @@ -47,7 +47,7 @@ C *construct_C() {

// Hidden visibility, public LTO visibility.
// CHECK-NOT: @_ZTV1D = {{.*}} !vcall_visibility
// CHECK-MS-NOT: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.D{{.*}} !vcall_visibility
// CHECK-MS-NOT: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4D@@6B@"{{.*}} !vcall_visibility
struct __attribute__((visibility("hidden"))) [[clang::lto_visibility_public]] D {
D() {}
virtual int f() { return 1; }
Expand All @@ -60,7 +60,7 @@ D *construct_D() {
// Hidden visibility, but inherits from class with default visibility.
// CHECK-NOT: @_ZTV1E = {{.*}} !vcall_visibility
// On MS default is hidden
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.E{{.*}} !vcall_visibility [[VIS_DSO]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4E@@6B@"{{.*}} !vcall_visibility [[VIS_DSO]]
struct __attribute__((visibility("hidden"))) E : C {
E() {}
virtual int f() { return 1; }
Expand All @@ -73,7 +73,7 @@ E *construct_E() {
// Anonymous namespace, but inherits from class with default visibility.
// CHECK-NOT: @_ZTVN12_GLOBAL__N_11FE = {{.*}} !vcall_visibility
// On MS default is hidden
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.(anonymous namespace)::F{{.*}} !vcall_visibility [[VIS_DSO]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4F@?A{{.*}}@@6B@"{{.*}} !vcall_visibility [[VIS_DSO]]
namespace {
struct __attribute__((visibility("hidden"))) F : C {
F() {}
Expand All @@ -87,7 +87,7 @@ void *construct_F() {

// Anonymous namespace, but inherits from class with hidden visibility.
// CHECK: @_ZTVN12_GLOBAL__N_11GE = {{.*}} !vcall_visibility [[VIS_DSO:![0-9]+]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}struct.(anonymous namespace)::G{{.*}} !vcall_visibility [[VIS_DSO]]
// CHECK-MS: @anon.{{.*}} = private unnamed_addr constant {{.*}}@"??_R4G@?A{{.*}}@@6B@"{{.*}} !vcall_visibility [[VIS_DSO]]
namespace {
struct __attribute__((visibility("hidden"))) G : B {
G() {}
Expand Down
40 changes: 20 additions & 20 deletions clang/test/CodeGenCXX/virtual-bases.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s

struct A {
A();
};

// CHECK: @_ZN1AC1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1AC2Ev
// CHECK-LABEL: define{{.*}} void @_ZN1AC2Ev(%struct.A* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1AC2Ev(ptr {{[^,]*}} %this) unnamed_addr
A::A() { }

struct B : virtual A {
B();
};

// CHECK-LABEL: define{{.*}} void @_ZN1BC2Ev(%struct.B* {{[^,]*}} %this, i8** noundef %vtt) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1BC1Ev(%struct.B* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1BC2Ev(ptr {{[^,]*}} %this, ptr noundef %vtt) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1BC1Ev(ptr {{[^,]*}} %this) unnamed_addr
B::B() { }

struct C : virtual A {
C(bool);
};

// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(%struct.C* {{[^,]*}} %this, i8** noundef %vtt, i1 noundef zeroext %0) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(%struct.C* {{[^,]*}} %this, i1 noundef zeroext %0) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(ptr {{[^,]*}} %this, ptr noundef %vtt, i1 noundef zeroext %0) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(ptr {{[^,]*}} %this, i1 noundef zeroext %0) unnamed_addr
C::C(bool) { }

// PR6251
Expand All @@ -39,7 +39,7 @@ struct D : B, C {
D();
};

// CHECK-LABEL: define{{.*}} void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN6PR62511DC1Ev(ptr {{[^,]*}} %this) unnamed_addr
// CHECK: call void @_ZN6PR62511AIcEC2Ev
// CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev
// CHECK: ret void
Expand All @@ -51,19 +51,19 @@ namespace virtualBaseAlignment {

// Check that the store to B::x in the base constructor has an 8-byte alignment.

// CHECK: define linkonce_odr void @_ZN20virtualBaseAlignment1BC1Ev(%[[STRUCT_B:.*]]* {{[^,]*}} %[[THIS:.*]])
// CHECK: %[[THIS_ADDR:.*]] = alloca %[[STRUCT_B]]*, align 8
// CHECK: store %[[STRUCT_B]]* %[[THIS]], %[[STRUCT_B]]** %[[THIS_ADDR]], align 8
// CHECK: %[[THIS1:.*]] = load %[[STRUCT_B]]*, %[[STRUCT_B]]** %[[THIS_ADDR]], align 8
// CHECK: %[[X:.*]] = getelementptr inbounds %[[STRUCT_B]], %[[STRUCT_B]]* %[[THIS1]], i32 0, i32 2
// CHECK: store i32 123, i32* %[[X]], align 16

// CHECK: define linkonce_odr void @_ZN20virtualBaseAlignment1BC2Ev(%[[STRUCT_B]]* {{[^,]*}} %[[THIS:.*]], i8** noundef %{{.*}})
// CHECK: %[[THIS_ADDR:.*]] = alloca %[[STRUCT_B]]*, align 8
// CHECK: store %[[STRUCT_B]]* %[[THIS]], %[[STRUCT_B]]** %[[THIS_ADDR]], align 8
// CHECK: %[[THIS1:.*]] = load %[[STRUCT_B]]*, %[[STRUCT_B]]** %[[THIS_ADDR]], align 8
// CHECK: %[[X:.*]] = getelementptr inbounds %[[STRUCT_B]], %[[STRUCT_B]]* %[[THIS1]], i32 0, i32 2
// CHECK: store i32 123, i32* %[[X]], align 8
// CHECK: define linkonce_odr void @_ZN20virtualBaseAlignment1BC1Ev(ptr {{[^,]*}} %[[THIS:.*]])
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8
// CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8
// CHECK: %[[X:.*]] = getelementptr inbounds %[[STRUCT_B:.*]], ptr %[[THIS1]], i32 0, i32 2
// CHECK: store i32 123, ptr %[[X]], align 16

// CHECK: define linkonce_odr void @_ZN20virtualBaseAlignment1BC2Ev(ptr {{[^,]*}} %[[THIS:.*]], ptr noundef %{{.*}})
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8
// CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8
// CHECK: %[[X:.*]] = getelementptr inbounds %[[STRUCT_B]], ptr %[[THIS1]], i32 0, i32 2
// CHECK: store i32 123, ptr %[[X]], align 8

struct A {
__attribute__((aligned(16))) double data1;
Expand Down
10 changes: 5 additions & 5 deletions clang/test/CodeGenCXX/virtual-destructor-calls.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases -O1 -disable-llvm-passes | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases -O1 -disable-llvm-passes | FileCheck %s

struct Member {
~Member();
Expand All @@ -17,16 +17,16 @@ struct B : A {
// CHECK: @_ZN1BD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev

// (aliases from C)
// CHECK: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}}, bitcast {{.*}} @_ZN1BD2Ev
// CHECK: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev
// CHECK: @_ZN1CD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1CD2Ev

// Base dtor: actually calls A's base dtor.
// CHECK-LABEL: define{{.*}} void @_ZN1BD2Ev(%struct.B* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1BD2Ev(ptr {{[^,]*}} %this) unnamed_addr
// CHECK: call void @_ZN6MemberD1Ev
// CHECK: call void @_ZN1AD2Ev

// Deleting dtor: defers to the complete dtor.
// CHECK-LABEL: define{{.*}} void @_ZN1BD0Ev(%struct.B* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1BD0Ev(ptr {{[^,]*}} %this) unnamed_addr
// CHECK: call void @_ZN1BD1Ev
// CHECK: call void @_ZdlPv

Expand All @@ -41,7 +41,7 @@ C::~C() { }
// Complete dtor: just an alias (checked above).

// Deleting dtor: defers to the complete dtor.
// CHECK-LABEL: define{{.*}} void @_ZN1CD0Ev(%struct.C* {{[^,]*}} %this) unnamed_addr
// CHECK-LABEL: define{{.*}} void @_ZN1CD0Ev(ptr {{[^,]*}} %this) unnamed_addr
// CHECK: call void @_ZN1CD1Ev
// CHECK: call void @_ZdlPv

Expand Down
54 changes: 26 additions & 28 deletions clang/test/CodeGenCXX/virtual-function-elimination.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux -flto -flto-unit -fvirtual-function-elimination -fwhole-program-vtables -emit-llvm -o - %s | FileCheck %s
// RUN: %clang -Xclang -no-opaque-pointers -target x86_64-unknown-linux -flto -fvirtual-function-elimination -fno-virtual-function-elimination -fwhole-program-vtables -S -emit-llvm -o - %s | FileCheck %s -check-prefix=NOVFE
// RUN: %clang_cc1 -triple x86_64-unknown-linux -flto -flto-unit -fvirtual-function-elimination -fwhole-program-vtables -emit-llvm -o - %s | FileCheck %s
// RUN: %clang -target x86_64-unknown-linux -flto -fvirtual-function-elimination -fno-virtual-function-elimination -fwhole-program-vtables -S -emit-llvm -o - %s | FileCheck %s -check-prefix=NOVFE

struct __attribute__((visibility("default"))) A {
virtual void foo();
Expand All @@ -9,10 +9,10 @@ void test_1(A *p) {
// A has default visibility, so no need for type.checked.load.
// CHECK-LABEL: define{{.*}} void @_Z6test_1P1A
// NOVFE-LABEL: define dso_local void @_Z6test_1P1A
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds void (%struct.A*)*, void (%struct.A*)** {{%.+}}, i64 0
// NOVFE: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds void (%struct.A*)*, void (%struct.A*)** {{%.+}}, i64 0
// CHECK: [[FN_PTR:%.+]] = load void (%struct.A*)*, void (%struct.A*)** [[FN_PTR_ADDR]]
// NOVFE: [[FN_PTR:%.+]] = load void (%struct.A*)*, void (%struct.A*)** [[FN_PTR_ADDR]]
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds ptr, ptr {{%.+}}, i64 0
// NOVFE: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds ptr, ptr {{%.+}}, i64 0
// CHECK: [[FN_PTR:%.+]] = load ptr, ptr [[FN_PTR_ADDR]]
// NOVFE: [[FN_PTR:%.+]] = load ptr, ptr [[FN_PTR_ADDR]]
// CHECK: call void [[FN_PTR]](
// NOVFE: call void [[FN_PTR]](
p->foo();
Expand All @@ -27,10 +27,10 @@ void test_2(B *p) {
// B has public LTO visibility, so no need for type.checked.load.
// CHECK-LABEL: define{{.*}} void @_Z6test_2P1B
// NOVFE-LABEL: define dso_local void @_Z6test_2P1B
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds void (%struct.B*)*, void (%struct.B*)** {{%.+}}, i64 0
// NOVFE: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds void (%struct.B*)*, void (%struct.B*)** {{%.+}}, i64 0
// CHECK: [[FN_PTR:%.+]] = load void (%struct.B*)*, void (%struct.B*)** [[FN_PTR_ADDR]]
// NOVFE: [[FN_PTR:%.+]] = load void (%struct.B*)*, void (%struct.B*)** [[FN_PTR_ADDR]]
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds ptr, ptr {{%.+}}, i64 0
// NOVFE: [[FN_PTR_ADDR:%.+]] = getelementptr inbounds ptr, ptr {{%.+}}, i64 0
// CHECK: [[FN_PTR:%.+]] = load ptr, ptr [[FN_PTR_ADDR]]
// NOVFE: [[FN_PTR:%.+]] = load ptr, ptr [[FN_PTR_ADDR]]
// CHECK: call void [[FN_PTR]](
// NOVFE: call void [[FN_PTR]](
p->foo();
Expand All @@ -46,11 +46,10 @@ void test_3(C *p) {
// C has hidden visibility, so we generate type.checked.load to allow VFE.
// CHECK-LABEL: define{{.*}} void @_Z6test_3P1C
// NOVFE-LABEL: define dso_local void @_Z6test_3P1C
// CHECK: [[LOAD:%.+]] = call { i8*, i1 } @llvm.type.checked.load(i8* {{%.+}}, i32 0, metadata !"_ZTS1C")
// NOVFE: call i1 @llvm.type.test(i8* {{%.+}}, metadata !"_ZTS1C")
// CHECK: [[FN_PTR_I8:%.+]] = extractvalue { i8*, i1 } [[LOAD]], 0
// NOVFE: [[FN_PTR:%.+]] = load void (%struct.C*)*, void (%struct.C*)** {{%.+}}, align 8
// CHECK: [[FN_PTR:%.+]] = bitcast i8* [[FN_PTR_I8]] to void (%struct.C*)*
// CHECK: [[LOAD:%.+]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%.+}}, i32 0, metadata !"_ZTS1C")
// NOVFE: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTS1C")
// CHECK: [[FN_PTR:%.+]] = extractvalue { ptr, i1 } [[LOAD]], 0
// NOVFE: [[FN_PTR:%.+]] = load ptr, ptr {{%.+}}, align 8
// CHECK: call void [[FN_PTR]](
// NOVFE: call void [[FN_PTR]](
p->foo();
Expand All @@ -61,11 +60,10 @@ void test_4(C *p) {
// rather than adding it to the pointer with a GEP.
// CHECK-LABEL: define{{.*}} void @_Z6test_4P1C
// NOVFE-LABEL: define dso_local void @_Z6test_4P1C
// CHECK: [[LOAD:%.+]] = call { i8*, i1 } @llvm.type.checked.load(i8* {{%.+}}, i32 8, metadata !"_ZTS1C")
// NOVFE: call i1 @llvm.type.test(i8* {{%.+}}, metadata !"_ZTS1C")
// CHECK: [[FN_PTR_I8:%.+]] = extractvalue { i8*, i1 } [[LOAD]], 0
// NOVFE: [[FN_PTR:%.+]] = load void (%struct.C*)*, void (%struct.C*)** {{%.+}}, align 8
// CHECK: [[FN_PTR:%.+]] = bitcast i8* [[FN_PTR_I8]] to void (%struct.C*)*
// CHECK: [[LOAD:%.+]] = call { ptr, i1 } @llvm.type.checked.load(ptr {{%.+}}, i32 8, metadata !"_ZTS1C")
// NOVFE: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTS1C")
// CHECK: [[FN_PTR:%.+]] = extractvalue { ptr, i1 } [[LOAD]], 0
// NOVFE: [[FN_PTR:%.+]] = load ptr, ptr {{%.+}}, align 8
// CHECK: call void [[FN_PTR]](
// NOVFE: call void [[FN_PTR]](
p->bar();
Expand All @@ -81,15 +79,15 @@ void test_5(C *p, void (C::*q)(void)) {
// codegen changes on the non-virtual side.
// CHECK-LABEL: define{{.*}} void @_Z6test_5P1CMS_FvvE(
// NOVFE-LABEL: define dso_local void @_Z6test_5P1CMS_FvvE(
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr i8, i8* %vtable, i64 {{%.+}}
// CHECK: [[LOAD:%.+]] = call { i8*, i1 } @llvm.type.checked.load(i8* [[FN_PTR_ADDR]], i32 0, metadata !"_ZTSM1CFvvE.virtual")
// NOVFE-NOT: call { i8*, i1 } @llvm.type.checked.load(i8* {{%.+}}, i32 0, metadata !"_ZTSM1CFvvE.virtual")
// CHECK: [[FN_PTR_I8:%.+]] = extractvalue { i8*, i1 } [[LOAD]], 0
// CHECK: [[FN_PTR:%.+]] = bitcast i8* [[FN_PTR_I8]] to void (%struct.C*)*
// NOVFE: [[FN_PTR:%.+]] = load void (%struct.C*)*, void (%struct.C*)** {{%.+}}, align 8
// CHECK: [[FN_PTR_ADDR:%.+]] = getelementptr i8, ptr %vtable, i64 {{%.+}}
// CHECK: [[LOAD:%.+]] = call { ptr, i1 } @llvm.type.checked.load(ptr [[FN_PTR_ADDR]], i32 0, metadata !"_ZTSM1CFvvE.virtual")
// NOVFE-NOT: call { ptr, i1 } @llvm.type.checked.load(ptr {{%.+}}, i32 0, metadata !"_ZTSM1CFvvE.virtual")
// NOVFE: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSM1CFvvE.virtual")
// CHECK: [[FN_PTR:%.+]] = extractvalue { ptr, i1 } [[LOAD]], 0
// NOVFE: [[FN_PTR:%.+]] = load ptr, ptr {{%.+}}, align 8

// CHECK: [[PHI:%.+]] = phi void (%struct.C*)* {{.*}}[ [[FN_PTR]], {{.*}} ]
// NOVFE: [[PHI:%.+]] = phi void (%struct.C*)* {{.*}}[ [[FN_PTR]], {{.*}} ]
// CHECK: [[PHI:%.+]] = phi ptr [ [[FN_PTR]], {{.*}} ]
// NOVFE: [[PHI:%.+]] = phi ptr [ [[FN_PTR]], {{.*}} ]
// CHECK: call void [[PHI]](
// NOVFE: call void [[PHI]](
(p->*q)();
Expand Down
Loading