llvmorg-22-init-2380-gd9971be83e5d.patch (5613B)
1 From 4d453e70c33e5262531e64bf01278a6b9e4085fb Mon Sep 17 00:00:00 2001 2 From: David Green <david.green@arm.com> 3 Date: Sun, 3 Aug 2025 10:19:42 +0100 4 Subject: [PATCH 2/2] [InstCombine] Make foldCmpLoadFromIndexedGlobal more 5 resilient to non-array geps. (#150639) 6 7 My understanding is that gep [n x i8] and gep i8 can be treated 8 equivalently - the array type conveys no extra information and could be 9 removed. This goes through foldCmpLoadFromIndexedGlobal and tries to 10 make it work for non-array gep types, so long as the index type still 11 matches the array being loaded. 12 --- 13 .../InstCombine/InstCombineCompares.cpp | 29 ++++++++++++----- 14 llvm/test/Transforms/InstCombine/load-cmp.ll | 32 ++++++++++++++++++- 15 2 files changed, 52 insertions(+), 9 deletions(-) 16 17 diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp 18 index 19dd71355622..3d49c60d1648 100644 19 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp 20 +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp 21 @@ -111,10 +111,16 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal( 22 LoadInst *LI, GetElementPtrInst *GEP, GlobalVariable *GV, CmpInst &ICI, 23 ConstantInt *AndCst) { 24 if (LI->isVolatile() || LI->getType() != GEP->getResultElementType() || 25 - GV->getValueType() != GEP->getSourceElementType() || !GV->isConstant() || 26 + !GV->getValueType()->isArrayTy() || !GV->isConstant() || 27 !GV->hasDefinitiveInitializer()) 28 return nullptr; 29 30 + Type *GEPSrcEltTy = GEP->getSourceElementType(); 31 + if (GEPSrcEltTy->isArrayTy()) 32 + GEPSrcEltTy = GEPSrcEltTy->getArrayElementType(); 33 + if (GV->getValueType()->getArrayElementType() != GEPSrcEltTy) 34 + return nullptr; 35 + 36 Constant *Init = GV->getInitializer(); 37 if (!isa<ConstantArray>(Init) && !isa<ConstantDataArray>(Init)) 38 return nullptr; 39 @@ -125,12 +131,19 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal( 40 return nullptr; 41 42 // There are many forms of this optimization we can handle, for now, just do 43 - // the simple index into a single-dimensional array. 44 + // the simple index into a single-dimensional array or elements of equal size. 45 // 46 - // Require: GEP GV, 0, i {{, constant indices}} 47 - if (GEP->getNumOperands() < 3 || !isa<ConstantInt>(GEP->getOperand(1)) || 48 - !cast<ConstantInt>(GEP->getOperand(1))->isZero() || 49 - isa<Constant>(GEP->getOperand(2))) 50 + // Require: GEP [n x i8] GV, 0, Idx {{, constant indices}} 51 + // Or: GEP i8 GV, Idx 52 + 53 + unsigned GEPIdxOp = 1; 54 + if (GEP->getSourceElementType()->isArrayTy()) { 55 + GEPIdxOp = 2; 56 + if (!match(GEP->getOperand(1), m_ZeroInt())) 57 + return nullptr; 58 + } 59 + if (GEP->getNumOperands() < GEPIdxOp + 1 || 60 + isa<Constant>(GEP->getOperand(GEPIdxOp))) 61 return nullptr; 62 63 // Check that indices after the variable are constants and in-range for the 64 @@ -139,7 +152,7 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal( 65 SmallVector<unsigned, 4> LaterIndices; 66 67 Type *EltTy = Init->getType()->getArrayElementType(); 68 - for (unsigned i = 3, e = GEP->getNumOperands(); i != e; ++i) { 69 + for (unsigned i = GEPIdxOp + 1, e = GEP->getNumOperands(); i != e; ++i) { 70 ConstantInt *Idx = dyn_cast<ConstantInt>(GEP->getOperand(i)); 71 if (!Idx) 72 return nullptr; // Variable index. 73 @@ -161,7 +174,7 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal( 74 LaterIndices.push_back(IdxVal); 75 } 76 77 - Value *Idx = GEP->getOperand(2); 78 + Value *Idx = GEP->getOperand(GEPIdxOp); 79 // If the index type is non-canonical, wait for it to be canonicalized. 80 if (Idx->getType() != DL.getIndexType(GEP->getType())) 81 return nullptr; 82 diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll 83 index 12be81b8f815..485da6d2aaec 100644 84 --- a/llvm/test/Transforms/InstCombine/load-cmp.ll 85 +++ b/llvm/test/Transforms/InstCombine/load-cmp.ll 86 @@ -68,7 +68,6 @@ define i1 @test1_noinbounds_as1(i32 %x) { 87 %q = load i16, ptr addrspace(1) %p 88 %r = icmp eq i16 %q, 0 89 ret i1 %r 90 - 91 } 92 93 define i1 @test1_noinbounds_as2(i64 %x) { 94 @@ -81,7 +80,17 @@ define i1 @test1_noinbounds_as2(i64 %x) { 95 %q = load i16, ptr addrspace(2) %p 96 %r = icmp eq i16 %q, 0 97 ret i1 %r 98 +} 99 100 +define i1 @test1_noarrayty(i32 %X) { 101 +; CHECK-LABEL: @test1_noarrayty( 102 +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[X:%.*]], 9 103 +; CHECK-NEXT: ret i1 [[R]] 104 +; 105 + %P = getelementptr inbounds i16, ptr @G16, i32 %X 106 + %Q = load i16, ptr %P 107 + %R = icmp eq i16 %Q, 0 108 + ret i1 %R 109 } 110 111 define i1 @test2(i32 %X) { 112 @@ -104,7 +113,17 @@ define i1 @test3(i32 %X) { 113 %Q = load double, ptr %P 114 %R = fcmp oeq double %Q, 1.0 115 ret i1 %R 116 +} 117 118 +define i1 @test3_noarrayty(i32 %X) { 119 +; CHECK-LABEL: @test3_noarrayty( 120 +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[X:%.*]], 1 121 +; CHECK-NEXT: ret i1 [[R]] 122 +; 123 + %P = getelementptr inbounds double, ptr @GD, i32 %X 124 + %Q = load double, ptr %P 125 + %R = fcmp oeq double %Q, 1.0 126 + ret i1 %R 127 } 128 129 define i1 @test4(i32 %X) { 130 @@ -333,6 +352,17 @@ define i1 @test10_struct_arr_noinbounds_i64(i64 %x) { 131 ret i1 %r 132 } 133 134 +define i1 @test10_struct_arr_noarrayty(i32 %x) { 135 +; CHECK-LABEL: @test10_struct_arr_noarrayty( 136 +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[X:%.*]], 1 137 +; CHECK-NEXT: ret i1 [[R]] 138 +; 139 + %p = getelementptr inbounds %Foo, ptr @GStructArr, i32 %x, i32 2 140 + %q = load i32, ptr %p 141 + %r = icmp eq i32 %q, 9 142 + ret i1 %r 143 +} 144 + 145 @table = internal constant [2 x ptr] [ptr @g, ptr getelementptr (i8, ptr @g, i64 4)], align 16 146 @g = external global [2 x i32] 147 148 -- 149 2.51.0