diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 7f5a7b666903d..df393d72a85bf 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2469,31 +2469,31 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { DL.getIndexSizeInBits(AS)) { uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue(); - bool Matched = false; - uint64_t C; - Value *V = nullptr; if (TyAllocSize == 1) { - V = GEP.getOperand(1); - Matched = true; - } else if (match(GEP.getOperand(1), - m_AShr(m_Value(V), m_ConstantInt(C)))) { - if (TyAllocSize == 1ULL << C) - Matched = true; - } else if (match(GEP.getOperand(1), - m_SDiv(m_Value(V), m_ConstantInt(C)))) { - if (TyAllocSize == C) - Matched = true; + // Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), + // but only if both point to the same underlying object (otherwise + // provenance is not necessarily retained). + Value *X = GEP.getPointerOperand(); + Value *Y; + if (match(GEP.getOperand(1), + m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) && + getUnderlyingObject(X) == getUnderlyingObject(Y)) + return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType); + } else { + // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V) + Value *V; + if ((has_single_bit(TyAllocSize) && + match(GEP.getOperand(1), + m_Exact(m_AShr(m_Value(V), + m_SpecificInt(countr_zero(TyAllocSize)))))) || + match(GEP.getOperand(1), + m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize))))) { + GetElementPtrInst *NewGEP = GetElementPtrInst::Create( + Builder.getInt8Ty(), GEP.getPointerOperand(), V); + NewGEP->setIsInBounds(GEP.isInBounds()); + return NewGEP; + } } - - // Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), but - // only if both point to the same underlying object (otherwise provenance - // is not necessarily retained). - Value *Y; - Value *X = GEP.getOperand(0); - if (Matched && - match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) && - getUnderlyingObject(X) == getUnderlyingObject(Y)) - return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType); } } // We do not handle pointer-vector geps here. diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll index bc7fdc9352df6..7d67f2583aa24 100644 --- a/llvm/test/Transforms/InstCombine/getelementptr.ll +++ b/llvm/test/Transforms/InstCombine/getelementptr.ll @@ -1453,4 +1453,88 @@ define ptr @const_gep_chain(ptr %p, i64 %a) { ret ptr %p4 } +define ptr @gep_sdiv(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_sdiv( +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = sdiv exact i64 %off, 7 + %ptr = getelementptr %struct.C, ptr %p, i64 %index + ret ptr %ptr +} + +define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) { +; CHECK-LABEL: @gep_sdiv_vec( +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, <2 x ptr> [[P:%.*]], <2 x i64> [[OFF:%.*]] +; CHECK-NEXT: ret <2 x ptr> [[PTR]] +; + %index = sdiv exact <2 x i64> %off, + %ptr = getelementptr %struct.C, <2 x ptr> %p, <2 x i64> %index + ret <2 x ptr> %ptr +} + +define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_sdiv_inbounds( +; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[OFF:%.*]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = sdiv exact i64 %off, 7 + %ptr = getelementptr inbounds %struct.C, ptr %p, i64 %index + ret ptr %ptr +} + +define ptr @gep_ashr(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_ashr( +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = ashr exact i64 %off, 2 + %ptr = getelementptr i32, ptr %p, i64 %index + ret ptr %ptr +} + +; Negative tests + +define ptr @gep_i8(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_i8( +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %ptr = getelementptr i8, ptr %p, i64 %off + ret ptr %ptr +} + +define ptr @gep_sdiv_mismatched_size(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_sdiv_mismatched_size( +; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 20 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = sdiv exact i64 %off, 20 + %ptr = getelementptr %struct.C, ptr %p, i64 %index + ret ptr %ptr +} + +define ptr @gep_sdiv_without_exact(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_sdiv_without_exact( +; CHECK-NEXT: [[INDEX:%.*]] = sdiv i64 [[OFF:%.*]], 7 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = sdiv i64 %off, 7 + %ptr = getelementptr %struct.C, ptr %p, i64 %index + ret ptr %ptr +} + +define ptr @gep_ashr_without_exact(ptr %p, i64 %off) { +; CHECK-LABEL: @gep_ashr_without_exact( +; CHECK-NEXT: [[INDEX:%.*]] = ashr i64 [[OFF:%.*]], 2 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: ret ptr [[PTR]] +; + %index = ashr i64 %off, 2 + %ptr = getelementptr i32, ptr %p, i64 %index + ret ptr %ptr +} + !0 = !{!"branch_weights", i32 2, i32 10}