[llvm] [NFC][WPD] Add constant propagation tests checking relative vtables (PR #138989)
Paul Kirth via llvm-commits
llvm-commits at lists.llvm.org
Wed May 7 18:02:06 PDT 2025
================
@@ -0,0 +1,284 @@
+; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
+
+;; This target uses 32-bit sized and aligned pointers.
+target datalayout = "e-p:32:32"
+
+;; Constant propagation should be agnostic towards sections.
+;; Also the new global should be in the original vtable's section.
+; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\01\00\00\00\03\00", [3 x ptr] [ptr @vf0i1, ptr @vf1i8, ptr @vf1i32], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
+ at vt1 = constant [3 x ptr] [
+ptr @vf0i1,
+ptr @vf1i8,
+ptr @vf1i32
+], section "vt1sec", !type !0
+
+;; This represents a normal vtable using the default ABI alignments.
+;; For this test, the pointers are 32-bit aligned.
+; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\02\00\00\00\02\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i8, ptr @vf2i32], [0 x i8] zeroinitializer }, !type [[T8]]
+ at vt2 = constant [3 x ptr] [
+ptr @vf1i1,
+ptr @vf0i8,
+ptr @vf2i32
+], !type !0
+
+;; This represents an underaligned vtable.
+;;
+;; All the functions returning i8s and i1s should still be constant-propagated
+;; because we can still do an aligned load regardless of where the 1-byte aligned
+;; vtable is.
+; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [6 x i8], [3 x ptr], [0 x i8] } { [6 x i8] c"\03\00\00\00\03\00", [3 x ptr] [ptr @vf0i1, ptr @vf1i8, ptr @vf3i32], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]]
+ at vt3 = constant [3 x ptr] [
+ptr @vf0i1,
+ptr @vf1i8,
+ptr @vf3i32
+], align 1, !type !0
+
+;; This represents an overaligned vtable.
+; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x ptr], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\04\00\00\00\02\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i8, ptr @vf4i32], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]]
+ at vt4 = constant [3 x ptr] [
+ptr @vf1i1,
+ptr @vf0i8,
+ptr @vf4i32
+], align 16, !type !0
+
+;; These contain a mix of different integral type sizes.
+; CHECK: [[VT6DATA:@[^ ]*]] = private constant { [12 x i8], [3 x ptr], [0 x i8] } { [12 x i8] c"\00\00\00\0B\05\00\00\00\00\00\00\00", [3 x ptr] [ptr @vf0i1, ptr @vf10i8, ptr @vf5i64], [0 x i8] zeroinitializer }, !type [[T1:![0-9]+]]
+ at vt6 = constant [3 x ptr] [
+ptr @vf0i1,
+ptr @vf10i8,
+ptr @vf5i64
+], !type !1
+
+; CHECK: [[VT7DATA:@[^ ]*]] = private constant { [12 x i8], [3 x ptr], [0 x i8] } { [12 x i8] c"\00\00\00\0A\06\00\00\00\00\00\00\00", [3 x ptr] [ptr @vf1i1, ptr @vf9i8, ptr @vf6i64], [0 x i8] zeroinitializer }, !type [[T1]]
+ at vt7 = constant [3 x ptr] [
+ptr @vf1i1,
+ptr @vf9i8,
+ptr @vf6i64
+], !type !1
+
+;; Test relative vtables
+; CHECK: [[VT6RELDATA:@[^ ]*]] = private constant { [12 x i8], [3 x i32], [0 x i8] } { [12 x i8] c"\00\00\00\0B\05\00\00\00\00\00\00\00", [3 x i32] [
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf10i8 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf5i64 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
+; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL:![0-9]+]]
+ at vt6_rel = constant [3 x i32] [
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf10i8 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf5i64 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
+], !type !2
+
+; CHECK: [[VT7RELDATA:@[^ ]*]] = private constant { [12 x i8], [3 x i32], [0 x i8] } { [12 x i8] c"\00\00\00\0A\06\00\00\00\00\00\00\00", [3 x i32] [
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf9i8 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
+; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf6i64 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
+; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL]]
+ at vt7_rel = constant [3 x i32] [
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf9i8 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
+i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf6i64 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
+], !type !2
+
+; CHECK: @vt1 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT1DATA]], i32 0, i32 1)
+; CHECK: @vt2 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT2DATA]], i32 0, i32 1)
+; CHECK: @vt3 = alias [3 x ptr], getelementptr inbounds ({ [6 x i8], [3 x ptr], [0 x i8] }, ptr [[VT3DATA]], i32 0, i32 1)
+; CHECK: @vt4 = alias [3 x ptr], getelementptr inbounds ({ [16 x i8], [3 x ptr], [0 x i8] }, ptr [[VT4DATA]], i32 0, i32 1)
+; CHECK: @vt6 = alias [3 x ptr], getelementptr inbounds ({ [12 x i8], [3 x ptr], [0 x i8] }, ptr [[VT6DATA]], i32 0, i32 1)
+; CHECK: @vt7 = alias [3 x ptr], getelementptr inbounds ({ [12 x i8], [3 x ptr], [0 x i8] }, ptr [[VT7DATA]], i32 0, i32 1)
+; CHECK: @vt6_rel = alias [3 x i32], getelementptr inbounds ({ [12 x i8], [3 x i32], [0 x i8] }, ptr [[VT6RELDATA]], i32 0, i32 1)
+; CHECK: @vt7_rel = alias [3 x i32], getelementptr inbounds ({ [12 x i8], [3 x i32], [0 x i8] }, ptr [[VT7RELDATA]], i32 0, i32 1)
+
+define i1 @vf0i1(ptr %this) readnone {
+ ret i1 0
+}
+
+define i1 @vf1i1(ptr %this) readnone {
+ ret i1 1
+}
+
+define i8 @vf0i8(ptr %this) readnone {
+ ret i8 2
+}
+
+define i8 @vf1i8(ptr %this) readnone {
+ ret i8 3
+}
+
+define i32 @vf1i32(ptr %this) readnone {
+ ret i32 1
+}
+
+define i32 @vf2i32(ptr %this) readnone {
+ ret i32 2
+}
+
+define i32 @vf3i32(ptr %this) readnone {
+ ret i32 3
+}
+
+define i32 @vf4i32(ptr %this) readnone {
+ ret i32 4
+}
+
+define i64 @vf5i64(ptr %this) readnone {
+ ret i64 5
+}
+
+define i64 @vf6i64(ptr %this) readnone {
+ ret i64 6
+}
+
+define i16 @vf7i16(ptr %this) readnone {
+ ret i16 7
+}
+
+define i16 @vf8i16(ptr %this) readnone {
+ ret i16 8
+}
+
+define i8 @vf9i8(ptr %this) readnone {
+ ret i8 10
+}
+
+define i8 @vf10i8(ptr %this) readnone {
+ ret i8 11
+}
+
+; CHECK: define i1 @call1(
+define i1 @call1(ptr %obj) {
+ %vtable = load ptr, ptr %obj
+ %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
+ call void @llvm.assume(i1 %p)
+ %fptr = load ptr, ptr %vtable
+ ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -1
+ ; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, ptr [[VTGEP1]]
+ ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1
+ ; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0
+ %result = call i1 %fptr(ptr %obj)
+ ; CHECK: ret i1 [[VTCMP1]]
+ ret i1 %result
+}
+
+; CHECK: define i8 @call2(
+define i8 @call2(ptr %obj) {
+ %vtable = load ptr, ptr %obj
+ %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
+ call void @llvm.assume(i1 %p)
+ %fptrptr = getelementptr [3 x ptr], ptr %vtable, i32 0, i32 1
+ %fptr = load ptr, ptr %fptrptr
+ %result = call i8 %fptr(ptr %obj)
+ ret i8 %result
+ ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -2
+ ; CHECK: [[VTLOAD:%[^ ]*]] = load i8, ptr [[VTGEP2]]
+ ; CHECK: ret i8 [[VTLOAD]]
+}
+
+;; We never constant propagate this since the i32 cannot reliabely loaded
----------------
ilovepi wrote:
```suggestion
;; We never constant propagate this since the i32 cannot be reliably loaded
```
https://github.com/llvm/llvm-project/pull/138989
More information about the llvm-commits
mailing list