[llvm] [clang] split load to bytes to deduce load value (PR #72364)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 15 01:31:30 PST 2023


https://github.com/mohammed-nurulhoque created https://github.com/llvm/llvm-project/pull/72364

When the last clobbering write for a load doesn't cover the whole load (example below). AnalyzeLoadAvailability would give up. 
This emits  temporary byte-sized loads that cover the original load, then run AnalyzeLoadAvailability  on each and reconstruct the load value.

```
  define i32 @f(i8* %P)
    %b2 = getelementptr inbounds i8, i8* %P, i64 1
    store i8 0, i8* %b2, align 1
    store i8 0, i8* %P, align 1
    %s1 = bitcast i8* %P to i16*
    %L = load i16, i16* %s1, align 4
```

>From 41a9dbd39fbb866e7fc090f82d58ee6364a7cfda Mon Sep 17 00:00:00 2001
From: "Mohammed.NurulHoque" <Mohammed.NurulHoque at imgtec.com>
Date: Wed, 27 Apr 2022 09:42:37 +0100
Subject: [PATCH] split load to bytes and run analyzeloadavailability per byte
 to deduce load value

---
 .../optimization-remark-extra-analysis.c      |   3 +-
 llvm/include/llvm/Transforms/Scalar/GVN.h     |   1 +
 llvm/lib/Transforms/Scalar/GVN.cpp            | 105 ++++++++++-
 .../BasicAA/2003-02-26-AccessSizeTest.ll      |  12 +-
 .../TypeBasedAliasAnalysis/precedence.ll      |   5 +-
 .../GVN/2009-11-12-MemDepMallocBitCast.ll     |   6 +-
 .../GVN/no_speculative_loads_with_asan.ll     |  20 +--
 .../GVN/opt-remarks-multiple-users.ll         |   3 +
 .../GVN/opt-remarks-non-dominating.ll         |   3 +
 .../Transforms/GVN/split-load-assertion.ll    | 166 ++++++++++++++++++
 .../NewGVN/no_speculative_loads_with_asan.ll  |  96 +++++-----
 11 files changed, 348 insertions(+), 72 deletions(-)
 create mode 100644 llvm/test/Transforms/GVN/split-load-assertion.ll

diff --git a/clang/test/Frontend/optimization-remark-extra-analysis.c b/clang/test/Frontend/optimization-remark-extra-analysis.c
index 1a8415e69cff9ba..5af30bd0d3c35b3 100644
--- a/clang/test/Frontend/optimization-remark-extra-analysis.c
+++ b/clang/test/Frontend/optimization-remark-extra-analysis.c
@@ -6,6 +6,7 @@
 int foo(int *x, int *y) {
   int a = *x;
   *y = 2;
-  // expected-remark at +1 {{load of type i32 not eliminated}}
+  // expected-remark at +2 {{load of type i32 not eliminated}}
+  // expected-remark at +1 {{load of type i8 not eliminated}}
   return a + *x;
 }
diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index 4ba9b74ccb005d4..4052c0d618d173d 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -314,6 +314,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
 
   // Helper functions of redundant load elimination
   bool processLoad(LoadInst *L);
+  bool splitAndprocessLoad(LoadInst *L);
   bool processNonLocalLoad(LoadInst *L);
   bool processAssumeIntrinsic(AssumeInst *II);
 
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 5e58af0edc1556f..f64508a8319197f 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -112,6 +112,7 @@ static cl::opt<bool>
 GVNEnableSplitBackedgeInLoadPRE("enable-split-backedge-in-load-pre",
                                 cl::init(false));
 static cl::opt<bool> GVNEnableMemDep("enable-gvn-memdep", cl::init(true));
+static cl::opt<bool> GVNEnableSplitLoad("enable-split-load", cl::init(true));
 
 static cl::opt<uint32_t> MaxNumDeps(
     "gvn-max-num-deps", cl::Hidden, cl::init(100),
@@ -2128,6 +2129,105 @@ static void patchAndReplaceAllUsesWith(Instruction *I, Value *Repl) {
   I->replaceAllUsesWith(Repl);
 }
 
+// split load to single byte loads and check if the value can be deduced
+//
+// Example:
+// define i32 @f(i8* %P)
+// 1:  %b2 = getelementptr inbounds i8, i8* %P, i64 1
+// 2:  store i8 0, i8* %b2, align 1
+// 3:  store i8 0, i8* %P, align 1
+// 4:  %s1 = bitcast i8* %P to i16*
+// 5:  %L = load i16, i16* %s1, align 4
+//
+// The last clobbering write for the load is (3) but it doesn't cover the whole
+// read. So AnalyzeLoadAvailability would give up.
+// This function emit temporary byte-sized loads that cover the original load,
+// so that any last write covers the read. We run AnalyzeLoadAvailability on
+// each byte to try to construct the load as a constant.
+bool GVNPass::splitAndprocessLoad(LoadInst *L) {
+  if (L->isAtomic())
+    return false;
+
+  Type *LTy = L->getType();
+  if (!LTy->isIntegerTy())
+    return false;
+
+  unsigned BW = LTy->getIntegerBitWidth();
+  if (BW % 8)
+    return false;
+
+  IntegerType *ByteTy = IntegerType::getInt8Ty(LTy->getContext());
+  Type *BytePtrTy = PointerType::get(ByteTy, L->getPointerAddressSpace());
+  BitCastInst *Base = new BitCastInst(L->getPointerOperand(), BytePtrTy, "", L);
+
+  // we update this byte by byte as we deduce the load value
+  APInt ConstructedValue = APInt::getZero(BW);
+
+  for (unsigned i=0; i<BW/8; i++) {
+    Value *Offset = Constant::getIntegerValue(LTy, APInt(BW, i));
+    GetElementPtrInst *GEP = GetElementPtrInst::Create(
+                               ByteTy, Base, ArrayRef<Value*>(Offset), "", L);
+    LoadInst *ByteLoad = new LoadInst(ByteTy, GEP, "", L);
+    ByteLoad->setDebugLoc(L->getDebugLoc());
+
+    auto CleanupTmps = [&]() {
+      MD->removeInstruction(ByteLoad);
+      ByteLoad->eraseFromParent();
+      GEP->eraseFromParent();
+    };
+
+    MemDepResult ByteDep = MD->getDependency(ByteLoad);
+    // AnalyzeLoadAvailability only analyzes local deps.
+    // If dep is not def or clobber, we cannot get a value from it.
+    if (ByteDep.isNonLocal() || (!ByteDep.isDef() && !ByteDep.isClobber())) {
+      CleanupTmps();
+      Base->eraseFromParent();
+      return false;
+    }
+
+    auto ByteRes = AnalyzeLoadAvailability(ByteLoad, ByteDep, GEP);
+    // If it doesn't reduce to a constant, give up. Creating the value at runtime by
+    // shifting the bytes is not worth it to remove a load.
+    if (ByteRes &&
+          (ByteRes->isMemIntrinValue() ||
+           (ByteRes->isSimpleValue() &&
+            (isa<ConstantInt>(ByteRes->getSimpleValue()) ||
+             isa<UndefValue>(ByteRes->getSimpleValue()))))) {
+        Value *V = ByteRes->MaterializeAdjustedValue(ByteLoad, ByteLoad, *this);
+        ConstantInt *ByteConst = dyn_cast<ConstantInt>(V);
+        if (!ByteConst) {
+          // replace undef with 0. This helps optimize cases where some bits of
+          // load are constant integer, and some are undef. So we can optimize
+          // the load to a particular integer.
+          ByteConst = ConstantInt::get(ByteTy, 0);
+        }
+        ConstructedValue.insertBits(ByteConst->getValue(), 8*i);
+    } else {
+      LLVM_DEBUG(dbgs() << "GVN split load: byte " << i
+                        << " did not reduce to a constant. Giving up");
+      CleanupTmps();
+      Base->eraseFromParent();
+      return false;
+    }
+    CleanupTmps();
+  }
+  Base->eraseFromParent();
+
+  // Replace the load!
+  Constant *LoadValue = ConstantInt::get(LTy, ConstructedValue);
+  patchAndReplaceAllUsesWith(L, LoadValue);
+  markInstructionForDeletion(L);
+  if (MSSAU)
+    MSSAU->removeMemoryAccess(L);
+  ++NumGVNLoad;
+  reportLoadElim(L, LoadValue, ORE);
+  // Tell MDA to reexamine the reused pointer since we might have more
+  // information after forwarding it.
+  if (MD && LoadValue->getType()->isPtrOrPtrVectorTy())
+    MD->invalidateCachedPointerInfo(LoadValue);
+  return true;
+}
+
 /// Attempt to eliminate a load, first by eliminating it
 /// locally, and then attempting non-local elimination if that fails.
 bool GVNPass::processLoad(LoadInst *L) {
@@ -2161,8 +2261,11 @@ bool GVNPass::processLoad(LoadInst *L) {
   }
 
   auto AV = AnalyzeLoadAvailability(L, Dep, L->getPointerOperand());
-  if (!AV)
+  if (!AV) {
+    if (GVNEnableSplitLoad)
+      return splitAndprocessLoad(L);
     return false;
+  }
 
   Value *AvailableValue = AV->MaterializeAdjustedValue(L, L, *this);
 
diff --git a/llvm/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll b/llvm/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll
index ed97d2192b8e4b8..a0ce0fdb6e756a3 100644
--- a/llvm/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll
+++ b/llvm/test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll
@@ -1,19 +1,19 @@
 ; This testcase makes sure that size is taken to account when alias analysis 
-; is performed.  It is not legal to delete the second load instruction because
-; the value computed by the first load instruction is changed by the store.
+; is performed. The stores rights to parts of the second load
 
 ; RUN: opt < %s -aa-pipeline=basic-aa -passes=gvn,instcombine -S | FileCheck %s
 
 define i32 @test() {
-; CHECK: %Y.DONOTREMOVE = load i32, ptr %A
-; CHECK: %Z = sub i32 0, %Y.DONOTREMOVE
+; CHECK:      @test
+; CHECK-NEXT: ret i32 -256
+
   %A = alloca i32
   store i32 0, ptr %A
   %X = load i32, ptr %A
   %C = getelementptr i8, ptr %A, i64 1
   store i8 1, ptr %C    ; Aliases %A
-  %Y.DONOTREMOVE = load i32, ptr %A
-  %Z = sub i32 %X, %Y.DONOTREMOVE
+  %D = load i32, ptr %A
+  %Z = sub i32 %X, %D
   ret i32 %Z
 }
 
diff --git a/llvm/test/Analysis/TypeBasedAliasAnalysis/precedence.ll b/llvm/test/Analysis/TypeBasedAliasAnalysis/precedence.ll
index 175bef60a4c167f..29bc1602be3b68b 100644
--- a/llvm/test/Analysis/TypeBasedAliasAnalysis/precedence.ll
+++ b/llvm/test/Analysis/TypeBasedAliasAnalysis/precedence.ll
@@ -21,13 +21,12 @@ entry:
   ret i32 %tmp3
 }
 
-; Test for PartialAlias aliasing. GVN doesn't yet eliminate the load
-; in the BasicAA case.
+; Test for PartialAlias aliasing.
 
 ; TBAA:    @offset
 ; TBAA:      ret i64 0
 ; BASICAA: @offset
-; BASICAA:   ret i64 %tmp3
+; BASICAA:   ret i64 256
 define i64 @offset(ptr %x) nounwind {
 entry:
   store i64 0, ptr %x, !tbaa !4
diff --git a/llvm/test/Transforms/GVN/2009-11-12-MemDepMallocBitCast.ll b/llvm/test/Transforms/GVN/2009-11-12-MemDepMallocBitCast.ll
index f2d4fa9d378448b..d51c86e8be54bc0 100644
--- a/llvm/test/Transforms/GVN/2009-11-12-MemDepMallocBitCast.ll
+++ b/llvm/test/Transforms/GVN/2009-11-12-MemDepMallocBitCast.ll
@@ -1,5 +1,5 @@
-; Test to make sure malloc's bitcast does not block detection of a store 
-; to aliased memory; GVN should not optimize away the load in this program.
+; Test to make sure malloc's bitcast does not block detection of a store
+; to aliased memory.
 ; RUN: opt < %s -passes=gvn -S | FileCheck %s
 
 define i64 @test() {
@@ -7,7 +7,7 @@ define i64 @test() {
   store i8 42, ptr %1
   %Y = load i64, ptr %1                               ; <i64> [#uses=1]
   ret i64 %Y
-; CHECK: %Y = load i64, ptr %1
+; CHECK: store i8 42, ptr %1, align 1
 ; CHECK: ret i64 %Y
 }
 
diff --git a/llvm/test/Transforms/GVN/no_speculative_loads_with_asan.ll b/llvm/test/Transforms/GVN/no_speculative_loads_with_asan.ll
index 0ff237b83fb3c83..9c624d2649ca78c 100644
--- a/llvm/test/Transforms/GVN/no_speculative_loads_with_asan.ll
+++ b/llvm/test/Transforms/GVN/no_speculative_loads_with_asan.ll
@@ -12,11 +12,11 @@ define i32 @TestNoAsan() {
 ; CHECK-NEXT:    [[I1:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1
 ; CHECK-NEXT:    store i8 0, ptr [[I1]], align 1
 ; CHECK-NEXT:    store i8 0, ptr [[I]], align 1
-; CHECK-NEXT:    [[I3:%.*]] = load i16, ptr [[I]], align 4
-; CHECK-NEXT:    [[I4:%.*]] = icmp eq i16 [[I3]], 0
-; CHECK-NEXT:    br i1 [[I4]], label [[BB10:%.*]], label [[BB5:%.*]]
+; CHECK-NEXT:    br i1 true, label [[BB10:%.*]], label [[BB5:%.*]]
 ; CHECK:       bb5:
 ; CHECK-NEXT:    [[I6:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 2
+; CHECK-NEXT:    [[I8:%.*]] = load i16, ptr [[I6]], align 2
+; CHECK-NEXT:    [[I9:%.*]] = sext i16 [[I8]] to i32
 ; CHECK-NEXT:    br label [[BB10]]
 ; CHECK:       bb10:
 ; CHECK-NEXT:    ret i32 0
@@ -48,17 +48,14 @@ define i32 @TestAsan() sanitize_address {
 ; CHECK-NEXT:    [[I1:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1
 ; CHECK-NEXT:    store i8 0, ptr [[I1]], align 1
 ; CHECK-NEXT:    store i8 0, ptr [[I]], align 1
-; CHECK-NEXT:    [[I3:%.*]] = load i16, ptr [[I]], align 4
-; CHECK-NEXT:    [[I4:%.*]] = icmp eq i16 [[I3]], 0
-; CHECK-NEXT:    br i1 [[I4]], label [[BB10:%.*]], label [[BB5:%.*]]
+; CHECK-NEXT:    br i1 true, label [[BB10:%.*]], label [[BB5:%.*]]
 ; CHECK:       bb5:
 ; CHECK-NEXT:    [[I6:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 2
 ; CHECK-NEXT:    [[I8:%.*]] = load i16, ptr [[I6]], align 2
 ; CHECK-NEXT:    [[I9:%.*]] = sext i16 [[I8]] to i32
 ; CHECK-NEXT:    br label [[BB10]]
 ; CHECK:       bb10:
-; CHECK-NEXT:    [[I11:%.*]] = phi i32 [ [[I9]], [[BB5]] ], [ 0, [[BB:%.*]] ]
-; CHECK-NEXT:    ret i32 [[I11]]
+; CHECK-NEXT:    ret i32 0
 ;
 bb:
   %i = tail call noalias ptr @_Znam(i64 2)
@@ -87,17 +84,14 @@ define i32 @TestHWAsan() sanitize_hwaddress {
 ; CHECK-NEXT:    [[I1:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 1
 ; CHECK-NEXT:    store i8 0, ptr [[I1]], align 1
 ; CHECK-NEXT:    store i8 0, ptr [[I]], align 1
-; CHECK-NEXT:    [[I3:%.*]] = load i16, ptr [[I]], align 4
-; CHECK-NEXT:    [[I4:%.*]] = icmp eq i16 [[I3]], 0
-; CHECK-NEXT:    br i1 [[I4]], label [[BB10:%.*]], label [[BB5:%.*]]
+; CHECK-NEXT:    br i1 true, label [[BB10:%.*]], label [[BB5:%.*]]
 ; CHECK:       bb5:
 ; CHECK-NEXT:    [[I6:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 2
 ; CHECK-NEXT:    [[I8:%.*]] = load i16, ptr [[I6]], align 2
 ; CHECK-NEXT:    [[I9:%.*]] = sext i16 [[I8]] to i32
 ; CHECK-NEXT:    br label [[BB10]]
 ; CHECK:       bb10:
-; CHECK-NEXT:    [[I11:%.*]] = phi i32 [ [[I9]], [[BB5]] ], [ 0, [[BB:%.*]] ]
-; CHECK-NEXT:    ret i32 [[I11]]
+; CHECK-NEXT:    ret i32 0
 ;
 bb:
   %i = tail call noalias ptr @_Znam(i64 2)
diff --git a/llvm/test/Transforms/GVN/opt-remarks-multiple-users.ll b/llvm/test/Transforms/GVN/opt-remarks-multiple-users.ll
index b7df74e08865efd..b8dbc6d1c32775d 100644
--- a/llvm/test/Transforms/GVN/opt-remarks-multiple-users.ll
+++ b/llvm/test/Transforms/GVN/opt-remarks-multiple-users.ll
@@ -17,6 +17,7 @@
 ; CHECK-NEXT:     DebugLoc: { File: '/tmp/s.c', Line: 1, Column: 1 }
 ; CHECK-NEXT: ...
 ; CHECK:      --- !Missed
+; CHECK:      --- !Missed
 ; CHECK-NEXT: Pass:            gvn
 ; CHECK-NEXT: Name:            LoadClobbered
 ; CHECK-NEXT: DebugLoc: { File: '/tmp/s.c', Line: 4, Column: 4 }
@@ -32,6 +33,7 @@
 ; CHECK-NEXT:   - ClobberedBy:     call
 ; CHECK-NEXT:     DebugLoc: { File: '/tmp/s.c', Line: 3, Column: 3 }
 ; CHECK-NEXT: ...
+; CHECK:      --- !Missed
 
 ; ModuleID = 'bugpoint-reduced-simplified.bc'
 source_filename = "gvn-test.c"
@@ -69,6 +71,7 @@ entry:
 ; CHECK-NEXT:     DebugLoc: { File: '/tmp/s.c', Line: 1, Column: 1 }
 ; CHECK-NEXT: ...
 ; CHECK:      --- !Missed
+; CHECK:      --- !Missed
 ; CHECK-NEXT: Pass:            gvn
 ; CHECK-NEXT: Name:            LoadClobbered
 ; CHECK-NEXT: DebugLoc: { File: '/tmp/s.c', Line: 4, Column: 4 }
diff --git a/llvm/test/Transforms/GVN/opt-remarks-non-dominating.ll b/llvm/test/Transforms/GVN/opt-remarks-non-dominating.ll
index a5f3d7ecce2b8e7..d4a337c2d9cf37f 100644
--- a/llvm/test/Transforms/GVN/opt-remarks-non-dominating.ll
+++ b/llvm/test/Transforms/GVN/opt-remarks-non-dominating.ll
@@ -42,6 +42,7 @@ if.end:                                           ; preds = %if.then, %entry
 
 declare dso_local void @clobberingFunc() local_unnamed_addr #0
 
+; CHECK:      --- !Missed
 ; CHECK:      --- !Missed
 ; CHECK-NEXT: Pass:            gvn
 ; CHECK-NEXT: Name:            LoadClobbered
@@ -59,6 +60,7 @@ declare dso_local void @clobberingFunc() local_unnamed_addr #0
 ; CHECK-NEXT:     DebugLoc: { File: '/tmp/s.c', Line: 2, Column: 2 }
 ; CHECK-NEXT: ...
 ; CHECK:      --- !Missed
+; CHECK:      --- !Missed
 ; CHECK-NEXT: Pass:            gvn
 ; CHECK-NEXT: Name:            LoadClobbered
 ; CHECK-NEXT: DebugLoc:        { File: '/tmp/s.c', Line: 5, Column: 5 }
@@ -136,6 +138,7 @@ if.end5:                                          ; preds = %if.end5.sink.split,
   ret void
 }
 
+; CHECK:      --- !Missed
 ; CHECK:      --- !Missed
 ; CHECK-NEXT: Pass:            gvn
 ; CHECK-NEXT: Name:            LoadClobbered
diff --git a/llvm/test/Transforms/GVN/split-load-assertion.ll b/llvm/test/Transforms/GVN/split-load-assertion.ll
new file mode 100644
index 000000000000000..0d7cc632d9cb3a7
--- /dev/null
+++ b/llvm/test/Transforms/GVN/split-load-assertion.ll
@@ -0,0 +1,166 @@
+; RUN: opt -S -O3 < %s
+
+; This test had caused a GVN assertion error in an earlier version
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32-img-unknown-elf"
+
+%"class.std::function" = type { %"class.std::_Function_base", ptr }
+%"class.std::_Function_base" = type { %"union.std::_Any_data", ptr }
+%"union.std::_Any_data" = type { %"union.std::_Nocopy_types" }
+%"union.std::_Nocopy_types" = type { { i32, i32 } }
+
+; Function Attrs: mustprogress
+define dso_local noundef i32 @_Z3foov() local_unnamed_addr personality ptr @__gxx_personality_v0 {
+entry:
+  %f = alloca %"class.std::function", align 4
+  %g = alloca %"class.std::function", align 4
+  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %f) 
+  call void @_ZNSt8functionIFivEEC2IRS0_vEEOT_(ptr noundef nonnull align 4 dereferenceable(16) %f, ptr noundef nonnull @_Z2f1v) 
+  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %g) 
+  call void @_ZNSt8functionIFivEEC2IRS0_vEEOT_(ptr noundef nonnull align 4 dereferenceable(16) %g, ptr noundef nonnull @_Z2f2v) 
+  call void @_ZNSt8functionIFivEE4swapERS1_(ptr noundef nonnull align 4 dereferenceable(16) %f, ptr noundef nonnull align 4 dereferenceable(16) %g) 
+  %call = invoke noundef i32 @_ZNKSt8functionIFivEEclEv(ptr noundef nonnull align 4 dereferenceable(16) %g)
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:                                      ; preds = %entry
+  %cmp = icmp eq i32 %call, 42
+  br i1 %cmp, label %land.rhs, label %land.end
+
+land.rhs:                                         ; preds = %invoke.cont
+  %call2 = invoke noundef i32 @_ZNKSt8functionIFivEEclEv(ptr noundef nonnull align 4 dereferenceable(16) %f)
+          to label %invoke.cont1 unwind label %lpad
+
+invoke.cont1:                                     ; preds = %land.rhs
+  %cmp3 = icmp eq i32 %call2, 0
+  %phi.cast = zext i1 %cmp3 to i32
+  br label %land.end
+
+land.end:                                         ; preds = %invoke.cont1, %invoke.cont
+  %0 = phi i32 [ 0, %invoke.cont ], [ %phi.cast, %invoke.cont1 ]
+  call void @_ZNSt14_Function_baseD2Ev(ptr noundef nonnull align 4 dereferenceable(16) %g) 
+  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %g) 
+  call void @_ZNSt14_Function_baseD2Ev(ptr noundef nonnull align 4 dereferenceable(16) %f) 
+  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %f) 
+  ret i32 %0
+
+lpad:                                             ; preds = %land.rhs, %entry
+  %1 = landingpad { ptr, i32 }
+          cleanup
+  call void @_ZNSt14_Function_baseD2Ev(ptr noundef nonnull align 4 dereferenceable(16) %g) 
+  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %g) 
+  call void @_ZNSt14_Function_baseD2Ev(ptr noundef nonnull align 4 dereferenceable(16) %f) 
+  call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %f) 
+  resume { ptr, i32 } %1
+}
+
+; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0(i64 immarg %0, ptr nocapture %1) 
+
+declare dso_local noundef i32 @_Z2f1v() 
+
+; Function Attrs: nounwind
+define linkonce_odr dso_local void @_ZNSt8functionIFivEEC2IRS0_vEEOT_(ptr noundef nonnull align 4 dereferenceable(16) %this, ptr noundef nonnull %__f) unnamed_addr align 2 {
+entry:
+  call void @llvm.memset.p0.i32(ptr noundef nonnull align 4 dereferenceable(12) %this, i8 0, i32 12, i1 false)
+  call void @_ZNSt14_Function_baseC2Ev(ptr noundef nonnull align 4 dereferenceable(12) %this) 
+  %_M_invoker = getelementptr inbounds %"class.std::function", ptr %this, i32 0, i32 1
+  store ptr null, ptr %_M_invoker, align 4
+  %call = call noundef zeroext i1 @_ZNSt14_Function_base13_Base_managerIPFivEE21_M_not_empty_functionIS1_EEbPT_(ptr noundef nonnull %__f) 
+  br i1 %call, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  call void @_ZNSt14_Function_base13_Base_managerIPFivEE15_M_init_functorIRS1_EEvRSt9_Any_dataOT_(ptr noundef nonnull align 4 dereferenceable(8) %this, ptr noundef nonnull %__f) 
+  store ptr @_ZNSt17_Function_handlerIFivEPS0_E9_M_invokeERKSt9_Any_data, ptr %_M_invoker, align 4
+  %_M_manager = getelementptr inbounds %"class.std::_Function_base", ptr %this, i32 0, i32 1
+  store ptr @_ZNSt17_Function_handlerIFivEPS0_E10_M_managerERSt9_Any_dataRKS3_St18_Manager_operation, ptr %_M_manager, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  ret void
+}
+
+declare dso_local noundef i32 @_Z2f2v() 
+
+; Function Attrs: mustprogress nounwind
+define linkonce_odr dso_local void @_ZNSt8functionIFivEE4swapERS1_(ptr noundef nonnull align 4 dereferenceable(16) %this, ptr noundef nonnull align 4 dereferenceable(16) %__x) local_unnamed_addr align 2 {
+entry:
+  call void @_ZSt4swapISt9_Any_dataENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleIS4_ESt18is_move_assignableIS4_EEE5valueEvE4typeERS4_SD_(ptr noundef nonnull align 4 dereferenceable(8) %this, ptr noundef nonnull align 4 dereferenceable(8) %__x) 
+  %_M_manager = getelementptr inbounds %"class.std::_Function_base", ptr %this, i32 0, i32 1
+  %_M_manager3 = getelementptr inbounds %"class.std::_Function_base", ptr %__x, i32 0, i32 1
+  call void @_ZSt4swapIPFbRSt9_Any_dataRKS0_St18_Manager_operationEENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleISA_ESt18is_move_assignableISA_EEE5valueEvE4typeERSA_SJ_(ptr noundef nonnull align 4 dereferenceable(4) %_M_manager, ptr noundef nonnull align 4 dereferenceable(4) %_M_manager3) 
+  %_M_invoker = getelementptr inbounds %"class.std::function", ptr %this, i32 0, i32 1
+  %_M_invoker4 = getelementptr inbounds %"class.std::function", ptr %__x, i32 0, i32 1
+  call void @_ZSt4swapIPFiRKSt9_Any_dataEENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleIS8_ESt18is_move_assignableIS8_EEE5valueEvE4typeERS8_SH_(ptr noundef nonnull align 4 dereferenceable(4) %_M_invoker, ptr noundef nonnull align 4 dereferenceable(4) %_M_invoker4) 
+  ret void
+}
+
+; Function Attrs: mustprogress
+declare dso_local noundef i32 @_ZNKSt8functionIFivEEclEv(ptr noundef nonnull align 4 dereferenceable(16) %this) local_unnamed_addr align 2 
+
+declare dso_local i32 @__gxx_personality_v0(...)
+
+; Function Attrs: nounwind
+declare dso_local void @_ZNSt14_Function_baseD2Ev(ptr noundef nonnull align 4 dereferenceable(12) %this) unnamed_addr align 2 
+
+; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0(i64 immarg %0, ptr nocapture %1) 
+
+; Function Attrs: argmemonly mustprogress nocallback nofree nounwind willreturn writeonly
+declare void @llvm.memset.p0.i32(ptr nocapture writeonly %0, i8 %1, i32 %2, i1 immarg %3) 
+
+; Function Attrs: nounwind
+define linkonce_odr dso_local void @_ZNSt14_Function_baseC2Ev(ptr noundef nonnull align 4 dereferenceable(12) %this) unnamed_addr align 2 {
+entry:
+  store ptr null, ptr %this, align 4
+  %_M_manager = getelementptr inbounds %"class.std::_Function_base", ptr %this, i32 0, i32 1
+  store ptr null, ptr %_M_manager, align 4
+  ret void
+}
+
+; Function Attrs: mustprogress nounwind
+declare dso_local noundef zeroext i1 @_ZNSt14_Function_base13_Base_managerIPFivEE21_M_not_empty_functionIS1_EEbPT_(ptr noundef %__fp) local_unnamed_addr align 2 
+
+; Function Attrs: mustprogress nounwind
+define linkonce_odr dso_local void @_ZNSt14_Function_base13_Base_managerIPFivEE15_M_init_functorIRS1_EEvRSt9_Any_dataOT_(ptr noundef nonnull align 4 dereferenceable(8) %__functor, ptr noundef nonnull %__f) local_unnamed_addr align 2 personality ptr @__gxx_personality_v0 {
+entry:
+  call void @_ZNSt14_Function_base13_Base_managerIPFivEE9_M_createIRS1_EEvRSt9_Any_dataOT_St17integral_constantIbLb1EE(ptr noundef nonnull align 4 dereferenceable(8) %__functor, ptr noundef nonnull %__f)
+  ret void
+}
+
+; Function Attrs: mustprogress
+declare dso_local noundef i32 @_ZNSt17_Function_handlerIFivEPS0_E9_M_invokeERKSt9_Any_data(ptr noundef nonnull align 4 dereferenceable(8) %__functor) align 2 
+
+; Function Attrs: mustprogress
+declare dso_local noundef zeroext i1 @_ZNSt17_Function_handlerIFivEPS0_E10_M_managerERSt9_Any_dataRKS3_St18_Manager_operation(ptr noundef nonnull align 4 dereferenceable(8) %__dest, ptr noundef nonnull align 4 dereferenceable(8) %__source, i32 noundef %__op) align 2 
+
+; Function Attrs: mustprogress nounwind
+define linkonce_odr dso_local void @_ZNSt14_Function_base13_Base_managerIPFivEE9_M_createIRS1_EEvRSt9_Any_dataOT_St17integral_constantIbLb1EE(ptr noundef nonnull align 4 dereferenceable(8) %__dest, ptr noundef nonnull %__f) local_unnamed_addr align 2 {
+entry:
+  %call = call noundef ptr @_ZNSt9_Any_data9_M_accessEv(ptr noundef nonnull align 4 dereferenceable(8) %__dest) 
+  store ptr %__f, ptr %call, align 4
+  ret void
+}
+
+; Function Attrs: mustprogress nounwind
+define linkonce_odr dso_local noundef ptr @_ZNSt9_Any_data9_M_accessEv(ptr noundef nonnull align 4 dereferenceable(8) %this) local_unnamed_addr align 2 {
+entry:
+  ret ptr %this
+}
+
+; Function Attrs: inlinehint mustprogress nounwind
+define linkonce_odr dso_local void @_ZSt4swapISt9_Any_dataENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleIS4_ESt18is_move_assignableIS4_EEE5valueEvE4typeERS4_SD_(ptr noundef nonnull align 4 dereferenceable(8) %__a, ptr noundef nonnull align 4 dereferenceable(8) %__b) local_unnamed_addr {
+entry:
+  %0 = load i64, ptr %__a, align 4
+  %1 = load i64, ptr %__b, align 4
+  store i64 %1, ptr %__a, align 4
+  store i64 %0, ptr %__b, align 4
+  ret void
+}
+
+; Function Attrs: inlinehint mustprogress nounwind
+declare dso_local void @_ZSt4swapIPFbRSt9_Any_dataRKS0_St18_Manager_operationEENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleISA_ESt18is_move_assignableISA_EEE5valueEvE4typeERSA_SJ_(ptr noundef nonnull align 4 dereferenceable(4) %__a, ptr noundef nonnull align 4 dereferenceable(4) %__b) local_unnamed_addr 
+
+; Function Attrs: inlinehint mustprogress nounwind
+declare dso_local void @_ZSt4swapIPFiRKSt9_Any_dataEENSt9enable_ifIXsr6__and_ISt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleIS8_ESt18is_move_assignableIS8_EEE5valueEvE4typeERS8_SH_(ptr noundef nonnull align 4 dereferenceable(4) %__a, ptr noundef nonnull align 4 dereferenceable(4) %__b) local_unnamed_addr 
+
diff --git a/llvm/test/Transforms/NewGVN/no_speculative_loads_with_asan.ll b/llvm/test/Transforms/NewGVN/no_speculative_loads_with_asan.ll
index b1d71e875728473..91dfb1464b993ec 100644
--- a/llvm/test/Transforms/NewGVN/no_speculative_loads_with_asan.ll
+++ b/llvm/test/Transforms/NewGVN/no_speculative_loads_with_asan.ll
@@ -21,23 +21,25 @@ define i32 @TestNoAsan() {
 ; CHECK-NEXT:    [[TMP10:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 0, [[TMP0:%.*]] ]
 ; CHECK-NEXT:    ret i32 [[TMP10]]
 ;
-  %1 = tail call noalias ptr @_Znam(i64 2)
-  %2 = getelementptr inbounds i8, ptr %1, i64 1
-  store i8 0, ptr %2, align 1
-  store i8 0, ptr %1, align 1
-  %3 = load i16, ptr %1, align 4
-  %4 = icmp eq i16 %3, 0
-  br i1 %4, label %9, label %5
+  %1 = tail call noalias i8* @_Znam(i64 2)
+  %2 = getelementptr inbounds i8, i8* %1, i64 1
+  store i8 0, i8* %2, align 1
+  store i8 0, i8* %1, align 1
+  %3 = bitcast i8* %1 to i16*
+  %4 = load i16, i16* %3, align 4
+  %5 = icmp eq i16 %4, 0
+  br i1 %5, label %11, label %6
 
-; <label>:5                                       ; preds = %0
-  %6 = getelementptr inbounds i8, ptr %1, i64 2
-  %7 = load i16, ptr %6, align 2
-  %8 = sext i16 %7 to i32
-  br label %9
+; <label>:6                                       ; preds = %0
+  %7 = getelementptr inbounds i8, i8* %1, i64 2
+  %8 = bitcast i8* %7 to i16*
+  %9 = load i16, i16* %8, align 2
+  %10 = sext i16 %9 to i32
+  br label %11
 
-; <label>:9                                      ; preds = %0, %5
-  %10 = phi i32 [ %8, %5 ], [ 0, %0 ]
-  ret i32 %10
+; <label>:11                                      ; preds = %0, %6
+  %12 = phi i32 [ %10, %6 ], [ 0, %0 ]
+  ret i32 %12
 }
 
 define i32 @TestAsan() sanitize_address {
@@ -58,23 +60,25 @@ define i32 @TestAsan() sanitize_address {
 ; CHECK-NEXT:    [[TMP10:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 0, [[TMP0:%.*]] ]
 ; CHECK-NEXT:    ret i32 [[TMP10]]
 ;
-  %1 = tail call noalias ptr @_Znam(i64 2)
-  %2 = getelementptr inbounds i8, ptr %1, i64 1
-  store i8 0, ptr %2, align 1
-  store i8 0, ptr %1, align 1
-  %3 = load i16, ptr %1, align 4
-  %4 = icmp eq i16 %3, 0
-  br i1 %4, label %9, label %5
+  %1 = tail call noalias i8* @_Znam(i64 2)
+  %2 = getelementptr inbounds i8, i8* %1, i64 1
+  store i8 0, i8* %2, align 1
+  store i8 0, i8* %1, align 1
+  %3 = bitcast i8* %1 to i16*
+  %4 = load i16, i16* %3, align 4
+  %5 = icmp eq i16 %4, 0
+  br i1 %5, label %11, label %6
 
-; <label>:5                                       ; preds = %0
-  %6 = getelementptr inbounds i8, ptr %1, i64 2
-  %7 = load i16, ptr %6, align 2
-  %8 = sext i16 %7 to i32
-  br label %9
+; <label>:6                                       ; preds = %0
+  %7 = getelementptr inbounds i8, i8* %1, i64 2
+  %8 = bitcast i8* %7 to i16*
+  %9 = load i16, i16* %8, align 2
+  %10 = sext i16 %9 to i32
+  br label %11
 
-; <label>:9                                      ; preds = %0, %5
-  %10 = phi i32 [ %8, %5 ], [ 0, %0 ]
-  ret i32 %10
+; <label>:11                                      ; preds = %0, %6
+  %12 = phi i32 [ %10, %6 ], [ 0, %0 ]
+  ret i32 %12
 }
 
 define i32 @TestHWAsan() sanitize_hwaddress {
@@ -95,21 +99,23 @@ define i32 @TestHWAsan() sanitize_hwaddress {
 ; CHECK-NEXT:    [[TMP10:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 0, [[TMP0:%.*]] ]
 ; CHECK-NEXT:    ret i32 [[TMP10]]
 ;
-  %1 = tail call noalias ptr @_Znam(i64 2)
-  %2 = getelementptr inbounds i8, ptr %1, i64 1
-  store i8 0, ptr %2, align 1
-  store i8 0, ptr %1, align 1
-  %3 = load i16, ptr %1, align 4
-  %4 = icmp eq i16 %3, 0
-  br i1 %4, label %9, label %5
+  %1 = tail call noalias i8* @_Znam(i64 2)
+  %2 = getelementptr inbounds i8, i8* %1, i64 1
+  store i8 0, i8* %2, align 1
+  store i8 0, i8* %1, align 1
+  %3 = bitcast i8* %1 to i16*
+  %4 = load i16, i16* %3, align 4
+  %5 = icmp eq i16 %4, 0
+  br i1 %5, label %11, label %6
 
-; <label>:5                                       ; preds = %0
-  %6 = getelementptr inbounds i8, ptr %1, i64 2
-  %7 = load i16, ptr %6, align 2
-  %8 = sext i16 %7 to i32
-  br label %9
+; <label>:6                                       ; preds = %0
+  %7 = getelementptr inbounds i8, i8* %1, i64 2
+  %8 = bitcast i8* %7 to i16*
+  %9 = load i16, i16* %8, align 2
+  %10 = sext i16 %9 to i32
+  br label %11
 
-; <label>:9                                      ; preds = %0, %5
-  %10 = phi i32 [ %8, %5 ], [ 0, %0 ]
-  ret i32 %10
+; <label>:11                                      ; preds = %0, %6
+  %12 = phi i32 [ %10, %6 ], [ 0, %0 ]
+  ret i32 %12
 }



More information about the llvm-commits mailing list