[llvm] 923727e - [ConstantFold] Extract GEP of GEP fold (NFCI)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 23 14:49:48 PDT 2021
Author: Nikita Popov
Date: 2021-07-23T23:49:40+02:00
New Revision: 923727e8bedac0257f5603ca3a1032737b01be96
URL: https://github.com/llvm/llvm-project/commit/923727e8bedac0257f5603ca3a1032737b01be96
DIFF: https://github.com/llvm/llvm-project/commit/923727e8bedac0257f5603ca3a1032737b01be96.diff
LOG: [ConstantFold] Extract GEP of GEP fold (NFCI)
Move this fold into a separate function and clean up the control
flow a bit.
Added:
Modified:
llvm/lib/IR/ConstantFold.cpp
Removed:
################################################################################
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index e2925784953b..ca1478787606 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -2344,6 +2344,94 @@ static bool isIndexInRangeOfArrayType(uint64_t NumElements,
return true;
}
+// Combine Indices - If the source pointer to this getelementptr instruction
+// is a getelementptr instruction, combine the indices of the two
+// getelementptr instructions into a single instruction.
+static Constant *foldGEPOfGEP(GEPOperator *GEP, bool InBounds,
+ ArrayRef<Value *> Idxs) {
+ Constant *Idx0 = cast<Constant>(Idxs[0]);
+ if (Idx0->isNullValue()) {
+ // Handle the simple case of a zero index.
+ SmallVector<Value*, 16> NewIndices;
+ NewIndices.reserve(Idxs.size() + GEP->getNumIndices());
+ NewIndices.append(GEP->idx_begin(), GEP->idx_end());
+ NewIndices.append(Idxs.begin() + 1, Idxs.end());
+ return ConstantExpr::getGetElementPtr(
+ GEP->getSourceElementType(), cast<Constant>(GEP->getPointerOperand()),
+ NewIndices, InBounds && GEP->isInBounds(), GEP->getInRangeIndex());
+ }
+
+ gep_type_iterator LastI = gep_type_end(GEP);
+ for (gep_type_iterator I = gep_type_begin(GEP), E = gep_type_end(GEP);
+ I != E; ++I)
+ LastI = I;
+
+ // We cannot combine indices if doing so would take us outside of an
+ // array or vector. Doing otherwise could trick us if we evaluated such a
+ // GEP as part of a load.
+ //
+ // e.g. Consider if the original GEP was:
+ // i8* getelementptr ({ [2 x i8], i32, i8, [3 x i8] }* @main.c,
+ // i32 0, i32 0, i64 0)
+ //
+ // If we then tried to offset it by '8' to get to the third element,
+ // an i8, we should *not* get:
+ // i8* getelementptr ({ [2 x i8], i32, i8, [3 x i8] }* @main.c,
+ // i32 0, i32 0, i64 8)
+ //
+ // This GEP tries to index array element '8 which runs out-of-bounds.
+ // Subsequent evaluation would get confused and produce erroneous results.
+ //
+ // The following prohibits such a GEP from being formed by checking to see
+ // if the index is in-range with respect to an array.
+ if (!LastI.isSequential())
+ return nullptr;
+ ConstantInt *CI = dyn_cast<ConstantInt>(Idx0);
+ if (!CI)
+ return nullptr;
+ if (LastI.isBoundedSequential() &&
+ !isIndexInRangeOfArrayType(LastI.getSequentialNumElements(), CI))
+ return nullptr;
+
+ // TODO: This code may be extended to handle vectors as well.
+ auto *LastIdx = cast<Constant>(GEP->getOperand(GEP->getNumOperands()-1));
+ Type *LastIdxTy = LastIdx->getType();
+ if (LastIdxTy->isVectorTy())
+ return nullptr;
+
+ SmallVector<Value*, 16> NewIndices;
+ NewIndices.reserve(Idxs.size() + GEP->getNumIndices());
+ NewIndices.append(GEP->idx_begin(), GEP->idx_end() - 1);
+
+ // Add the last index of the source with the first index of the new GEP.
+ // Make sure to handle the case when they are actually
diff erent types.
+ if (LastIdxTy != Idx0->getType()) {
+ unsigned CommonExtendedWidth =
+ std::max(LastIdxTy->getIntegerBitWidth(),
+ Idx0->getType()->getIntegerBitWidth());
+ CommonExtendedWidth = std::max(CommonExtendedWidth, 64U);
+
+ Type *CommonTy =
+ Type::getIntNTy(LastIdxTy->getContext(), CommonExtendedWidth);
+ Idx0 = ConstantExpr::getSExtOrBitCast(Idx0, CommonTy);
+ LastIdx = ConstantExpr::getSExtOrBitCast(LastIdx, CommonTy);
+ }
+
+ NewIndices.push_back(ConstantExpr::get(Instruction::Add, Idx0, LastIdx));
+ NewIndices.append(Idxs.begin() + 1, Idxs.end());
+
+ // The combined GEP normally inherits its index inrange attribute from
+ // the inner GEP, but if the inner GEP's last index was adjusted by the
+ // outer GEP, any inbounds attribute on that index is invalidated.
+ Optional<unsigned> IRIndex = GEP->getInRangeIndex();
+ if (IRIndex && *IRIndex == GEP->getNumIndices() - 1)
+ IRIndex = None;
+
+ return ConstantExpr::getGetElementPtr(
+ GEP->getSourceElementType(), cast<Constant>(GEP->getPointerOperand()),
+ NewIndices, InBounds && GEP->isInBounds(), IRIndex);
+}
+
Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
bool InBounds,
Optional<unsigned> InRangeIndex,
@@ -2402,91 +2490,9 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
}
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
- // Combine Indices - If the source pointer to this getelementptr instruction
- // is a getelementptr instruction, combine the indices of the two
- // getelementptr instructions into a single instruction.
- //
- if (CE->getOpcode() == Instruction::GetElementPtr) {
- gep_type_iterator LastI = gep_type_end(CE);
- for (gep_type_iterator I = gep_type_begin(CE), E = gep_type_end(CE);
- I != E; ++I)
- LastI = I;
-
- // We cannot combine indices if doing so would take us outside of an
- // array or vector. Doing otherwise could trick us if we evaluated such a
- // GEP as part of a load.
- //
- // e.g. Consider if the original GEP was:
- // i8* getelementptr ({ [2 x i8], i32, i8, [3 x i8] }* @main.c,
- // i32 0, i32 0, i64 0)
- //
- // If we then tried to offset it by '8' to get to the third element,
- // an i8, we should *not* get:
- // i8* getelementptr ({ [2 x i8], i32, i8, [3 x i8] }* @main.c,
- // i32 0, i32 0, i64 8)
- //
- // This GEP tries to index array element '8 which runs out-of-bounds.
- // Subsequent evaluation would get confused and produce erroneous results.
- //
- // The following prohibits such a GEP from being formed by checking to see
- // if the index is in-range with respect to an array.
- // TODO: This code may be extended to handle vectors as well.
- bool PerformFold = false;
- if (Idx0->isNullValue())
- PerformFold = true;
- else if (LastI.isSequential())
- if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx0))
- PerformFold = (!LastI.isBoundedSequential() ||
- isIndexInRangeOfArrayType(
- LastI.getSequentialNumElements(), CI)) &&
- !CE->getOperand(CE->getNumOperands() - 1)
- ->getType()
- ->isVectorTy();
-
- if (PerformFold) {
- SmallVector<Value*, 16> NewIndices;
- NewIndices.reserve(Idxs.size() + CE->getNumOperands());
- NewIndices.append(CE->op_begin() + 1, CE->op_end() - 1);
-
- // Add the last index of the source with the first index of the new GEP.
- // Make sure to handle the case when they are actually
diff erent types.
- Constant *Combined = CE->getOperand(CE->getNumOperands()-1);
- // Otherwise it must be an array.
- if (!Idx0->isNullValue()) {
- Type *IdxTy = Combined->getType();
- if (IdxTy != Idx0->getType()) {
- unsigned CommonExtendedWidth =
- std::max(IdxTy->getIntegerBitWidth(),
- Idx0->getType()->getIntegerBitWidth());
- CommonExtendedWidth = std::max(CommonExtendedWidth, 64U);
-
- Type *CommonTy =
- Type::getIntNTy(IdxTy->getContext(), CommonExtendedWidth);
- Constant *C1 = ConstantExpr::getSExtOrBitCast(Idx0, CommonTy);
- Constant *C2 = ConstantExpr::getSExtOrBitCast(Combined, CommonTy);
- Combined = ConstantExpr::get(Instruction::Add, C1, C2);
- } else {
- Combined =
- ConstantExpr::get(Instruction::Add, Idx0, Combined);
- }
- }
-
- NewIndices.push_back(Combined);
- NewIndices.append(Idxs.begin() + 1, Idxs.end());
-
- // The combined GEP normally inherits its index inrange attribute from
- // the inner GEP, but if the inner GEP's last index was adjusted by the
- // outer GEP, any inbounds attribute on that index is invalidated.
- Optional<unsigned> IRIndex = cast<GEPOperator>(CE)->getInRangeIndex();
- if (IRIndex && *IRIndex == CE->getNumOperands() - 2 && !Idx0->isNullValue())
- IRIndex = None;
-
- return ConstantExpr::getGetElementPtr(
- cast<GEPOperator>(CE)->getSourceElementType(), CE->getOperand(0),
- NewIndices, InBounds && cast<GEPOperator>(CE)->isInBounds(),
- IRIndex);
- }
- }
+ if (auto *GEP = dyn_cast<GEPOperator>(CE))
+ if (Constant *C = foldGEPOfGEP(GEP, InBounds, Idxs))
+ return C;
// Attempt to fold casts to the same type away. For example, folding:
//
More information about the llvm-commits
mailing list