; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -passes="fatlto-cleanup" < %s -S | FileCheck %s declare void @llvm.ubsantrap(i8 immarg) declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata) declare { ptr, i1 } @llvm.type.checked.load.relative(ptr, i32, metadata) define hidden void @foo(ptr %p1) { ; CHECK-LABEL: define hidden void @foo( ; CHECK-SAME: ptr [[P1:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[P1]], align 8 ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[VTABLE]], i32 0 ; CHECK-NEXT: [[VFUNC:%.*]] = load ptr, ptr [[TMP0]], align 8 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr, i1 } { ptr poison, i1 true }, ptr [[VFUNC]], 0 ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i1 } [[TMP2]], 1 ; CHECK-NEXT: br i1 [[TMP3]], label %[[CONT2:.*]], label %[[TRAP1:.*]] ; CHECK: [[TRAP1]]: ; CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) ; CHECK-NEXT: unreachable ; CHECK: [[CONT2]]: ; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i1 } [[TMP2]], 0 ; CHECK-NEXT: [[CALL:%.*]] = tail call noundef i64 [[TMP4]](ptr noundef nonnull align 8 dereferenceable(8) [[P1]]) ; CHECK-NEXT: ret void ; entry: %vtable = load ptr, ptr %p1, align 8 %0 = tail call { ptr, i1 } @llvm.type.checked.load(ptr %vtable, i32 0, metadata !"_ZTS1a") %1 = extractvalue { ptr, i1 } %0, 1 br i1 %1, label %cont2, label %trap1 trap1: tail call void @llvm.ubsantrap(i8 2) unreachable cont2: %2 = extractvalue { ptr, i1 } %0, 0 %call = tail call noundef i64 %2(ptr noundef nonnull align 8 dereferenceable(8) %p1) ret void } define hidden void @relative.vtable(ptr %p1) { ; CHECK-LABEL: define hidden void @relative.vtable( ; CHECK-SAME: ptr [[P1:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[P1]], align 8 ; CHECK-NEXT: [[REL_LOAD:%.*]] = call ptr @llvm.load.relative.i32(ptr [[VTABLE]], i32 0) ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr, i1 } { ptr poison, i1 true }, ptr [[REL_LOAD]], 0 ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i1 } [[TMP2]], 1 ; CHECK-NEXT: br i1 [[TMP3]], label %[[CONT2:.*]], label %[[TRAP1:.*]] ; CHECK: [[TRAP1]]: ; CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) ; CHECK-NEXT: unreachable ; CHECK: [[CONT2]]: ; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i1 } [[TMP2]], 0 ; CHECK-NEXT: [[CALL:%.*]] = tail call noundef i64 [[TMP4]](ptr noundef nonnull align 8 dereferenceable(8) [[P1]]) ; CHECK-NEXT: ret void ; entry: %vtable = load ptr, ptr %p1, align 8 %0 = tail call { ptr, i1 } @llvm.type.checked.load.relative(ptr %vtable, i32 0, metadata !"rel.vtable.type") %1 = extractvalue { ptr, i1 } %0, 1 br i1 %1, label %cont2, label %trap1 trap1: tail call void @llvm.ubsantrap(i8 2) unreachable cont2: %2 = extractvalue { ptr, i1 } %0, 0 %call = tail call noundef i64 %2(ptr noundef nonnull align 8 dereferenceable(8) %p1) ret void }