blob: 5c3bd17ab909c09a5c0def1cf6486d4f74fba872 [file] [log] [blame]
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --include-generated-funcs --version 6
// with MERGE/NO-MERGE assertions added manually.
// N.B. although the clang driver defaults to merge, clang_cc1 defaults to non-merge.
// (This is similar to -fsanitize-recover, for which the default is also applied
// at the driver level only.)
// If optimization is disabled, merging is disabled (overrides -fsanitize-merge).
// RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux -fsanitize=cfi-mfcall -fsanitize-trap=cfi-mfcall -fvisibility=hidden -emit-llvm -o - %s | FileCheck %s --check-prefixes=NO-MERGE
// RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux -fsanitize-merge=cfi-mfcall -fsanitize=cfi-mfcall -fsanitize-trap=cfi-mfcall -fvisibility=hidden -emit-llvm -o - %s | FileCheck %s --check-prefixes=MERGE
struct B1 {};
struct B2 {};
struct B3 : B2 {};
struct S : B1, B3 {};
void f(S *s, void (S::*p)()) {
(s->*p)();
(s->*p)();
(s->*p)();
}
// NO-MERGE-LABEL: define hidden void @_Z1fP1SMS_FvvE(
// NO-MERGE-SAME: ptr noundef [[S:%.*]], i64 [[P_COERCE0:%.*]], i64 [[P_COERCE1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// NO-MERGE-NEXT: [[ENTRY:.*:]]
// NO-MERGE-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[P_COERCE1]]
// NO-MERGE-NEXT: [[TMP1:%.*]] = and i64 [[P_COERCE0]], 1
// NO-MERGE-NEXT: [[MEMPTR_ISVIRTUAL_NOT:%.*]] = icmp eq i64 [[TMP1]], 0
// NO-MERGE-NEXT: br i1 [[MEMPTR_ISVIRTUAL_NOT]], label %[[MEMPTR_NONVIRTUAL:.*]], label %[[MEMPTR_VIRTUAL:.*]]
// NO-MERGE: [[MEMPTR_VIRTUAL]]:
// NO-MERGE-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6:![0-9]+]]
// NO-MERGE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[VTABLE]], i64 [[P_COERCE0]]
// NO-MERGE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -1
// NO-MERGE-NEXT: [[TMP4:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP3]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8:![0-9]+]]
// NO-MERGE-NEXT: br i1 [[TMP4]], label %[[MEMPTR_VIRTUAL7:.*]], label %[[TRAP:.*]], !prof [[PROF9:![0-9]+]], !nosanitize [[META8]]
// NO-MERGE: [[TRAP]]:
// NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !nosanitize [[META8]]
// NO-MERGE-NEXT: unreachable, !nosanitize [[META8]]
// NO-MERGE: [[MEMPTR_NONVIRTUAL]]:
// NO-MERGE-NEXT: [[MEMPTR_NONVIRTUALFN:%.*]] = inttoptr i64 [[P_COERCE0]] to ptr
// NO-MERGE-NEXT: [[TMP5:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B1FvvE"), !nosanitize [[META8]]
// NO-MERGE-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B2FvvE"), !nosanitize [[META8]]
// NO-MERGE-NEXT: [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]], !nosanitize [[META8]]
// NO-MERGE-NEXT: br i1 [[TMP7]], label %[[MEMPTR_NONVIRTUAL23:.*]], label %[[TRAP2:.*]], !prof [[PROF9]], !nosanitize [[META8]]
// NO-MERGE: [[TRAP2]]:
// NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !nosanitize [[META8]]
// NO-MERGE-NEXT: unreachable, !nosanitize [[META8]]
// NO-MERGE: [[MEMPTR_VIRTUAL7]]:
// NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[TMP3]], align 8, !nosanitize [[META8]]
// NO-MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5:[0-9]+]]
// NO-MERGE-NEXT: [[VTABLE8:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6]]
// NO-MERGE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[VTABLE8]], i64 [[P_COERCE0]]
// NO-MERGE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP8]], i64 -1
// NO-MERGE-NEXT: [[TMP10:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP9]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8]]
// NO-MERGE-NEXT: br i1 [[TMP10]], label %[[MEMPTR_VIRTUAL19:.*]], label %[[TRAP2]], !prof [[PROF9]], !nosanitize [[META8]]
// NO-MERGE: [[TRAP13:.*]]:
// NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META8]]
// NO-MERGE-NEXT: unreachable, !nosanitize [[META8]]
// NO-MERGE: [[MEMPTR_VIRTUAL19]]:
// NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN9:%.*]] = load ptr, ptr [[TMP9]], align 8, !nosanitize [[META8]]
// NO-MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN9]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]]
// NO-MERGE-NEXT: [[VTABLE20:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6]]
// NO-MERGE-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[VTABLE20]], i64 [[P_COERCE0]]
// NO-MERGE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP11]], i64 -1
// NO-MERGE-NEXT: [[TMP13:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP12]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8]]
// NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN21:%.*]] = load ptr, ptr [[TMP12]], align 8, !nosanitize [[META8]]
// NO-MERGE-NEXT: br i1 [[TMP13]], label %[[MEMPTR_END27:.*]], label %[[TRAP13]], !prof [[PROF9]], !nosanitize [[META8]]
// NO-MERGE: [[MEMPTR_NONVIRTUAL23]]:
// NO-MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]]
// NO-MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]]
// NO-MERGE-NEXT: br label %[[MEMPTR_END27]]
// NO-MERGE: [[MEMPTR_END27]]:
// NO-MERGE-NEXT: [[TMP14:%.*]] = phi ptr [ [[MEMPTR_VIRTUALFN21]], %[[MEMPTR_VIRTUAL19]] ], [ [[MEMPTR_NONVIRTUALFN]], %[[MEMPTR_NONVIRTUAL23]] ]
// NO-MERGE-NEXT: tail call void [[TMP14]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]]
// NO-MERGE-NEXT: ret void
//
//
// MERGE-LABEL: define hidden void @_Z1fP1SMS_FvvE(
// MERGE-SAME: ptr noundef [[S:%.*]], i64 [[P_COERCE0:%.*]], i64 [[P_COERCE1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// MERGE-NEXT: [[ENTRY:.*:]]
// MERGE-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[P_COERCE1]]
// MERGE-NEXT: [[TMP1:%.*]] = and i64 [[P_COERCE0]], 1
// MERGE-NEXT: [[MEMPTR_ISVIRTUAL_NOT:%.*]] = icmp eq i64 [[TMP1]], 0
// MERGE-NEXT: br i1 [[MEMPTR_ISVIRTUAL_NOT]], label %[[MEMPTR_NONVIRTUAL:.*]], label %[[MEMPTR_VIRTUAL:.*]]
// MERGE: [[MEMPTR_VIRTUAL]]:
// MERGE-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6:![0-9]+]]
// MERGE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[VTABLE]], i64 [[P_COERCE0]]
// MERGE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -1
// MERGE-NEXT: [[TMP4:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP3]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8:![0-9]+]]
// MERGE-NEXT: br i1 [[TMP4]], label %[[MEMPTR_VIRTUAL6:.*]], label %[[TRAP:.*]], !prof [[PROF9:![0-9]+]], !nosanitize [[META8]]
// MERGE: [[TRAP]]:
// MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !nosanitize [[META8]]
// MERGE-NEXT: unreachable, !nosanitize [[META8]]
// MERGE: [[MEMPTR_NONVIRTUAL]]:
// MERGE-NEXT: [[MEMPTR_NONVIRTUALFN:%.*]] = inttoptr i64 [[P_COERCE0]] to ptr
// MERGE-NEXT: [[TMP5:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B1FvvE"), !nosanitize [[META8]]
// MERGE-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B2FvvE"), !nosanitize [[META8]]
// MERGE-NEXT: [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]], !nosanitize [[META8]]
// MERGE-NEXT: br i1 [[TMP7]], label %[[MEMPTR_NONVIRTUAL21:.*]], label %[[TRAP]], !prof [[PROF9]], !nosanitize [[META8]]
// MERGE: [[MEMPTR_VIRTUAL6]]:
// MERGE-NEXT: [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[TMP3]], align 8, !nosanitize [[META8]]
// MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4:[0-9]+]]
// MERGE-NEXT: [[VTABLE7:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6]]
// MERGE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[VTABLE7]], i64 [[P_COERCE0]]
// MERGE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP8]], i64 -1
// MERGE-NEXT: [[TMP10:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP9]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8]]
// MERGE-NEXT: br i1 [[TMP10]], label %[[MEMPTR_VIRTUAL17:.*]], label %[[TRAP]], !prof [[PROF9]], !nosanitize [[META8]]
// MERGE: [[MEMPTR_VIRTUAL17]]:
// MERGE-NEXT: [[MEMPTR_VIRTUALFN8:%.*]] = load ptr, ptr [[TMP9]], align 8, !nosanitize [[META8]]
// MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN8]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]]
// MERGE-NEXT: [[VTABLE18:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[VTABLE_POINTER_TBAA6]]
// MERGE-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[VTABLE18]], i64 [[P_COERCE0]]
// MERGE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP11]], i64 -1
// MERGE-NEXT: [[TMP13:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP12]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META8]]
// MERGE-NEXT: [[MEMPTR_VIRTUALFN19:%.*]] = load ptr, ptr [[TMP12]], align 8, !nosanitize [[META8]]
// MERGE-NEXT: br i1 [[TMP13]], label %[[MEMPTR_END24:.*]], label %[[TRAP]], !prof [[PROF9]], !nosanitize [[META8]]
// MERGE: [[MEMPTR_NONVIRTUAL21]]:
// MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]]
// MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]]
// MERGE-NEXT: br label %[[MEMPTR_END24]]
// MERGE: [[MEMPTR_END24]]:
// MERGE-NEXT: [[TMP14:%.*]] = phi ptr [ [[MEMPTR_VIRTUALFN19]], %[[MEMPTR_VIRTUAL17]] ], [ [[MEMPTR_NONVIRTUALFN]], %[[MEMPTR_NONVIRTUAL21]] ]
// MERGE-NEXT: tail call void [[TMP14]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]]
// MERGE-NEXT: ret void
//
//.
// NO-MERGE: [[META5:![0-9]+]] = !{!"Simple C++ TBAA"}
// NO-MERGE: [[VTABLE_POINTER_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
// NO-MERGE: [[META7]] = !{!"vtable pointer", [[META5]], i64 0}
// NO-MERGE: [[META8]] = !{}
// NO-MERGE: [[PROF9]] = !{!"branch_weights", i32 1048575, i32 1}
//.
// MERGE: [[META5:![0-9]+]] = !{!"Simple C++ TBAA"}
// MERGE: [[VTABLE_POINTER_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
// MERGE: [[META7]] = !{!"vtable pointer", [[META5]], i64 0}
// MERGE: [[META8]] = !{}
// MERGE: [[PROF9]] = !{!"branch_weights", i32 1048575, i32 1}
//.