From b8dc2c8dee4fa5f3cd5a129d099817d6ae0d065c Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 28 Dec 2023 01:23:08 +0800 Subject: [PATCH 1/3] [InstCombine] Add pre-commit tests. NFC. --- .../Transforms/InstCombine/getelementptr.ll | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll index bc7fdc9352df6..0ecf166b84da6 100644 --- a/llvm/test/Transforms/InstCombine/getelementptr.ll +++ b/llvm/test/Transforms/InstCombine/getelementptr.ll @@ -1453,4 +1453,92 @@ 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: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; 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: [[INDEX:%.*]] = sdiv exact <2 x i64> [[OFF:%.*]], +; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], <2 x ptr> [[P:%.*]], <2 x i64> [[INDEX]] +; 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: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; 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: [[INDEX:%.*]] = ashr exact i64 [[OFF:%.*]], 2 +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]] +; 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} From 8c4a86cd8ce457a0cee3acdf74e5e359255015bd Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 28 Dec 2023 01:32:52 +0800 Subject: [PATCH 2/3] [InstCombine] Canonicalize `gep T* X, V / sizeof(T)` to `gep i8* X, V` --- .../InstCombine/InstructionCombining.cpp | 26 ++++++++++++------- .../Transforms/InstCombine/getelementptr.ll | 12 +++------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 7f5a7b666903d..fed311cec24a2 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2470,20 +2470,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { 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; - } + } else if (has_single_bit(TyAllocSize) && + match(GEP.getOperand(1), + m_Exact(m_AShr(m_Value(V), m_SpecificInt(countr_zero( + TyAllocSize)))))) + Matched = true; + else if (match(GEP.getOperand(1), + m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize))))) + 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 @@ -2494,6 +2492,14 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) && getUnderlyingObject(X) == getUnderlyingObject(Y)) return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType); + + // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V) + if (Matched && TyAllocSize != 1) { + GetElementPtrInst *NewGEP = GetElementPtrInst::Create( + Builder.getInt8Ty(), GEP.getPointerOperand(), V); + NewGEP->setIsInBounds(GEP.isInBounds()); + return NewGEP; + } } } // 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 0ecf166b84da6..7d67f2583aa24 100644 --- a/llvm/test/Transforms/InstCombine/getelementptr.ll +++ b/llvm/test/Transforms/InstCombine/getelementptr.ll @@ -1455,8 +1455,7 @@ define ptr @const_gep_chain(ptr %p, i64 %a) { define ptr @gep_sdiv(ptr %p, i64 %off) { ; CHECK-LABEL: @gep_sdiv( -; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7 -; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]] ; CHECK-NEXT: ret ptr [[PTR]] ; %index = sdiv exact i64 %off, 7 @@ -1466,8 +1465,7 @@ define ptr @gep_sdiv(ptr %p, i64 %off) { define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) { ; CHECK-LABEL: @gep_sdiv_vec( -; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact <2 x i64> [[OFF:%.*]], -; CHECK-NEXT: [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], <2 x ptr> [[P:%.*]], <2 x i64> [[INDEX]] +; 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, @@ -1477,8 +1475,7 @@ define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) { define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) { ; CHECK-LABEL: @gep_sdiv_inbounds( -; CHECK-NEXT: [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7 -; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[OFF:%.*]] ; CHECK-NEXT: ret ptr [[PTR]] ; %index = sdiv exact i64 %off, 7 @@ -1488,8 +1485,7 @@ define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) { define ptr @gep_ashr(ptr %p, i64 %off) { ; CHECK-LABEL: @gep_ashr( -; CHECK-NEXT: [[INDEX:%.*]] = ashr exact i64 [[OFF:%.*]], 2 -; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]] ; CHECK-NEXT: ret ptr [[PTR]] ; %index = ashr exact i64 %off, 2 From 57533c1c2847f40b4ebe00a93afee2cc5a599f75 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 29 Dec 2023 01:03:28 +0800 Subject: [PATCH 3/3] [InstCombine] Do the ptrtoint transform after canonicalizing the SrcTy to i8 --- .../InstCombine/InstructionCombining.cpp | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index fed311cec24a2..df393d72a85bf 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2469,36 +2469,30 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { DL.getIndexSizeInBits(AS)) { uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue(); - bool Matched = false; - Value *V = nullptr; if (TyAllocSize == 1) { - V = GEP.getOperand(1); - Matched = true; - } else if (has_single_bit(TyAllocSize) && - match(GEP.getOperand(1), - m_Exact(m_AShr(m_Value(V), m_SpecificInt(countr_zero( - TyAllocSize)))))) - Matched = true; - else if (match(GEP.getOperand(1), - m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize))))) - 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 *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); - - // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V) - if (Matched && TyAllocSize != 1) { - 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 *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; + } } } }