diff options
author | Martin Sebor <msebor@redhat.com> | 2022-06-28 15:04:26 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2022-06-28 15:58:42 -0600 |
commit | e263a7670e28d880ec45971f91fa88de01fc51e1 (patch) | |
tree | b70459718d8690409cc62b981280430317b9b697 /llvm/lib/Analysis/ValueTracking.cpp | |
parent | a145a32544a8d04864d9f392e71887f8609206c2 (diff) | |
download | llvm-e263a7670e28d880ec45971f91fa88de01fc51e1.zip llvm-e263a7670e28d880ec45971f91fa88de01fc51e1.tar.gz llvm-e263a7670e28d880ec45971f91fa88de01fc51e1.tar.bz2 |
[InstCombine] Look through more casts when folding memchr and memcmp
Enhance getConstantDataArrayInfo to let the memchr and memcmp library
call folders look through arbitrarily long sequences of bitcast and
GEP instructions.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D128364
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 73 |
1 files changed, 34 insertions, 39 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 801167f..05d5e47 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4187,45 +4187,30 @@ bool llvm::getConstantDataArrayInfo(const Value *V, unsigned ElementSize, uint64_t Offset) { assert(V); - // Look through bitcast instructions and geps. - V = V->stripPointerCasts(); - - // If the value is a GEP instruction or constant expression, treat it as an - // offset. - if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) { - // Fail if the first GEP operand is not a constant zero and we're - // not indexing into the initializer. - const ConstantInt *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1)); - if (!FirstIdx || !FirstIdx->isZero()) - return false; + // Drill down into the pointer expression V, ignoring any intervening + // casts, and determine the identity of the object it references along + // with the cumulative byte offset into it. + const GlobalVariable *GV = + dyn_cast<GlobalVariable>(getUnderlyingObject(V)); + if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer()) + // Fail if V is not based on constant global object. + return false; - Value *Op0 = GEP->getOperand(0); - const GlobalVariable *GV = dyn_cast<GlobalVariable>(Op0); - if (!GV) - return false; + const DataLayout &DL = GV->getParent()->getDataLayout(); + APInt Off(DL.getIndexTypeSizeInBits(V->getType()), 0); - // Fail if the offset into the initializer is not constant. - const DataLayout &DL = GV->getParent()->getDataLayout(); - APInt Off(DL.getIndexSizeInBits(GEP->getPointerAddressSpace()), 0); - if (!GEP->accumulateConstantOffset(DL, Off)) - return false; + if (GV != V->stripAndAccumulateConstantOffsets(DL, Off, + /*AllowNonInbounds*/ true)) + // Fail if a constant offset could not be determined. + return false; + uint64_t StartIdx = Off.getLimitedValue(); + if (StartIdx == UINT64_MAX) // Fail if the constant offset is excessive. - uint64_t StartIdx = Off.getLimitedValue(); - if (StartIdx == UINT64_MAX) - return false; - - return getConstantDataArrayInfo(Op0, Slice, ElementSize, StartIdx + Offset); - } - - // The GEP instruction, constant or instruction, must reference a global - // variable that is a constant and is initialized. The referenced constant - // initializer is the array that we'll use for optimization. - const GlobalVariable *GV = dyn_cast<GlobalVariable>(V); - if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer()) return false; - const DataLayout &DL = GV->getParent()->getDataLayout(); + Offset += StartIdx; + ConstantDataArray *Array = nullptr; ArrayType *ArrayTy = nullptr; @@ -4233,14 +4218,14 @@ bool llvm::getConstantDataArrayInfo(const Value *V, Type *GVTy = GV->getValueType(); uint64_t SizeInBytes = DL.getTypeStoreSize(GVTy).getFixedSize(); uint64_t Length = SizeInBytes / (ElementSize / 8); - if (Length <= Offset) - // Bail on undersized constants to let sanitizers detect library - // calls with them as arguments. - return false; Slice.Array = nullptr; Slice.Offset = 0; - Slice.Length = Length - Offset; + // Return an empty Slice for undersized constants to let callers + // transform even undefined library calls into simpler, well-defined + // expressions. This is preferable to making the calls although it + // prevents sanitizers from detecting such calls. + Slice.Length = Length < Offset ? 0 : Length - Offset; return true; } @@ -4292,6 +4277,12 @@ bool llvm::getConstantStringInfo(const Value *V, StringRef &Str, if (Slice.Array == nullptr) { if (TrimAtNul) { + // Return a nul-terminated string even for an empty Slice. This is + // safe because all existing SimplifyLibcalls callers require string + // arguments and the behavior of the functions they fold is undefined + // otherwise. Folding the calls this way is preferable to making + // the undefined library calls, even though it prevents sanitizers + // from reporting such calls. Str = StringRef(); return true; } @@ -4371,9 +4362,13 @@ static uint64_t GetStringLengthH(const Value *V, return 0; if (Slice.Array == nullptr) + // Zeroinitializer (including an empty one). return 1; - // Search for nul characters + // Search for the first nul character. Return a conservative result even + // when there is no nul. This is safe since otherwise the string function + // being folded such as strlen is undefined, and can be preferable to + // making the undefined library call. unsigned NullIndex = 0; for (unsigned E = Slice.Length; NullIndex < E; ++NullIndex) { if (Slice.Array->getElementAsInteger(Slice.Offset + NullIndex) == 0) |