diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 40 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 3 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLToken.h | 1 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 22 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/IR/ConstantFold.cpp | 55 | ||||
-rw-r--r-- | llvm/lib/IR/ConstantFold.h | 7 | ||||
-rw-r--r-- | llvm/lib/IR/Constants.cpp | 13 |
11 files changed, 129 insertions, 57 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index ec442cedac0..69e2e8ad20f 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -718,8 +718,8 @@ Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0, Constant *Op1, /// If array indices are not pointer-sized integers, explicitly cast them so /// that they aren't implicitly casted by the getelementptr. Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops, - Type *ResultTy, const DataLayout &DL, - const TargetLibraryInfo *TLI) { + Type *ResultTy, Optional<unsigned> InRangeIndex, + const DataLayout &DL, const TargetLibraryInfo *TLI) { Type *IntPtrTy = DL.getIntPtrType(ResultTy); bool Any = false; @@ -742,7 +742,8 @@ Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops, if (!Any) return nullptr; - Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ops[0], NewIdxs); + Constant *C = ConstantExpr::getGetElementPtr( + SrcElemTy, Ops[0], NewIdxs, /*InBounds=*/false, InRangeIndex); if (Constant *Folded = ConstantFoldConstant(C, DL, TLI)) C = Folded; @@ -771,13 +772,16 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, ArrayRef<Constant *> Ops, const DataLayout &DL, const TargetLibraryInfo *TLI) { + const GEPOperator *InnermostGEP = GEP; + Type *SrcElemTy = GEP->getSourceElementType(); Type *ResElemTy = GEP->getResultElementType(); Type *ResTy = GEP->getType(); if (!SrcElemTy->isSized()) return nullptr; - if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy, DL, TLI)) + if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy, + GEP->getInRangeIndex(), DL, TLI)) return C; Constant *Ptr = Ops[0]; @@ -820,6 +824,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, // If this is a GEP of a GEP, fold it all into a single GEP. while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) { + InnermostGEP = GEP; + SmallVector<Value *, 4> NestedOps(GEP->op_begin() + 1, GEP->op_end()); // Do not try the incorporate the sub-GEP if some index is not a number. @@ -925,8 +931,23 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, if (Offset != 0) return nullptr; + // Preserve the inrange index from the innermost GEP if possible. We must + // have calculated the same indices up to and including the inrange index. + Optional<unsigned> InRangeIndex; + if (Optional<unsigned> LastIRIndex = InnermostGEP->getInRangeIndex()) + if (SrcElemTy == InnermostGEP->getSourceElementType() && + NewIdxs.size() > *LastIRIndex) { + InRangeIndex = LastIRIndex; + for (unsigned I = 0; I <= *LastIRIndex; ++I) + if (NewIdxs[I] != InnermostGEP->getOperand(I + 1)) { + InRangeIndex = None; + break; + } + } + // Create a GEP. - Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ptr, NewIdxs); + Constant *C = ConstantExpr::getGetElementPtr( + SrcElemTy, Ptr, NewIdxs, /*InBounds=*/false, InRangeIndex); assert(C->getType()->getPointerElementType() == Ty && "Computed GetElementPtr has unexpected type!"); @@ -944,8 +965,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, /// attempting to fold instructions like loads and stores, which have no /// constant expression form. /// -/// TODO: This function neither utilizes nor preserves nsw/nuw/inbounds/etc -/// information, due to only being passed an opcode and operands. Constant +/// TODO: This function neither utilizes nor preserves nsw/nuw/inbounds/inrange +/// etc information, due to only being passed an opcode and operands. Constant /// folding using this function strips this information. /// Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode, @@ -965,8 +986,9 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode, if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI)) return C; - return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(), - Ops[0], Ops.slice(1)); + return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(), Ops[0], + Ops.slice(1), GEP->isInBounds(), + GEP->getInRangeIndex()); } if (auto *CE = dyn_cast<ConstantExpr>(InstOrCE)) diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 2dc1c0a1487..2ead37198b1 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -551,6 +551,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(nsw); KEYWORD(exact); KEYWORD(inbounds); + KEYWORD(inrange); KEYWORD(align); KEYWORD(addrspace); KEYWORD(section); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 2b8d2f81011..d73818d2b86 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3175,7 +3175,9 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { return true; } - if (ParseGlobalValueVector(Elts) || + Optional<unsigned> InRangeOp; + if (ParseGlobalValueVector( + Elts, Opc == Instruction::GetElementPtr ? &InRangeOp : nullptr) || ParseToken(lltok::rparen, "expected ')' in constantexpr")) return true; @@ -3214,8 +3216,16 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { if (!GetElementPtrInst::getIndexedType(Ty, Indices)) return Error(ID.Loc, "invalid getelementptr indices"); - ID.ConstantVal = - ConstantExpr::getGetElementPtr(Ty, Elts[0], Indices, InBounds); + + if (InRangeOp) { + if (*InRangeOp == 0) + return Error(ID.Loc, + "inrange keyword may not appear on pointer operand"); + --*InRangeOp; + } + + ID.ConstantVal = ConstantExpr::getGetElementPtr(Ty, Elts[0], Indices, + InBounds, InRangeOp); } else if (Opc == Instruction::Select) { if (Elts.size() != 3) return Error(ID.Loc, "expected three operands to select"); @@ -3298,8 +3308,9 @@ bool LLParser::parseOptionalComdat(StringRef GlobalName, Comdat *&C) { /// ParseGlobalValueVector /// ::= /*empty*/ -/// ::= TypeAndValue (',' TypeAndValue)* -bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts) { +/// ::= [inrange] TypeAndValue (',' [inrange] TypeAndValue)* +bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts, + Optional<unsigned> *InRangeOp) { // Empty list. if (Lex.getKind() == lltok::rbrace || Lex.getKind() == lltok::rsquare || @@ -3307,14 +3318,14 @@ bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts) { Lex.getKind() == lltok::rparen) return false; - Constant *C; - if (ParseGlobalTypeAndValue(C)) return true; - Elts.push_back(C); + do { + if (InRangeOp && !*InRangeOp && EatIfPresent(lltok::kw_inrange)) + *InRangeOp = Elts.size(); - while (EatIfPresent(lltok::comma)) { + Constant *C; if (ParseGlobalTypeAndValue(C)) return true; Elts.push_back(C); - } + } while (EatIfPresent(lltok::comma)); return false; } diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index 479ff96bc8a..16d4e8b5baa 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -411,7 +411,8 @@ namespace llvm { bool ParseValID(ValID &ID, PerFunctionState *PFS = nullptr); bool ParseGlobalValue(Type *Ty, Constant *&V); bool ParseGlobalTypeAndValue(Constant *&V); - bool ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts); + bool ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts, + Optional<unsigned> *InRangeOp = nullptr); bool parseOptionalComdat(StringRef GlobalName, Comdat *&C); bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS); bool ParseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg, diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 555aee3ef04..a1695258bbe 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -103,6 +103,7 @@ enum Kind { kw_nsw, kw_exact, kw_inbounds, + kw_inrange, kw_align, kw_addrspace, kw_section, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 23876ffcb99..d2c2ec774c1 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3268,12 +3268,25 @@ Error BitcodeReader::parseConstants() { } break; } - case bitc::CST_CODE_CE_INBOUNDS_GEP: - case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands] + case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands] + case bitc::CST_CODE_CE_GEP: // [ty, n x operands] + case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x + // operands] unsigned OpNum = 0; Type *PointeeType = nullptr; - if (Record.size() % 2) + if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX || + Record.size() % 2) PointeeType = getTypeByID(Record[OpNum++]); + + bool InBounds = false; + Optional<unsigned> InRangeIndex; + if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) { + uint64_t Op = Record[OpNum++]; + InBounds = Op & 1; + InRangeIndex = Op >> 1; + } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) + InBounds = true; + SmallVector<Constant*, 16> Elts; while (OpNum != Record.size()) { Type *ElTy = getTypeByID(Record[OpNum++]); @@ -3294,8 +3307,7 @@ Error BitcodeReader::parseConstants() { ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end()); V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, - BitCode == - bitc::CST_CODE_CE_INBOUNDS_GEP); + InBounds, InRangeIndex); break; } case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#, opval#] diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 8de61bc0b7c..0a09b3cef91 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2217,9 +2217,12 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, case Instruction::GetElementPtr: { Code = bitc::CST_CODE_CE_GEP; const auto *GO = cast<GEPOperator>(C); - if (GO->isInBounds()) - Code = bitc::CST_CODE_CE_INBOUNDS_GEP; Record.push_back(VE.getTypeID(GO->getSourceElementType())); + if (Optional<unsigned> Idx = GO->getInRangeIndex()) { + Code = bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX; + Record.push_back((*Idx << 1) | GO->isInBounds()); + } else if (GO->isInBounds()) + Code = bitc::CST_CODE_CE_INBOUNDS_GEP; for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) { Record.push_back(VE.getTypeID(C->getOperand(i)->getType())); Record.push_back(VE.getValueID(C->getOperand(i))); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index f93739d14c7..7334c988f29 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1320,12 +1320,18 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, static_cast<CmpInst::Predicate>(CE->getPredicate())); Out << " ("; + Optional<unsigned> InRangeOp; if (const GEPOperator *GEP = dyn_cast<GEPOperator>(CE)) { TypePrinter.print(GEP->getSourceElementType(), Out); Out << ", "; + InRangeOp = GEP->getInRangeIndex(); + if (InRangeOp) + ++*InRangeOp; } for (User::const_op_iterator OI=CE->op_begin(); OI != CE->op_end(); ++OI) { + if (InRangeOp && (OI - CE->op_begin()) == *InRangeOp) + Out << "inrange "; TypePrinter.print((*OI)->getType(), Out); Out << ' '; WriteAsOperandInternal(Out, *OI, &TypePrinter, Machine, Context); diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index 7625619e02e..37bab3a0d28 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -545,7 +545,10 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, } else if (CE->getOpcode() == Instruction::GetElementPtr && // Do not fold addrspacecast (gep 0, .., 0). It might make the // addrspacecast uncanonicalized. - opc != Instruction::AddrSpaceCast) { + opc != Instruction::AddrSpaceCast && + // Do not fold bitcast (gep) with inrange index, as this loses + // information. + !cast<GEPOperator>(CE)->getInRangeIndex().hasValue()) { // If all of the indexes in the GEP are null values, there is no pointer // adjustment going on. We might as well cast the source pointer. bool isAllNull = true; @@ -2046,10 +2049,10 @@ static bool isIndexInRangeOfSequentialType(SequentialType *STy, return true; } -template<typename IndexTy> -static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, - bool inBounds, - ArrayRef<IndexTy> Idxs) { +Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, + bool InBounds, + Optional<unsigned> InRangeIndex, + ArrayRef<Value *> Idxs) { if (Idxs.empty()) return C; Constant *Idx0 = cast<Constant>(Idxs[0]); if ((Idxs.size() == 1 && Idx0->isNullValue())) @@ -2146,9 +2149,18 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, 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()); + NewIndices, InBounds && cast<GEPOperator>(CE)->isInBounds(), + IRIndex); } } @@ -2173,8 +2185,9 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, if (SrcArrayTy && DstArrayTy && SrcArrayTy->getElementType() == DstArrayTy->getElementType() && SrcPtrTy->getAddressSpace() == DstPtrTy->getAddressSpace()) - return ConstantExpr::getGetElementPtr( - SrcArrayTy, (Constant *)CE->getOperand(0), Idxs, inBounds); + return ConstantExpr::getGetElementPtr(SrcArrayTy, + (Constant *)CE->getOperand(0), + Idxs, InBounds, InRangeIndex); } } } @@ -2194,6 +2207,12 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, Unknown = true; continue; } + if (InRangeIndex && i == *InRangeIndex + 1) { + // If an index is marked inrange, we cannot apply this canonicalization to + // the following index, as that will cause the inrange index to point to + // the wrong element. + continue; + } if (isa<StructType>(Ty)) { // The verify makes sure that GEPs into a struct are in range. continue; @@ -2256,27 +2275,17 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, if (!NewIdxs.empty()) { for (unsigned i = 0, e = Idxs.size(); i != e; ++i) if (!NewIdxs[i]) NewIdxs[i] = cast<Constant>(Idxs[i]); - return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs, inBounds); + return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs, InBounds, + InRangeIndex); } // If all indices are known integers and normalized, we can do a simple // check for the "inbounds" property. - if (!Unknown && !inBounds) + if (!Unknown && !InBounds) if (auto *GV = dyn_cast<GlobalVariable>(C)) if (!GV->hasExternalWeakLinkage() && isInBoundsIndices(Idxs)) - return ConstantExpr::getInBoundsGetElementPtr(PointeeTy, C, Idxs); + return ConstantExpr::getGetElementPtr(PointeeTy, C, Idxs, + /*InBounds=*/true, InRangeIndex); return nullptr; } - -Constant *llvm::ConstantFoldGetElementPtr(Type *Ty, Constant *C, - bool inBounds, - ArrayRef<Constant *> Idxs) { - return ConstantFoldGetElementPtrImpl(Ty, C, inBounds, Idxs); -} - -Constant *llvm::ConstantFoldGetElementPtr(Type *Ty, Constant *C, - bool inBounds, - ArrayRef<Value *> Idxs) { - return ConstantFoldGetElementPtrImpl(Ty, C, inBounds, Idxs); -} diff --git a/llvm/lib/IR/ConstantFold.h b/llvm/lib/IR/ConstantFold.h index 9b0a937c84d..2d8de1132b9 100644 --- a/llvm/lib/IR/ConstantFold.h +++ b/llvm/lib/IR/ConstantFold.h @@ -19,6 +19,8 @@ #ifndef LLVM_LIB_IR_CONSTANTFOLD_H #define LLVM_LIB_IR_CONSTANTFOLD_H +#include "llvm/ADT/Optional.h" + namespace llvm { template <typename T> class ArrayRef; class Value; @@ -46,9 +48,8 @@ template <typename T> class ArrayRef; Constant *V2); Constant *ConstantFoldCompareInstruction(unsigned short predicate, Constant *C1, Constant *C2); - Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool inBounds, - ArrayRef<Constant *> Idxs); - Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool inBounds, + Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool InBounds, + Optional<unsigned> InRangeIndex, ArrayRef<Value *> Idxs); } // End llvm namespace diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index 8138f8904b8..0e5fa248caa 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -1167,7 +1167,7 @@ Constant *ConstantExpr::getWithOperands(ArrayRef<Constant *> Ops, Type *Ty, assert(SrcTy || (Ops[0]->getType() == getOperand(0)->getType())); return ConstantExpr::getGetElementPtr( SrcTy ? SrcTy : GEPO->getSourceElementType(), Ops[0], Ops.slice(1), - GEPO->isInBounds(), OnlyIfReducedTy); + GEPO->isInBounds(), GEPO->getInRangeIndex(), OnlyIfReducedTy); } case Instruction::ICmp: case Instruction::FCmp: @@ -1893,6 +1893,7 @@ Constant *ConstantExpr::getSelect(Constant *C, Constant *V1, Constant *V2, Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, ArrayRef<Value *> Idxs, bool InBounds, + Optional<unsigned> InRangeIndex, Type *OnlyIfReducedTy) { if (!Ty) Ty = cast<PointerType>(C->getType()->getScalarType())->getElementType(); @@ -1901,7 +1902,8 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, Ty == cast<PointerType>(C->getType()->getScalarType())->getContainedType(0u)); - if (Constant *FC = ConstantFoldGetElementPtr(Ty, C, InBounds, Idxs)) + if (Constant *FC = + ConstantFoldGetElementPtr(Ty, C, InBounds, InRangeIndex, Idxs)) return FC; // Fold a few common cases. // Get the result type of the getelementptr! @@ -1937,9 +1939,12 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, Idx = ConstantVector::getSplat(NumVecElts, Idx); ArgVec.push_back(Idx); } + + unsigned SubClassOptionalData = InBounds ? GEPOperator::IsInBounds : 0; + if (InRangeIndex && *InRangeIndex < 63) + SubClassOptionalData |= (*InRangeIndex + 1) << 1; const ConstantExprKeyType Key(Instruction::GetElementPtr, ArgVec, 0, - InBounds ? GEPOperator::IsInBounds : 0, None, - Ty); + SubClassOptionalData, None, Ty); LLVMContextImpl *pImpl = C->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(ReqTy, Key); |