https://github.com/vtjnash updated https://github.com/llvm/llvm-project/pull/143958
>From 0d309ccbde665a033976a9eaa9f84c284765825c Mon Sep 17 00:00:00 2001 From: Jameson Nash <vtjn...@gmail.com> Date: Thu, 12 Jun 2025 18:48:00 +0000 Subject: [PATCH 1/3] [instcombine] remove dead loads, such as memcpy from undef --- .../InstCombine/InstructionCombining.cpp | 66 +++++++++++++++++-- .../Transforms/InstCombine/malloc-free.ll | 6 +- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index dc2a8cb0115e7..aa7119b005013 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3217,10 +3217,12 @@ static bool isRemovableWrite(CallBase &CB, Value *UsedV, static bool isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakTrackingVH> &Users, - const TargetLibraryInfo &TLI) { + const TargetLibraryInfo &TLI, + bool KnowInit) { SmallVector<Instruction*, 4> Worklist; const std::optional<StringRef> Family = getAllocationFamily(AI, &TLI); Worklist.push_back(AI); + ModRefInfo Access = KnowInit ? ModRefInfo::NoModRef : ModRefInfo::Mod; do { Instruction *PI = Worklist.pop_back_val(); @@ -3283,10 +3285,15 @@ static bool isAllocSiteRemovable(Instruction *AI, case Intrinsic::memcpy: case Intrinsic::memset: { MemIntrinsic *MI = cast<MemIntrinsic>(II); - if (MI->isVolatile() || MI->getRawDest() != PI) + if (MI->isVolatile()) return false; + // Note: this could also be ModRef, but we can still interpret that as just Mod in that case. + ModRefInfo NewAccess = MI->getRawDest() == PI ? ModRefInfo::Mod : ModRefInfo::Ref; + if ((Access & ~NewAccess) != ModRefInfo::NoModRef) + return false; + Access |= NewAccess; + } [[fallthrough]]; - } case Intrinsic::assume: case Intrinsic::invariant_start: case Intrinsic::invariant_end: @@ -3327,6 +3334,20 @@ static bool isAllocSiteRemovable(Instruction *AI, StoreInst *SI = cast<StoreInst>(I); if (SI->isVolatile() || SI->getPointerOperand() != PI) return false; + if (isRefSet(Access)) + return false; + Access |= ModRefInfo::Mod; + Users.emplace_back(I); + continue; + } + + case Instruction::Load: { + LoadInst *LI = cast<LoadInst>(I); + if (LI->isVolatile() || LI->getPointerOperand() != LI) + return false; + if (isModSet(Access)) + return false; + Access |= ModRefInfo::Ref; Users.emplace_back(I); continue; } @@ -3334,6 +3355,7 @@ static bool isAllocSiteRemovable(Instruction *AI, llvm_unreachable("missing a return?"); } } while (!Worklist.empty()); + return true; } @@ -3362,10 +3384,23 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); } - if (isAllocSiteRemovable(&MI, Users, TLI)) { + // Determine what getInitialValueOfAllocation would return without actually allocating the result. + bool KnowInitUndef = isa<AllocaInst>(MI); + bool KnowInitZero = false; + if (!KnowInitUndef) { + Constant *Init = getInitialValueOfAllocation(&MI, &TLI, Type::getInt8Ty(MI.getContext())); + if (Init) { + if (isa<UndefValue>(Init)) + KnowInitUndef = true; + else if (Init->isNullValue()) + KnowInitZero = true; + } + } + + if (isAllocSiteRemovable(&MI, Users, TLI, KnowInitZero | KnowInitUndef)) { for (unsigned i = 0, e = Users.size(); i != e; ++i) { - // Lowering all @llvm.objectsize calls first because they may - // use a bitcast/GEP of the alloca we are removing. + // Lowering all @llvm.objectsize and MTI calls first because they may use + // a bitcast/GEP of the alloca we are removing. if (!Users[i]) continue; @@ -3382,6 +3417,17 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { eraseInstFromFunction(*I); Users[i] = nullptr; // Skip examining in the next loop. } + if (auto *MTI = dyn_cast<MemTransferInst>(I)) { + if (KnowInitZero && getUnderlyingObject(MTI->getRawDest()) != &MI) { + IRBuilderBase::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(MTI); + auto *M = Builder.CreateMemSet(MTI->getRawDest(), + ConstantInt::get(Type::getInt8Ty(MI.getContext()), 0), + MTI->getLength(), + MTI->getDestAlign()); + M->copyMetadata(*MTI, LLVMContext::MD_DIAssignID); + } + } } } for (unsigned i = 0, e = Users.size(); i != e; ++i) { @@ -3404,7 +3450,13 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { } else { // Casts, GEP, or anything else: we're about to delete this instruction, // so it can not have any valid uses. - replaceInstUsesWith(*I, PoisonValue::get(I->getType())); + Constant *Replace; + if (isa<LoadInst>(I)) { + assert(KnowInitZero || KnowInitUndef); + Replace = KnowInitUndef ? UndefValue::get(I->getType()) : Constant::getNullValue(I->getType()); + } else + Replace = PoisonValue::get(I->getType()); + replaceInstUsesWith(*I, Replace); } eraseInstFromFunction(*I); } diff --git a/llvm/test/Transforms/InstCombine/malloc-free.ll b/llvm/test/Transforms/InstCombine/malloc-free.ll index 1f556821270a2..989074f97aaf6 100644 --- a/llvm/test/Transforms/InstCombine/malloc-free.ll +++ b/llvm/test/Transforms/InstCombine/malloc-free.ll @@ -133,17 +133,13 @@ define void @test4() { define void @test5(ptr %ptr, ptr %esc) { ; CHECK-LABEL: @test5( -; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) -; CHECK-NEXT: [[B:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) ; CHECK-NEXT: [[C:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) ; CHECK-NEXT: [[D:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) ; CHECK-NEXT: [[E:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) ; CHECK-NEXT: [[F:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) ; CHECK-NEXT: [[G:%.*]] = call dereferenceable_or_null(700) ptr @malloc(i32 700) -; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(32) [[PTR:%.*]], ptr noundef nonnull align 1 dereferenceable(32) [[A]], i32 32, i1 false) -; CHECK-NEXT: call void @llvm.memmove.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(32) [[PTR]], ptr noundef nonnull align 1 dereferenceable(32) [[B]], i32 32, i1 false) ; CHECK-NEXT: store ptr [[C]], ptr [[ESC:%.*]], align 4 -; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[D]], ptr [[PTR]], i32 32, i1 true) +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[D]], ptr [[PTR:%.*]], i32 32, i1 true) ; CHECK-NEXT: call void @llvm.memmove.p0.p0.i32(ptr [[E]], ptr [[PTR]], i32 32, i1 true) ; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr [[F]], i8 5, i32 32, i1 true) ; CHECK-NEXT: store volatile i8 4, ptr [[G]], align 1 >From 5acfa4e5fb7ec248807da001f51e6624edc079bb Mon Sep 17 00:00:00 2001 From: Jameson Nash <vtjn...@gmail.com> Date: Thu, 12 Jun 2025 14:54:29 -0400 Subject: [PATCH 2/3] add tests and bugfixes, with help from Claude --- clang/test/Misc/loop-opt-setup.c | 2 +- .../InstCombine/InstructionCombining.cpp | 13 +- .../Transforms/InstCombine/and-or-icmps.ll | 16 +- .../Transforms/InstCombine/apint-shift.ll | 2 +- .../InstCombine/call-cast-target.ll | 6 +- .../Transforms/InstCombine/dead-alloc-elim.ll | 140 ++++++++++++++++++ .../Transforms/InstCombine/fp-ret-bitcast.ll | 4 +- .../Transforms/InstCombine/getelementptr.ll | 16 +- .../multiple-uses-load-bitcast-select.ll | 16 -- llvm/test/Transforms/InstCombine/objsize.ll | 6 +- .../Transforms/InstCombine/select-load.ll | 14 +- .../InstCombine/shift-amount-reassociation.ll | 2 +- .../test/Transforms/InstCombine/vscale_gep.ll | 13 +- 13 files changed, 163 insertions(+), 87 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/dead-alloc-elim.ll diff --git a/clang/test/Misc/loop-opt-setup.c b/clang/test/Misc/loop-opt-setup.c index 01643e6073b56..c1c620e52200d 100644 --- a/clang/test/Misc/loop-opt-setup.c +++ b/clang/test/Misc/loop-opt-setup.c @@ -15,7 +15,7 @@ int foo(void) { // CHECK-NOT: br i1 void Helper(void) { - const int *nodes[5]; + const int *nodes[5] = {0}; int num_active = 5; while (num_active) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index aa7119b005013..83ebf9e402c06 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3310,11 +3310,6 @@ static bool isAllocSiteRemovable(Instruction *AI, } } - if (isRemovableWrite(*cast<CallBase>(I), PI, TLI)) { - Users.emplace_back(I); - continue; - } - if (Family && getFreedOperand(cast<CallBase>(I), &TLI) == PI && getAllocationFamily(I, &TLI) == Family) { Users.emplace_back(I); @@ -3328,6 +3323,12 @@ static bool isAllocSiteRemovable(Instruction *AI, continue; } + if (!isRefSet(Access) && isRemovableWrite(*cast<CallBase>(I), PI, TLI)) { + Access |= ModRefInfo::Mod; + Users.emplace_back(I); + continue; + } + return false; case Instruction::Store: { @@ -3343,7 +3344,7 @@ static bool isAllocSiteRemovable(Instruction *AI, case Instruction::Load: { LoadInst *LI = cast<LoadInst>(I); - if (LI->isVolatile() || LI->getPointerOperand() != LI) + if (LI->isVolatile() || LI->getPointerOperand() != PI) return false; if (isModSet(Access)) return false; diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll index 8824ae48417b0..26e0552886814 100644 --- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll +++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll @@ -364,20 +364,8 @@ define <2 x i1> @and_ne_with_diff_one_splatvec(<2 x i32> %x) { define void @simplify_before_foldAndOfICmps(ptr %p) { ; CHECK-LABEL: @simplify_before_foldAndOfICmps( -; CHECK-NEXT: [[A8:%.*]] = alloca i16, align 2 -; CHECK-NEXT: [[L7:%.*]] = load i16, ptr [[A8]], align 2 -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[L7]], -1 -; CHECK-NEXT: [[B11:%.*]] = zext i1 [[TMP1]] to i16 -; CHECK-NEXT: [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]] -; CHECK-NEXT: [[C7:%.*]] = icmp slt i16 [[L7]], 0 -; CHECK-NEXT: [[C3:%.*]] = and i1 [[C7]], [[C10]] -; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[C10]], true -; CHECK-NEXT: [[C18:%.*]] = or i1 [[C7]], [[TMP2]] -; CHECK-NEXT: [[TMP3:%.*]] = sext i1 [[C3]] to i64 -; CHECK-NEXT: [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP3]] -; CHECK-NEXT: store i16 [[L7]], ptr [[P:%.*]], align 2 -; CHECK-NEXT: store i1 [[C18]], ptr [[P]], align 1 -; CHECK-NEXT: store ptr [[G26]], ptr [[P]], align 8 +; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1 +; CHECK-NEXT: store ptr null, ptr [[P]], align 8 ; CHECK-NEXT: ret void ; %A8 = alloca i16 diff --git a/llvm/test/Transforms/InstCombine/apint-shift.ll b/llvm/test/Transforms/InstCombine/apint-shift.ll index 3cc530bdbd021..d81f14a30cd99 100644 --- a/llvm/test/Transforms/InstCombine/apint-shift.ll +++ b/llvm/test/Transforms/InstCombine/apint-shift.ll @@ -564,7 +564,7 @@ define i40 @test26(i40 %A) { ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9880 define i177 @ossfuzz_9880(i177 %X) { ; CHECK-LABEL: @ossfuzz_9880( -; CHECK-NEXT: ret i177 0 +; CHECK-NEXT: ret i177 poison ; %A = alloca i177 %L1 = load i177, ptr %A diff --git a/llvm/test/Transforms/InstCombine/call-cast-target.ll b/llvm/test/Transforms/InstCombine/call-cast-target.ll index 2cedc6c81d735..d18b70ff5ce9b 100644 --- a/llvm/test/Transforms/InstCombine/call-cast-target.ll +++ b/llvm/test/Transforms/InstCombine/call-cast-target.ll @@ -112,11 +112,7 @@ declare i1 @fn5(ptr byval({ i32, i32 }) align 4 %r) define i1 @test5() { ; CHECK-LABEL: define i1 @test5() { -; CHECK-NEXT: [[TMP1:%.*]] = alloca { i32, i32 }, align 4 -; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4 -; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i32 4 -; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4 -; CHECK-NEXT: [[TMP5:%.*]] = call i1 @fn5(i32 [[TMP2]], i32 [[TMP4]]) +; CHECK-NEXT: [[TMP5:%.*]] = call i1 @fn5(i32 undef, i32 undef) ; CHECK-NEXT: ret i1 [[TMP5]] ; %1 = alloca { i32, i32 }, align 4 diff --git a/llvm/test/Transforms/InstCombine/dead-alloc-elim.ll b/llvm/test/Transforms/InstCombine/dead-alloc-elim.ll new file mode 100644 index 0000000000000..b135f76f709f1 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/dead-alloc-elim.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +declare noalias ptr @calloc(i32, i32) nounwind allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc" +declare void @free(ptr) allockind("free") "alloc-family"="malloc" + +; Test load from uninitialized alloca - should be removed and replaced with undef +define i32 @test_load_uninitialized_alloca() { +; CHECK-LABEL: @test_load_uninitialized_alloca( +; CHECK-NEXT: ret i32 undef +; + %a = alloca i32 + %v = load i32, ptr %a + ret i32 %v +} + +; Test load from zero-initialized malloc - should be removed and replaced with zero +define i32 @test_load_zero_initialized_malloc() { +; CHECK-LABEL: @test_load_zero_initialized_malloc( +; CHECK-NEXT: ret i32 0 +; + %a = call ptr @calloc(i32 1, i32 4) + %v = load i32, ptr %a + call void @free(ptr %a) + ret i32 %v +} + +; Test memcpy from uninitialized source - should be removed +define void @test_memcpy_from_uninitialized_alloca(ptr %dest) { +; CHECK-LABEL: @test_memcpy_from_uninitialized_alloca( +; CHECK-NEXT: ret void +; + %src = alloca i32, align 1 + call void @llvm.memcpy.p0.p0.i32(ptr %src, ptr %src, i32 4, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 4, i1 false) + ret void +} + +; Test memcpy from zeroed source - should transform to memset with zero +define void @test_memcpy_from_uninitialized_calloc(ptr %dest) { +; CHECK-LABEL: @test_memcpy_from_uninitialized_calloc( +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(16) [[DEST:%.*]], i8 0, i32 16, i1 false) +; CHECK-NEXT: ret void +; + %src = call ptr @calloc(i32 1, i32 16) + call void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 16, i1 false) + call void @free(ptr %src) + ret void +} + +; Test mixed read/write pattern - should not be removable due to write before read +define i32 @test_write_then_read_alloca() { +; CHECK-LABEL: @test_write_then_read_alloca( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i8 42, ptr [[A]], align 1 +; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4 +; CHECK-NEXT: ret i32 [[V]] +; + %a = alloca i32 + store i8 42, ptr %a + %v = load i32, ptr %a + ret i32 %v +} + +; Test read then write pattern - should not be removable due to conflicting access +define void @test_read_then_write_alloca() { +; CHECK-LABEL: @test_read_then_write_alloca( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4 +; CHECK-NEXT: [[V8:%.*]] = trunc i32 [[V]] to i8 +; CHECK-NEXT: store i8 [[V8]], ptr [[A]], align 1 +; CHECK-NEXT: ret void +; + %a = alloca i32 + %v = load i32, ptr %a + %v8 = trunc i32 %v to i8 + store i8 %v8, ptr %a + ret void +} + +; Test load through GEP from uninitialized alloca +define i8 @test_load_gep_uninitialized_alloca() { +; CHECK-LABEL: @test_load_gep_uninitialized_alloca( +; CHECK-NEXT: ret i8 undef +; + %a = alloca [4 x i8] + %gep = getelementptr [4 x i8], ptr %a, i32 0, i32 2 + %v = load i8, ptr %gep + ret i8 %v +} + +; Test load through bitcast from uninitialized alloca +define i16 @test_load_bitcast_uninitialized_alloca() { +; CHECK-LABEL: @test_load_bitcast_uninitialized_alloca( +; CHECK-NEXT: ret i16 undef +; + %a = alloca i32 + %bc = bitcast ptr %a to ptr + %v = load i16, ptr %bc + ret i16 %v +} + +; Test memmove from zero-initialized malloc +define void @test_memmove_from_zero_initialized_malloc(ptr %dest) { +; CHECK-LABEL: @test_memmove_from_zero_initialized_malloc( +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(32) [[DEST:%.*]], i8 0, i32 32, i1 false) +; CHECK-NEXT: ret void +; + %src = call ptr @calloc(i32 8, i32 4) + call void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 32, i1 false) + call void @free(ptr %src) + ret void +} + +; Test multiple loads from same uninitialized alloca +define { i32, i32 } @test_multiple_loads_uninitialized_alloca() { +; CHECK-LABEL: @test_multiple_loads_uninitialized_alloca( +; CHECK-NEXT: ret { i32, i32 } undef +; + %a = alloca [2 x i32] + %gep1 = getelementptr [2 x i32], ptr %a, i32 0, i32 0 + %gep2 = getelementptr [2 x i32], ptr %a, i32 0, i32 1 + %v1 = load i32, ptr %gep1 + %v2 = load i32, ptr %gep2 + %ret = insertvalue { i32, i32 } { i32 undef, i32 poison }, i32 %v1, 0 + %ret2 = insertvalue { i32, i32 } %ret, i32 %v2, 1 + ret { i32, i32 } %ret2 +} + +; Test that volatile operations prevent removal +define i32 @test_volatile_load_prevents_removal() { +; CHECK-LABEL: @test_volatile_load_prevents_removal( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[V:%.*]] = load volatile i32, ptr [[A]], align 4 +; CHECK-NEXT: ret i32 [[V]] +; + %a = alloca i32 + %v = load volatile i32, ptr %a + ret i32 %v +} diff --git a/llvm/test/Transforms/InstCombine/fp-ret-bitcast.ll b/llvm/test/Transforms/InstCombine/fp-ret-bitcast.ll index 15eb3e15ea44a..12a554081ca79 100644 --- a/llvm/test/Transforms/InstCombine/fp-ret-bitcast.ll +++ b/llvm/test/Transforms/InstCombine/fp-ret-bitcast.ll @@ -15,10 +15,8 @@ target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:1 define void @bork() nounwind { ; CHECK-LABEL: @bork( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[COLOR:%.*]] = alloca ptr, align 8 -; CHECK-NEXT: [[TMP103:%.*]] = load ptr, ptr [[COLOR]], align 4 ; CHECK-NEXT: [[TMP105:%.*]] = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_81", align 4 -; CHECK-NEXT: [[TMP107:%.*]] = call float @objc_msgSend_fpret(ptr [[TMP103]], ptr [[TMP105]]) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: [[TMP107:%.*]] = call float @objc_msgSend_fpret(ptr undef, ptr [[TMP105]]) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll index 61236df80bfa6..19466e48fb73c 100644 --- a/llvm/test/Transforms/InstCombine/getelementptr.ll +++ b/llvm/test/Transforms/InstCombine/getelementptr.ll @@ -582,9 +582,7 @@ define i32 @test20_as1(ptr addrspace(1) %P, i32 %A, i32 %B) { define i32 @test21() { ; CHECK-LABEL: @test21( -; CHECK-NEXT: [[PBOB1:%.*]] = alloca [[INTSTRUCT:%.*]], align 8 -; CHECK-NEXT: [[RVAL:%.*]] = load i32, ptr [[PBOB1]], align 4 -; CHECK-NEXT: ret i32 [[RVAL]] +; CHECK-NEXT: ret i32 undef ; %pbob1 = alloca %intstruct %pbob2 = getelementptr %intstruct, ptr %pbob1 @@ -657,11 +655,6 @@ define i1 @test26(ptr %arr) { define i32 @test27(ptr %to, ptr %from) { ; CHECK-LABEL: @test27( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[FROM_ADDR:%.*]] = alloca ptr, align 8 -; CHECK-NEXT: [[T344:%.*]] = load ptr, ptr [[FROM_ADDR]], align 8 -; CHECK-NEXT: [[T348:%.*]] = getelementptr i8, ptr [[T344]], i64 24 -; CHECK-NEXT: [[T351:%.*]] = load i32, ptr [[T348]], align 8 -; CHECK-NEXT: [[T360:%.*]] = call i32 asm sideeffect "...", "=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"(i32 [[T351]], ptr elementtype([[STRUCT___LARGE_STRUCT:%.*]]) null, i32 -14, i32 0) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: unreachable ; entry: @@ -685,7 +678,7 @@ define i32 @test28() nounwind { ; CHECK-LABEL: @test28( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ORIENTATIONS:%.*]] = alloca [1 x [1 x %struct.x]], align 8 -; CHECK-NEXT: [[T3:%.*]] = call i32 @puts(ptr noundef nonnull dereferenceable(1) @.str) #[[ATTR0]] +; CHECK-NEXT: [[T3:%.*]] = call i32 @puts(ptr noundef nonnull dereferenceable(1) @.str) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: [[T45:%.*]] = getelementptr inbounds nuw i8, ptr [[ORIENTATIONS]], i64 1 ; CHECK-NEXT: br label [[BB10:%.*]] ; CHECK: bb10: @@ -1345,10 +1338,7 @@ declare noalias ptr @malloc(i64) nounwind allockind("alloc,uninitialized") alloc define i32 @test_gep_bitcast_malloc(ptr %a) { ; CHECK-LABEL: @test_gep_bitcast_malloc( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = call noalias dereferenceable_or_null(16) ptr @malloc(i64 16) -; CHECK-NEXT: [[G3:%.*]] = getelementptr i8, ptr [[CALL]], i64 12 -; CHECK-NEXT: [[A_C:%.*]] = load i32, ptr [[G3]], align 4 -; CHECK-NEXT: ret i32 [[A_C]] +; CHECK-NEXT: ret i32 undef ; entry: %call = call noalias ptr @malloc(i64 16) #2 diff --git a/llvm/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll b/llvm/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll index 38fca0314ae11..a0f4f571a4b93 100644 --- a/llvm/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll +++ b/llvm/test/Transforms/InstCombine/multiple-uses-load-bitcast-select.ll @@ -3,14 +3,6 @@ define void @PR35618(ptr %st1, ptr %st2) { ; CHECK-LABEL: @PR35618( -; CHECK-NEXT: [[Y1:%.*]] = alloca double, align 8 -; CHECK-NEXT: [[Z1:%.*]] = alloca double, align 8 -; CHECK-NEXT: [[LD1:%.*]] = load double, ptr [[Y1]], align 8 -; CHECK-NEXT: [[LD2:%.*]] = load double, ptr [[Z1]], align 8 -; CHECK-NEXT: [[TMP:%.*]] = fcmp olt double [[LD1]], [[LD2]] -; CHECK-NEXT: [[TMP12_V:%.*]] = select i1 [[TMP]], double [[LD1]], double [[LD2]] -; CHECK-NEXT: store double [[TMP12_V]], ptr [[ST1:%.*]], align 8 -; CHECK-NEXT: store double [[TMP12_V]], ptr [[ST2:%.*]], align 8 ; CHECK-NEXT: ret void ; %y1 = alloca double @@ -27,14 +19,6 @@ define void @PR35618(ptr %st1, ptr %st2) { define void @PR35618_asan(ptr %st1, ptr %st2) sanitize_address { ; CHECK-LABEL: @PR35618_asan( -; CHECK-NEXT: [[Y1:%.*]] = alloca double, align 8 -; CHECK-NEXT: [[Z1:%.*]] = alloca double, align 8 -; CHECK-NEXT: [[LD1:%.*]] = load double, ptr [[Y1]], align 8 -; CHECK-NEXT: [[LD2:%.*]] = load double, ptr [[Z1]], align 8 -; CHECK-NEXT: [[TMP:%.*]] = fcmp olt double [[LD1]], [[LD2]] -; CHECK-NEXT: [[TMP12_V:%.*]] = select i1 [[TMP]], double [[LD1]], double [[LD2]] -; CHECK-NEXT: store double [[TMP12_V]], ptr [[ST1:%.*]], align 8 -; CHECK-NEXT: store double [[TMP12_V]], ptr [[ST2:%.*]], align 8 ; CHECK-NEXT: ret void ; %y1 = alloca double diff --git a/llvm/test/Transforms/InstCombine/objsize.ll b/llvm/test/Transforms/InstCombine/objsize.ll index 1c33412303c19..f113616a478ab 100644 --- a/llvm/test/Transforms/InstCombine/objsize.ll +++ b/llvm/test/Transforms/InstCombine/objsize.ll @@ -17,13 +17,11 @@ define i32 @foo() nounwind { define ptr @bar() nounwind { ; CHECK-LABEL: @bar( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[RETVAL:%.*]] = alloca ptr, align 4 ; CHECK-NEXT: br i1 true, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[RETVAL]], align 4 -; CHECK-NEXT: ret ptr [[TMP0]] +; CHECK-NEXT: ret ptr undef ; CHECK: cond.false: -; CHECK-NEXT: ret ptr poison +; CHECK-NEXT: ret ptr undef ; entry: %retval = alloca ptr diff --git a/llvm/test/Transforms/InstCombine/select-load.ll b/llvm/test/Transforms/InstCombine/select-load.ll index 36883423aea36..6012452a48da9 100644 --- a/llvm/test/Transforms/InstCombine/select-load.ll +++ b/llvm/test/Transforms/InstCombine/select-load.ll @@ -7,12 +7,7 @@ target triple = "x86_64-grtev4-linux-gnu" define i32 @test_plain(i1 %f) { ; CHECK-LABEL: @test_plain( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 8 -; CHECK-NEXT: [[B:%.*]] = alloca i32, align 8 -; CHECK-NEXT: [[A_VAL:%.*]] = load i32, ptr [[A]], align 8 -; CHECK-NEXT: [[B_VAL:%.*]] = load i32, ptr [[B]], align 8 -; CHECK-NEXT: [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]] -; CHECK-NEXT: ret i32 [[L]] +; CHECK-NEXT: ret i32 undef ; entry: %a = alloca i32, align 8 @@ -85,12 +80,7 @@ entry: define i32 @test_msan(i1 %f) sanitize_memory { ; CHECK-LABEL: @test_msan( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[A:%.*]] = alloca i32, align 8 -; CHECK-NEXT: [[B:%.*]] = alloca i32, align 8 -; CHECK-NEXT: [[A_VAL:%.*]] = load i32, ptr [[A]], align 8 -; CHECK-NEXT: [[B_VAL:%.*]] = load i32, ptr [[B]], align 8 -; CHECK-NEXT: [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]] -; CHECK-NEXT: ret i32 [[L]] +; CHECK-NEXT: ret i32 undef ; entry: %a = alloca i32, align 8 diff --git a/llvm/test/Transforms/InstCombine/shift-amount-reassociation.ll b/llvm/test/Transforms/InstCombine/shift-amount-reassociation.ll index b4c606f037d56..f251dc282f4ca 100644 --- a/llvm/test/Transforms/InstCombine/shift-amount-reassociation.ll +++ b/llvm/test/Transforms/InstCombine/shift-amount-reassociation.ll @@ -158,7 +158,7 @@ define i32 @t11_shl_nsw_flag_preservation(i32 %x, i32 %y) { @X = external global i32 define i64 @constantexpr() { ; CHECK-LABEL: @constantexpr( -; CHECK-NEXT: ret i64 0 +; CHECK-NEXT: ret i64 poison ; %A = alloca i64 %L = load i64, ptr %A diff --git a/llvm/test/Transforms/InstCombine/vscale_gep.ll b/llvm/test/Transforms/InstCombine/vscale_gep.ll index 371ee71e45f23..2f5e2a074ea5f 100644 --- a/llvm/test/Transforms/InstCombine/vscale_gep.ll +++ b/llvm/test/Transforms/InstCombine/vscale_gep.ll @@ -43,10 +43,7 @@ define void @gep_bitcast(ptr %p) { ; This test is to verify 'inbounds' is added when it's valid to accumulate constant offset. define i32 @gep_alloca_inbounds_vscale_zero() { ; CHECK-LABEL: @gep_alloca_inbounds_vscale_zero( -; CHECK-NEXT: [[A:%.*]] = alloca <vscale x 4 x i32>, align 16 -; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8 -; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[TMP]], align 4 -; CHECK-NEXT: ret i32 [[LOAD]] +; CHECK-NEXT: ret i32 undef ; %a = alloca <vscale x 4 x i32> %tmp = getelementptr <vscale x 4 x i32>, ptr %a, i32 0, i32 2 @@ -57,13 +54,7 @@ define i32 @gep_alloca_inbounds_vscale_zero() { ; This test is to verify 'inbounds' is not added when a constant offset can not be determined at compile-time. define i32 @gep_alloca_inbounds_vscale_nonzero() { ; CHECK-LABEL: @gep_alloca_inbounds_vscale_nonzero( -; CHECK-NEXT: [[A:%.*]] = alloca <vscale x 4 x i32>, align 16 -; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64() -; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 4 -; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[A]], i64 [[TMP2]] -; CHECK-NEXT: [[TMP:%.*]] = getelementptr i8, ptr [[TMP3]], i64 8 -; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[TMP]], align 4 -; CHECK-NEXT: ret i32 [[LOAD]] +; CHECK-NEXT: ret i32 undef ; %a = alloca <vscale x 4 x i32> %tmp = getelementptr <vscale x 4 x i32>, ptr %a, i32 1, i32 2 >From c088c0c52080348c0c5cb6fdb52f3e9bfcb3e816 Mon Sep 17 00:00:00 2001 From: Jameson Nash <vtjn...@gmail.com> Date: Thu, 12 Jun 2025 20:43:27 +0000 Subject: [PATCH 3/3] clang-format --- .../InstCombine/InstructionCombining.cpp | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 83ebf9e402c06..f75e76f80cb0e 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3217,8 +3217,7 @@ static bool isRemovableWrite(CallBase &CB, Value *UsedV, static bool isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakTrackingVH> &Users, - const TargetLibraryInfo &TLI, - bool KnowInit) { + const TargetLibraryInfo &TLI, bool KnowInit) { SmallVector<Instruction*, 4> Worklist; const std::optional<StringRef> Family = getAllocationFamily(AI, &TLI); Worklist.push_back(AI); @@ -3287,12 +3286,14 @@ static bool isAllocSiteRemovable(Instruction *AI, MemIntrinsic *MI = cast<MemIntrinsic>(II); if (MI->isVolatile()) return false; - // Note: this could also be ModRef, but we can still interpret that as just Mod in that case. - ModRefInfo NewAccess = MI->getRawDest() == PI ? ModRefInfo::Mod : ModRefInfo::Ref; + // Note: this could also be ModRef, but we can still interpret that + // as just Mod in that case. + ModRefInfo NewAccess = + MI->getRawDest() == PI ? ModRefInfo::Mod : ModRefInfo::Ref; if ((Access & ~NewAccess) != ModRefInfo::NoModRef) return false; Access |= NewAccess; - } + } [[fallthrough]]; case Intrinsic::assume: case Intrinsic::invariant_start: @@ -3323,7 +3324,8 @@ static bool isAllocSiteRemovable(Instruction *AI, continue; } - if (!isRefSet(Access) && isRemovableWrite(*cast<CallBase>(I), PI, TLI)) { + if (!isRefSet(Access) && + isRemovableWrite(*cast<CallBase>(I), PI, TLI)) { Access |= ModRefInfo::Mod; Users.emplace_back(I); continue; @@ -3385,11 +3387,13 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); } - // Determine what getInitialValueOfAllocation would return without actually allocating the result. + // Determine what getInitialValueOfAllocation would return without actually + // allocating the result. bool KnowInitUndef = isa<AllocaInst>(MI); bool KnowInitZero = false; if (!KnowInitUndef) { - Constant *Init = getInitialValueOfAllocation(&MI, &TLI, Type::getInt8Ty(MI.getContext())); + Constant *Init = getInitialValueOfAllocation( + &MI, &TLI, Type::getInt8Ty(MI.getContext())); if (Init) { if (isa<UndefValue>(Init)) KnowInitUndef = true; @@ -3422,10 +3426,10 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { if (KnowInitZero && getUnderlyingObject(MTI->getRawDest()) != &MI) { IRBuilderBase::InsertPointGuard Guard(Builder); Builder.SetInsertPoint(MTI); - auto *M = Builder.CreateMemSet(MTI->getRawDest(), - ConstantInt::get(Type::getInt8Ty(MI.getContext()), 0), - MTI->getLength(), - MTI->getDestAlign()); + auto *M = Builder.CreateMemSet( + MTI->getRawDest(), + ConstantInt::get(Type::getInt8Ty(MI.getContext()), 0), + MTI->getLength(), MTI->getDestAlign()); M->copyMetadata(*MTI, LLVMContext::MD_DIAssignID); } } @@ -3454,7 +3458,8 @@ Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { Constant *Replace; if (isa<LoadInst>(I)) { assert(KnowInitZero || KnowInitUndef); - Replace = KnowInitUndef ? UndefValue::get(I->getType()) : Constant::getNullValue(I->getType()); + Replace = KnowInitUndef ? UndefValue::get(I->getType()) + : Constant::getNullValue(I->getType()); } else Replace = PoisonValue::get(I->getType()); replaceInstUsesWith(*I, Replace); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits