[llvm] cc5c588 - [WPD] Avoid noalias assumptions in unique return value optimization

Bob Haarman via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 14:52:30 PDT 2020


Author: Bob Haarman
Date: 2020-04-16T14:49:51-07:00
New Revision: cc5c58889ec624461d41bdd0366ee88cf2805564

URL: https://github.com/llvm/llvm-project/commit/cc5c58889ec624461d41bdd0366ee88cf2805564
DIFF: https://github.com/llvm/llvm-project/commit/cc5c58889ec624461d41bdd0366ee88cf2805564.diff

LOG: [WPD] Avoid noalias assumptions in unique return value optimization

Summary:
Changes the type of the @__typeid_.*_unique_member imports we generate
for unique return value optimization from i8 to [0 x i8]. This
prevents assuming that these imports do not alias, such as when
two unique return values occur in the same vtable.

Fixes PR45393.

Reviewers: tejohnson, pcc

Reviewed By: pcc

Subscribers: aganea, hiraditya, rnk, george.burgess.iv, dblaikie, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77421

Added: 
    llvm/test/Transforms/WholeProgramDevirt/Inputs/unique-retval-same-vtable.yaml
    llvm/test/Transforms/WholeProgramDevirt/unique-retval-same-vtable.ll

Modified: 
    llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
    llvm/test/Transforms/WholeProgramDevirt/import.ll
    llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index b1905e2af05a..60f8e935ffdd 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -500,6 +500,10 @@ struct DevirtModule {
   IntegerType *Int32Ty;
   IntegerType *Int64Ty;
   IntegerType *IntPtrTy;
+  /// Sizeless array type, used for imported vtables. This provides a signal
+  /// to analyzers that these imports may alias, as they do for example
+  /// when multiple unique return values occur in the same vtable.
+  ArrayType *Int8Arr0Ty;
 
   bool RemarksEnabled;
   function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;
@@ -529,6 +533,7 @@ struct DevirtModule {
         Int32Ty(Type::getInt32Ty(M.getContext())),
         Int64Ty(Type::getInt64Ty(M.getContext())),
         IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),
+        Int8Arr0Ty(ArrayType::get(Type::getInt8Ty(M.getContext()), 0)),
         RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
     assert(!(ExportSummary && ImportSummary));
     FunctionsToSkip.init(SkipFunctionNames);
@@ -1415,7 +1420,8 @@ void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
 
 Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
                                      StringRef Name) {
-  Constant *C = M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Ty);
+  Constant *C =
+      M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
   auto *GV = dyn_cast<GlobalVariable>(C);
   if (GV)
     GV->setVisibility(GlobalValue::HiddenVisibility);
@@ -1457,8 +1463,8 @@ void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
   for (auto &&Call : CSInfo.CallSites) {
     IRBuilder<> B(Call.CS.getInstruction());
     Value *Cmp =
-        B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
-                     B.CreateBitCast(Call.VTable, Int8PtrTy), UniqueMemberAddr);
+        B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, Call.VTable,
+                     B.CreateBitCast(UniqueMemberAddr, Call.VTable->getType()));
     Cmp = B.CreateZExt(Cmp, Call.CS->getType());
     Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, OREGetter,
                          Cmp);

diff  --git a/llvm/test/Transforms/WholeProgramDevirt/Inputs/unique-retval-same-vtable.yaml b/llvm/test/Transforms/WholeProgramDevirt/Inputs/unique-retval-same-vtable.yaml
new file mode 100644
index 000000000000..198a7fc29977
--- /dev/null
+++ b/llvm/test/Transforms/WholeProgramDevirt/Inputs/unique-retval-same-vtable.yaml
@@ -0,0 +1,17 @@
+---
+TypeIdMap:
+  _ZTS1C:
+    WPDRes:
+      16:
+        Kind:            Indir
+        ResByArg:
+          '':
+            Kind:            UniqueRetVal
+            Info:            1
+      24:
+        Kind:            Indir
+        ResByArg:
+          '':
+            Kind:            UniqueRetVal
+            Info:            1
+...

diff  --git a/llvm/test/Transforms/WholeProgramDevirt/import.ll b/llvm/test/Transforms/WholeProgramDevirt/import.ll
index 525d88cb6624..8beb27db26fe 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/import.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/import.ll
@@ -11,10 +11,10 @@
 target datalayout = "e-p:64:64"
 target triple = "x86_64-unknown-linux-gnu"
 
-; VCP-X86: @__typeid_typeid1_0_1_byte = external hidden global i8, !absolute_symbol !0
-; VCP-X86: @__typeid_typeid1_0_1_bit = external hidden global i8, !absolute_symbol !1
-; VCP-X86: @__typeid_typeid2_8_3_byte = external hidden global i8, !absolute_symbol !0
-; VCP-X86: @__typeid_typeid2_8_3_bit = external hidden global i8, !absolute_symbol !1
+; VCP-X86: @__typeid_typeid1_0_1_byte = external hidden global [0 x i8], !absolute_symbol !0
+; VCP-X86: @__typeid_typeid1_0_1_bit = external hidden global [0 x i8], !absolute_symbol !1
+; VCP-X86: @__typeid_typeid2_8_3_byte = external hidden global [0 x i8], !absolute_symbol !0
+; VCP-X86: @__typeid_typeid2_8_3_bit = external hidden global [0 x i8], !absolute_symbol !1
 
 ; Test cases where the argument values are known and we can apply virtual
 ; constant propagation.
@@ -34,7 +34,7 @@ define i32 @call1(i8* %obj) #0 {
   ; SINGLE-IMPL: call i32 bitcast (void ()* @singleimpl1 to i32 (i8*, i32)*)
   %result = call i32 %fptr_casted(i8* %obj, i32 1)
   ; UNIFORM-RET-VAL: ret i32 42
-  ; VCP-X86: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 ptrtoint (i8* @__typeid_typeid1_0_1_byte to i32)
+  ; VCP-X86: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 ptrtoint ([0 x i8]* @__typeid_typeid1_0_1_byte to i32)
   ; VCP-ARM: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 42
   ; VCP: [[BC1:%.*]] = bitcast i8* [[GEP1]] to i32*
   ; VCP: [[LOAD1:%.*]] = load i32, i32* [[BC1]]
@@ -85,13 +85,13 @@ define i1 @call3(i8* %obj) #0 {
 cont:
   %fptr_casted = bitcast i8* %fptr to i1 (i8*, i32)*
   %result = call i1 %fptr_casted(i8* %obj, i32 3)
-  ; UNIQUE-RET-VAL0: icmp ne i8* %vtablei8, @__typeid_typeid2_8_3_unique_member
-  ; UNIQUE-RET-VAL1: icmp eq i8* %vtablei8, @__typeid_typeid2_8_3_unique_member
+  ; UNIQUE-RET-VAL0: icmp ne i8* %vtablei8, getelementptr inbounds ([0 x i8], [0 x i8]* @__typeid_typeid2_8_3_unique_member, i32 0, i32 0)
+  ; UNIQUE-RET-VAL1: icmp eq i8* %vtablei8, getelementptr inbounds ([0 x i8], [0 x i8]* @__typeid_typeid2_8_3_unique_member, i32 0, i32 0)
   ; VCP: [[VT2:%.*]] = bitcast {{.*}} to i8*
-  ; VCP-X86: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 ptrtoint (i8* @__typeid_typeid2_8_3_byte to i32)
+  ; VCP-X86: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 ptrtoint ([0 x i8]* @__typeid_typeid2_8_3_byte to i32)
   ; VCP-ARM: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 43
   ; VCP: [[LOAD2:%.*]] = load i8, i8* [[GEP2]]
-  ; VCP-X86: [[AND2:%.*]] = and i8 [[LOAD2]], ptrtoint (i8* @__typeid_typeid2_8_3_bit to i8)
+  ; VCP-X86: [[AND2:%.*]] = and i8 [[LOAD2]], ptrtoint ([0 x i8]* @__typeid_typeid2_8_3_bit to i8)
   ; VCP-ARM: [[AND2:%.*]] = and i8 [[LOAD2]], -128
   ; VCP: [[ICMP2:%.*]] = icmp ne i8 [[AND2]], 0
   ; VCP: ret i1 [[ICMP2]]

diff  --git a/llvm/test/Transforms/WholeProgramDevirt/unique-retval-same-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/unique-retval-same-vtable.ll
new file mode 100644
index 000000000000..c4d6de7f932b
--- /dev/null
+++ b/llvm/test/Transforms/WholeProgramDevirt/unique-retval-same-vtable.ll
@@ -0,0 +1,59 @@
+; Test for PR45393: Two virtual functions that return unique i1 values
+; in the same vtable. Both calls are optimized to a comparison of
+; this's vptr against the address of the vtable. When nesting these
+; checks, LLVM would previously assume the nested check always fails,
+; but that assumption does not hold if both checks refer to the same vtable.
+; This tests checks that this case is handled correctly.
+;
+; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import \
+; RUN:   -wholeprogramdevirt-read-summary=%p/Inputs/unique-retval-same-vtable.yaml \
+; RUN:   -O2 -o - %s | FileCheck %s
+;
+; Check that C::f() contains both possible return values.
+; CHECK-LABEL: define {{.*}} @_ZNK1C1fEv
+; CHECK-NOT: }
+; CHECK: 20074028
+; CHECK-NOT: }
+; CHECK: 1008434
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%class.C = type { i32 (...)** }
+
+define hidden i32 @_ZNK1C1fEv(%class.C* %this) {
+entry:
+  %0 = bitcast %class.C* %this to i1 (%class.C*)***
+  %vtable = load i1 (%class.C*)**, i1 (%class.C*)*** %0
+  %1 = bitcast i1 (%class.C*)** %vtable to i8*
+  %2 = tail call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1C")
+  tail call void @llvm.assume(i1 %2)
+  %vfn = getelementptr inbounds i1 (%class.C*)*, i1 (%class.C*)** %vtable, i64 2
+  %3 = load i1 (%class.C*)*, i1 (%class.C*)** %vfn
+  %call = tail call zeroext i1 %3(%class.C* %this)
+  br i1 %call, label %if.then, label %return
+
+if.then:
+  %vtable2 = load i1 (%class.C*)**, i1 (%class.C*)*** %0
+  %4 = bitcast i1 (%class.C*)** %vtable2 to i8*
+  %5 = tail call i1 @llvm.type.test(i8* %4, metadata !"_ZTS1C")
+  tail call void @llvm.assume(i1 %5)
+  %vfn3 = getelementptr inbounds i1 (%class.C*)*, i1 (%class.C*)** %vtable2, i64 3
+  %6 = load i1 (%class.C*)*, i1 (%class.C*)** %vfn3
+  ; The method being called here and the method being called before
+  ; the branch above both return true in the same vtable and only that
+  ; vtable. Therefore, if this call is reached, we must select
+  ; 20074028. Earlier versions of LLVM mistakenly concluded that
+  ; this code *never* selects 200744028.
+  %call4 = tail call zeroext i1 %6(%class.C* nonnull %this)
+  %. = select i1 %call4, i32 20074028, i32 3007762
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ %., %if.then ], [ 1008434, %entry ]
+  ret i32 %retval.0
+}
+
+declare i1 @llvm.type.test(i8*, metadata)
+
+declare void @llvm.assume(i1)

diff  --git a/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll b/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll
index f03c07d24de6..6d91cd4be7eb 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll
@@ -20,15 +20,13 @@ define i1 @vf1(i8* %this) readnone {
 define i1 @call1(i8* %obj) {
   %vtableptr = bitcast i8* %obj to [1 x i8*]**
   %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
-  ; CHECK: {{.*}} = bitcast [1 x i8*]* {{.*}} to i8*
-  ; CHECK: [[VT1:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8*
   %vtablei8 = bitcast [1 x i8*]* %vtable to i8*
   %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid1")
   call void @llvm.assume(i1 %p)
   %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
   %fptr = load i8*, i8** %fptrptr
   %fptr_casted = bitcast i8* %fptr to i1 (i8*)*
-  ; CHECK: [[RES1:%[^ ]*]] = icmp eq i8* [[VT1]], bitcast ([1 x i8*]* @vt3 to i8*)
+  ; CHECK: [[RES1:%[^ ]*]] = icmp eq [1 x i8*]* %vtable, @vt3
   %result = call i1 %fptr_casted(i8* %obj)
   ; CHECK: ret i1 [[RES1]]
   ret i1 %result
@@ -38,7 +36,6 @@ define i1 @call1(i8* %obj) {
 define i32 @call2(i8* %obj) {
   %vtableptr = bitcast i8* %obj to [1 x i8*]**
   %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
-  ; CHECK: [[VT2:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8*
   %vtablei8 = bitcast [1 x i8*]* %vtable to i8*
   %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid2")
   call void @llvm.assume(i1 %p)
@@ -46,7 +43,7 @@ define i32 @call2(i8* %obj) {
   %fptr = load i8*, i8** %fptrptr
   ; Intentional type mismatch to test zero extend.
   %fptr_casted = bitcast i8* %fptr to i32 (i8*)*
-  ; CHECK: [[RES2:%[^ ]*]] = icmp ne i8* [[VT1]], bitcast ([1 x i8*]* @vt2 to i8*)
+  ; CHECK: [[RES2:%[^ ]*]] = icmp ne [1 x i8*]* %vtable, @vt2
   %result = call i32 %fptr_casted(i8* %obj)
   ; CHECK: [[ZEXT2:%[^ ]*]] = zext i1 [[RES2]] to i32
   ; CHECK: ret i32 [[ZEXT2:%[^ ]*]]


        


More information about the llvm-commits mailing list