diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
commit | b60736ec1405bb0a8dd40989f67ef4c93da068ab (patch) | |
tree | 5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /llvm/lib/IR | |
parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) | |
download | src-b60736ec1405bb0a8dd40989f67ef4c93da068ab.tar.gz src-b60736ec1405bb0a8dd40989f67ef4c93da068ab.zip |
Diffstat (limited to 'llvm/lib/IR')
51 files changed, 3443 insertions, 1736 deletions
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index fd08310316b3..69abf8769e4b 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -116,6 +116,15 @@ struct OrderMap { } // end anonymous namespace +/// Look for a value that might be wrapped as metadata, e.g. a value in a +/// metadata operand. Returns the input value as-is if it is not wrapped. +static const Value *skipMetadataWrapper(const Value *V) { + if (const auto *MAV = dyn_cast<MetadataAsValue>(V)) + if (const auto *VAM = dyn_cast<ValueAsMetadata>(MAV->getMetadata())) + return VAM->getValue(); + return V; +} + static void orderValue(const Value *V, OrderMap &OM) { if (OM.lookup(V).first) return; @@ -132,8 +141,6 @@ static void orderValue(const Value *V, OrderMap &OM) { } static OrderMap orderModule(const Module *M) { - // This needs to match the order used by ValueEnumerator::ValueEnumerator() - // and ValueEnumerator::incorporateFunction(). OrderMap OM; for (const GlobalVariable &G : M->globals()) { @@ -167,10 +174,12 @@ static OrderMap orderModule(const Module *M) { for (const BasicBlock &BB : F) { orderValue(&BB, OM); for (const Instruction &I : BB) { - for (const Value *Op : I.operands()) + for (const Value *Op : I.operands()) { + Op = skipMetadataWrapper(Op); if ((isa<Constant>(*Op) && !isa<GlobalValue>(*Op)) || isa<InlineAsm>(*Op)) orderValue(Op, OM); + } orderValue(&I, OM); } } @@ -284,9 +293,11 @@ static UseListOrderStack predictUseListOrder(const Module *M) { predictValueUseListOrder(&A, &F, OM, Stack); for (const BasicBlock &BB : F) for (const Instruction &I : BB) - for (const Value *Op : I.operands()) + for (const Value *Op : I.operands()) { + Op = skipMetadataWrapper(Op); if (isa<Constant>(*Op) || isa<InlineAsm>(*Op)) // Visit GlobalValues. predictValueUseListOrder(Op, &F, OM, Stack); + } for (const BasicBlock &BB : F) for (const Instruction &I : BB) predictValueUseListOrder(&I, &F, OM, Stack); @@ -388,6 +399,7 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::AMDGPU_PS: Out << "amdgpu_ps"; break; case CallingConv::AMDGPU_CS: Out << "amdgpu_cs"; break; case CallingConv::AMDGPU_KERNEL: Out << "amdgpu_kernel"; break; + case CallingConv::AMDGPU_Gfx: Out << "amdgpu_gfx"; break; } } @@ -597,6 +609,7 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) { case Type::LabelTyID: OS << "label"; return; case Type::MetadataTyID: OS << "metadata"; return; case Type::X86_MMXTyID: OS << "x86_mmx"; return; + case Type::X86_AMXTyID: OS << "x86_amx"; return; case Type::TokenTyID: OS << "token"; return; case Type::IntegerTyID: OS << 'i' << cast<IntegerType>(Ty)->getBitWidth(); @@ -656,9 +669,9 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) { VectorType *PTy = cast<VectorType>(Ty); ElementCount EC = PTy->getElementCount(); OS << "<"; - if (EC.Scalable) + if (EC.isScalable()) OS << "vscale x "; - OS << EC.Min << " x "; + OS << EC.getKnownMinValue() << " x "; print(PTy->getElementType(), OS); OS << '>'; return; @@ -1355,9 +1368,8 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, // "Inf" or NaN, that atof will accept, but the lexer will not. Check // that the string matches the "[-+]?[0-9]" regex. // - assert(((StrVal[0] >= '0' && StrVal[0] <= '9') || - ((StrVal[0] == '-' || StrVal[0] == '+') && - (StrVal[1] >= '0' && StrVal[1] <= '9'))) && + assert((isDigit(StrVal[0]) || ((StrVal[0] == '-' || StrVal[0] == '+') && + isDigit(StrVal[1]))) && "[-+]?[0-9] regex does not match!"); // Reparse stringized version! if (APFloat(APFloat::IEEEdouble(), StrVal).convertToDouble() == Val) { @@ -1373,9 +1385,19 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, "assuming that double is 64 bits!"); APFloat apf = APF; // Floats are represented in ASCII IR as double, convert. - if (!isDouble) + // FIXME: We should allow 32-bit hex float and remove this. + if (!isDouble) { + // A signaling NaN is quieted on conversion, so we need to recreate the + // expected value after convert (quiet bit of the payload is clear). + bool IsSNAN = apf.isSignaling(); apf.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, - &ignored); + &ignored); + if (IsSNAN) { + APInt Payload = apf.bitcastToAPInt(); + apf = APFloat::getSNaN(APFloat::IEEEdouble(), apf.isNegative(), + &Payload); + } + } Out << format_hex(apf.bitcastToAPInt().getZExtValue(), 0, /*Upper=*/true); return; } @@ -1433,6 +1455,13 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, return; } + if (const auto *Equiv = dyn_cast<DSOLocalEquivalent>(CV)) { + Out << "dso_local_equivalent "; + WriteAsOperandInternal(Out, Equiv->getGlobalValue(), &TypePrinter, Machine, + Context); + return; + } + if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV)) { Type *ETy = CA->getType()->getElementType(); Out << '['; @@ -1511,7 +1540,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, } if (isa<ConstantVector>(CV) || isa<ConstantDataVector>(CV)) { - auto *CVVTy = cast<VectorType>(CV->getType()); + auto *CVVTy = cast<FixedVectorType>(CV->getType()); Type *ETy = CVVTy->getElementType(); Out << '<'; TypePrinter.print(ETy, Out); @@ -1539,6 +1568,11 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, return; } + if (isa<PoisonValue>(CV)) { + Out << "poison"; + return; + } + if (isa<UndefValue>(CV)) { Out << "undef"; return; @@ -1889,6 +1923,57 @@ static void writeDISubrange(raw_ostream &Out, const DISubrange *N, Out << ")"; } +static void writeDIGenericSubrange(raw_ostream &Out, const DIGenericSubrange *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, + const Module *Context) { + Out << "!DIGenericSubrange("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + + auto IsConstant = [&](Metadata *Bound) -> bool { + if (auto *BE = dyn_cast_or_null<DIExpression>(Bound)) { + return BE->isSignedConstant(); + } + return false; + }; + + auto GetConstant = [&](Metadata *Bound) -> int64_t { + assert(IsConstant(Bound) && "Expected constant"); + auto *BE = dyn_cast_or_null<DIExpression>(Bound); + return static_cast<int64_t>(BE->getElement(1)); + }; + + auto *Count = N->getRawCountNode(); + if (IsConstant(Count)) + Printer.printInt("count", GetConstant(Count), + /* ShouldSkipZero */ false); + else + Printer.printMetadata("count", Count, /*ShouldSkipNull */ true); + + auto *LBound = N->getRawLowerBound(); + if (IsConstant(LBound)) + Printer.printInt("lowerBound", GetConstant(LBound), + /* ShouldSkipZero */ false); + else + Printer.printMetadata("lowerBound", LBound, /*ShouldSkipNull */ true); + + auto *UBound = N->getRawUpperBound(); + if (IsConstant(UBound)) + Printer.printInt("upperBound", GetConstant(UBound), + /* ShouldSkipZero */ false); + else + Printer.printMetadata("upperBound", UBound, /*ShouldSkipNull */ true); + + auto *Stride = N->getRawStride(); + if (IsConstant(Stride)) + Printer.printInt("stride", GetConstant(Stride), + /* ShouldSkipZero */ false); + else + Printer.printMetadata("stride", Stride, /*ShouldSkipNull */ true); + + Out << ")"; +} + static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, TypePrinting *, SlotTracker *, const Module *) { Out << "!DIEnumerator("; @@ -1916,6 +2001,23 @@ static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N, Out << ")"; } +static void writeDIStringType(raw_ostream &Out, const DIStringType *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DIStringType("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + if (N->getTag() != dwarf::DW_TAG_string_type) + Printer.printTag(N); + Printer.printString("name", N->getName()); + Printer.printMetadata("stringLength", N->getRawStringLength()); + Printer.printMetadata("stringLengthExpression", N->getRawStringLengthExp()); + Printer.printInt("size", N->getSizeInBits()); + Printer.printInt("align", N->getAlignInBits()); + Printer.printDwarfEnum("encoding", N->getEncoding(), + dwarf::AttributeEncodingString); + Out << ")"; +} + static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { @@ -1962,6 +2064,13 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N, Printer.printString("identifier", N->getIdentifier()); Printer.printMetadata("discriminator", N->getRawDiscriminator()); Printer.printMetadata("dataLocation", N->getRawDataLocation()); + Printer.printMetadata("associated", N->getRawAssociated()); + Printer.printMetadata("allocated", N->getRawAllocated()); + if (auto *RankConst = N->getRankConst()) + Printer.printInt("rank", RankConst->getSExtValue(), + /* ShouldSkipZero */ false); + else + Printer.printMetadata("rank", N->getRawRank(), /*ShouldSkipNull */ true); Out << ")"; } @@ -2136,6 +2245,7 @@ static void writeDIModule(raw_ostream &Out, const DIModule *N, Printer.printString("apinotes", N->getAPINotesFile()); Printer.printMetadata("file", N->getRawFile()); Printer.printInt("line", N->getLineNo()); + Printer.printBool("isDecl", N->getIsDecl(), /* Default */ false); Out << ")"; } @@ -3087,7 +3197,7 @@ void AssemblyWriter::printFunctionSummary(const FunctionSummary *FS) { printTypeIdInfo(*TIdInfo); auto PrintRange = [&](const ConstantRange &Range) { - Out << "[" << Range.getLower() << ", " << Range.getSignedMax() << "]"; + Out << "[" << Range.getSignedMin() << ", " << Range.getSignedMax() << "]"; }; if (!FS->paramAccesses().empty()) { @@ -3103,7 +3213,7 @@ void AssemblyWriter::printFunctionSummary(const FunctionSummary *FS) { FieldSeparator IFS; for (auto &Call : PS.Calls) { Out << IFS; - Out << "(callee: ^" << Machine.getGUIDSlot(Call.Callee); + Out << "(callee: ^" << Machine.getGUIDSlot(Call.Callee.getGUID()); Out << ", param: " << Call.ParamNo; Out << ", offset: "; PrintRange(Call.Offsets); @@ -4269,11 +4379,17 @@ void AssemblyWriter::writeAttribute(const Attribute &Attr, bool InAttrGroup) { } assert((Attr.hasAttribute(Attribute::ByVal) || + Attr.hasAttribute(Attribute::StructRet) || + Attr.hasAttribute(Attribute::ByRef) || Attr.hasAttribute(Attribute::Preallocated)) && "unexpected type attr"); if (Attr.hasAttribute(Attribute::ByVal)) { Out << "byval"; + } else if (Attr.hasAttribute(Attribute::StructRet)) { + Out << "sret"; + } else if (Attr.hasAttribute(Attribute::ByRef)) { + Out << "byref"; } else { Out << "preallocated"; } @@ -4366,7 +4482,7 @@ void Function::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW, void BasicBlock::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW, bool ShouldPreserveUseListOrder, bool IsForDebug) const { - SlotTracker SlotTable(this->getModule()); + SlotTracker SlotTable(this->getParent()); formatted_raw_ostream OS(ROS); AssemblyWriter W(OS, SlotTable, this->getModule(), AAW, IsForDebug, diff --git a/llvm/lib/IR/Assumptions.cpp b/llvm/lib/IR/Assumptions.cpp new file mode 100644 index 000000000000..1bd8b7f51e67 --- /dev/null +++ b/llvm/lib/IR/Assumptions.cpp @@ -0,0 +1,36 @@ +//===- Assumptions.cpp ------ Collection of helpers for assumptions -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Assumptions.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" + +using namespace llvm; + +bool llvm::hasAssumption(Function &F, + const KnownAssumptionString &AssumptionStr) { + const Attribute &A = F.getFnAttribute(AssumptionAttrKey); + if (!A.isValid()) + return false; + assert(A.isStringAttribute() && "Expected a string attribute!"); + + SmallVector<StringRef, 8> Strings; + A.getValueAsString().split(Strings, ","); + + return llvm::any_of(Strings, [=](StringRef Assumption) { + return Assumption == AssumptionStr; + }); +} + +StringSet<> llvm::KnownAssumptionStrings({ + "omp_no_openmp", // OpenMP 5.1 + "omp_no_openmp_routines", // OpenMP 5.1 + "omp_no_parallelism", // OpenMP 5.1 +}); diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h index 5c334348cde3..c69fe3fe0827 100644 --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -121,7 +121,10 @@ protected: public: EnumAttributeImpl(Attribute::AttrKind Kind) - : AttributeImpl(EnumAttrEntry), Kind(Kind) {} + : AttributeImpl(EnumAttrEntry), Kind(Kind) { + assert(Kind != Attribute::AttrKind::None && + "Can't create a None attribute!"); + } Attribute::AttrKind getEnumKind() const { return Kind; } }; @@ -251,6 +254,8 @@ public: std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; std::string getAsString(bool InAttrGrp) const; Type *getByValType() const; + Type *getStructRetType() const; + Type *getByRefType() const; Type *getPreallocatedType() const; using iterator = const Attribute *; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index f67d96a854f4..c4629decc6d9 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -172,6 +172,14 @@ Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { return get(Context, ByVal, Ty); } +Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) { + return get(Context, StructRet, Ty); +} + +Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) { + return get(Context, ByRef, Ty); +} + Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) { return get(Context, Preallocated, Ty); } @@ -363,6 +371,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "noalias"; if (hasAttribute(Attribute::NoBuiltin)) return "nobuiltin"; + if (hasAttribute(Attribute::NoCallback)) + return "nocallback"; if (hasAttribute(Attribute::NoCapture)) return "nocapture"; if (hasAttribute(Attribute::NoDuplicate)) @@ -393,6 +403,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "nocf_check"; if (hasAttribute(Attribute::NoRecurse)) return "norecurse"; + if (hasAttribute(Attribute::NoProfile)) + return "noprofile"; if (hasAttribute(Attribute::NoUnwind)) return "nounwind"; if (hasAttribute(Attribute::OptForFuzzing)) @@ -429,8 +441,6 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "shadowcallstack"; if (hasAttribute(Attribute::StrictFP)) return "strictfp"; - if (hasAttribute(Attribute::StructRet)) - return "sret"; if (hasAttribute(Attribute::SanitizeThread)) return "sanitize_thread"; if (hasAttribute(Attribute::SanitizeMemory)) @@ -441,14 +451,19 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "zeroext"; if (hasAttribute(Attribute::Cold)) return "cold"; + if (hasAttribute(Attribute::Hot)) + return "hot"; if (hasAttribute(Attribute::ImmArg)) return "immarg"; if (hasAttribute(Attribute::NoUndef)) return "noundef"; + if (hasAttribute(Attribute::MustProgress)) + return "mustprogress"; - if (hasAttribute(Attribute::ByVal)) { + const bool IsByVal = hasAttribute(Attribute::ByVal); + if (IsByVal || hasAttribute(Attribute::StructRet)) { std::string Result; - Result += "byval"; + Result += IsByVal ? "byval" : "sret"; if (Type *Ty = getValueAsType()) { raw_string_ostream OS(Result); Result += '('; @@ -459,9 +474,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return Result; } - if (hasAttribute(Attribute::Preallocated)) { - std::string Result; - Result += "preallocated"; + const bool IsByRef = hasAttribute(Attribute::ByRef); + if (IsByRef || hasAttribute(Attribute::Preallocated)) { + std::string Result = IsByRef ? "byref" : "preallocated"; raw_string_ostream OS(Result); Result += '('; getValueAsType()->print(OS, false, true); @@ -742,10 +757,18 @@ uint64_t AttributeSet::getDereferenceableOrNullBytes() const { return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0; } +Type *AttributeSet::getByRefType() const { + return SetNode ? SetNode->getByRefType() : nullptr; +} + Type *AttributeSet::getByValType() const { return SetNode ? SetNode->getByValType() : nullptr; } +Type *AttributeSet::getStructRetType() const { + return SetNode ? SetNode->getStructRetType() : nullptr; +} + Type *AttributeSet::getPreallocatedType() const { return SetNode ? SetNode->getPreallocatedType() : nullptr; } @@ -842,6 +865,12 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) { case Attribute::ByVal: Attr = Attribute::getWithByValType(C, B.getByValType()); break; + case Attribute::StructRet: + Attr = Attribute::getWithStructRetType(C, B.getStructRetType()); + break; + case Attribute::ByRef: + Attr = Attribute::getWithByRefType(C, B.getByRefType()); + break; case Attribute::Preallocated: Attr = Attribute::getWithPreallocatedType(C, B.getPreallocatedType()); break; @@ -925,14 +954,25 @@ MaybeAlign AttributeSetNode::getStackAlignment() const { Type *AttributeSetNode::getByValType() const { if (auto A = findEnumAttribute(Attribute::ByVal)) return A->getValueAsType(); - return 0; + return nullptr; +} + +Type *AttributeSetNode::getStructRetType() const { + if (auto A = findEnumAttribute(Attribute::StructRet)) + return A->getValueAsType(); + return nullptr; +} + +Type *AttributeSetNode::getByRefType() const { + if (auto A = findEnumAttribute(Attribute::ByRef)) + return A->getValueAsType(); + return nullptr; } Type *AttributeSetNode::getPreallocatedType() const { - for (const auto &I : *this) - if (I.hasAttribute(Attribute::Preallocated)) - return I.getValueAsType(); - return 0; + if (auto A = findEnumAttribute(Attribute::Preallocated)) + return A->getValueAsType(); + return nullptr; } uint64_t AttributeSetNode::getDereferenceableBytes() const { @@ -970,7 +1010,7 @@ std::string AttributeSetNode::getAsString(bool InAttrGrp) const { /// Map from AttributeList index to the internal array index. Adding one happens /// to work, because -1 wraps around to 0. -static constexpr unsigned attrIdxToArrayIdx(unsigned Index) { +static unsigned attrIdxToArrayIdx(unsigned Index) { return Index + 1; } @@ -983,9 +1023,7 @@ AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets) // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs // summary bitsets. - static_assert(attrIdxToArrayIdx(AttributeList::FunctionIndex) == 0U, - "function should be stored in slot 0"); - for (const auto &I : Sets[0]) + for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)]) if (!I.isStringAttribute()) AvailableFunctionAttrs.addAttribute(I.getKindAsEnum()); @@ -1073,10 +1111,10 @@ AttributeList::get(LLVMContext &C, return LHS.first < RHS.first; }) && "Misordered Attributes list!"); - assert(llvm::none_of(Attrs, - [](const std::pair<unsigned, Attribute> &Pair) { - return Pair.second.hasAttribute(Attribute::None); - }) && + assert(llvm::all_of(Attrs, + [](const std::pair<unsigned, Attribute> &Pair) { + return Pair.second.isValid(); + }) && "Pointless attribute!"); // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes @@ -1164,7 +1202,7 @@ AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, if (NumSets > 2) { // Drop the empty argument attribute sets at the end. ArgAttrs = ArgAttrs.take_front(NumSets - 2); - AttrSets.insert(AttrSets.end(), ArgAttrs.begin(), ArgAttrs.end()); + llvm::append_range(AttrSets, ArgAttrs); } return getImpl(C, AttrSets); @@ -1236,9 +1274,11 @@ AttributeList AttributeList::get(LLVMContext &C, AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index, Attribute::AttrKind Kind) const { if (hasAttribute(Index, Kind)) return *this; - AttrBuilder B; - B.addAttribute(Kind); - return addAttributes(C, Index, B); + AttributeSet Attrs = getAttributes(Index); + // TODO: Insert at correct position and avoid sort. + SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end()); + NewAttrs.push_back(Attribute::get(C, Kind)); + return setAttributes(C, Index, AttributeSet::get(C, NewAttrs)); } AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index, @@ -1256,6 +1296,16 @@ AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index, return addAttributes(C, Index, B); } +AttributeList AttributeList::setAttributes(LLVMContext &C, unsigned Index, + AttributeSet Attrs) const { + Index = attrIdxToArrayIdx(Index); + SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); + if (Index >= AttrSets.size()) + AttrSets.resize(Index + 1); + AttrSets[Index] = Attrs; + return AttributeList::getImpl(C, AttrSets); +} + AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index, const AttrBuilder &B) const { if (!B.hasAttributes()) @@ -1273,16 +1323,9 @@ AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index, "Attempt to change alignment!"); #endif - Index = attrIdxToArrayIdx(Index); - SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); - if (Index >= AttrSets.size()) - AttrSets.resize(Index + 1); - - AttrBuilder Merged(AttrSets[Index]); + AttrBuilder Merged(getAttributes(Index)); Merged.merge(B); - AttrSets[Index] = AttributeSet::get(C, Merged); - - return getImpl(C, AttrSets); + return setAttributes(C, Index, AttributeSet::get(C, Merged)); } AttributeList AttributeList::addParamAttribute(LLVMContext &C, @@ -1452,6 +1495,14 @@ Type *AttributeList::getParamByValType(unsigned Index) const { return getAttributes(Index+FirstArgIndex).getByValType(); } +Type *AttributeList::getParamStructRetType(unsigned Index) const { + return getAttributes(Index + FirstArgIndex).getStructRetType(); +} + +Type *AttributeList::getParamByRefType(unsigned Index) const { + return getAttributes(Index + FirstArgIndex).getByRefType(); +} + Type *AttributeList::getParamPreallocatedType(unsigned Index) const { return getAttributes(Index + FirstArgIndex).getPreallocatedType(); } @@ -1537,17 +1588,11 @@ void AttrBuilder::clear() { DerefBytes = DerefOrNullBytes = 0; AllocSizeArgs = 0; ByValType = nullptr; + StructRetType = nullptr; + ByRefType = nullptr; PreallocatedType = nullptr; } -AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { - assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); - assert(!Attribute::doesAttrKindHaveArgument(Val) && - "Adding integer attribute without adding a value!"); - Attrs[Val] = true; - return *this; -} - AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { if (Attr.isStringAttribute()) { addAttribute(Attr.getKindAsString(), Attr.getValueAsString()); @@ -1563,6 +1608,10 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { StackAlignment = Attr.getStackAlignment(); else if (Kind == Attribute::ByVal) ByValType = Attr.getValueAsType(); + else if (Kind == Attribute::StructRet) + StructRetType = Attr.getValueAsType(); + else if (Kind == Attribute::ByRef) + ByRefType = Attr.getValueAsType(); else if (Kind == Attribute::Preallocated) PreallocatedType = Attr.getValueAsType(); else if (Kind == Attribute::Dereferenceable) @@ -1589,6 +1638,10 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { StackAlignment.reset(); else if (Val == Attribute::ByVal) ByValType = nullptr; + else if (Val == Attribute::StructRet) + StructRetType = nullptr; + else if (Val == Attribute::ByRef) + ByRefType = nullptr; else if (Val == Attribute::Preallocated) PreallocatedType = nullptr; else if (Val == Attribute::Dereferenceable) @@ -1679,6 +1732,18 @@ AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { return *this; } +AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) { + Attrs[Attribute::StructRet] = true; + StructRetType = Ty; + return *this; +} + +AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) { + Attrs[Attribute::ByRef] = true; + ByRefType = Ty; + return *this; +} + AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) { Attrs[Attribute::Preallocated] = true; PreallocatedType = Ty; @@ -1705,6 +1770,12 @@ AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { if (!ByValType) ByValType = B.ByValType; + if (!StructRetType) + StructRetType = B.StructRetType; + + if (!ByRefType) + ByRefType = B.ByRefType; + if (!PreallocatedType) PreallocatedType = B.PreallocatedType; @@ -1736,6 +1807,12 @@ AttrBuilder &AttrBuilder::remove(const AttrBuilder &B) { if (B.ByValType) ByValType = nullptr; + if (B.StructRetType) + StructRetType = nullptr; + + if (B.ByRefType) + ByRefType = nullptr; + if (B.PreallocatedType) PreallocatedType = nullptr; @@ -1788,7 +1865,7 @@ bool AttrBuilder::hasAlignmentAttr() const { return Alignment != 0; } -bool AttrBuilder::operator==(const AttrBuilder &B) { +bool AttrBuilder::operator==(const AttrBuilder &B) const { if (Attrs != B.Attrs) return false; @@ -1799,6 +1876,7 @@ bool AttrBuilder::operator==(const AttrBuilder &B) { return Alignment == B.Alignment && StackAlignment == B.StackAlignment && DerefBytes == B.DerefBytes && ByValType == B.ByValType && + StructRetType == B.StructRetType && ByRefType == B.ByRefType && PreallocatedType == B.PreallocatedType; } @@ -1821,14 +1899,20 @@ AttrBuilder AttributeFuncs::typeIncompatible(Type *Ty) { .addAttribute(Attribute::NoAlias) .addAttribute(Attribute::NoCapture) .addAttribute(Attribute::NonNull) + .addAlignmentAttr(1) // the int here is ignored .addDereferenceableAttr(1) // the int here is ignored .addDereferenceableOrNullAttr(1) // the int here is ignored .addAttribute(Attribute::ReadNone) .addAttribute(Attribute::ReadOnly) - .addAttribute(Attribute::StructRet) .addAttribute(Attribute::InAlloca) .addPreallocatedAttr(Ty) - .addByValAttr(Ty); + .addByValAttr(Ty) + .addStructRetAttr(Ty) + .addByRefAttr(Ty); + + // Some attributes can apply to all "values" but there are no `void` values. + if (Ty->isVoidTy()) + Incompatible.addAttribute(Attribute::NoUndef); return Incompatible; } @@ -1866,6 +1950,16 @@ static void setOR(Function &Caller, const Function &Callee) { /// If the inlined function had a higher stack protection level than the /// calling function, then bump up the caller's stack protection level. static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { +#ifndef NDEBUG + if (!Callee.hasFnAttribute(Attribute::AlwaysInline)) { + assert(!(!Callee.hasStackProtectorFnAttr() && + Caller.hasStackProtectorFnAttr()) && + "stack protected caller but callee requested no stack protector"); + assert(!(!Caller.hasStackProtectorFnAttr() && + Callee.hasStackProtectorFnAttr()) && + "stack protected callee but caller requested no stack protector"); + } +#endif // If upgrading the SSP attribute, clear out the old SSP Attributes first. // Having multiple SSP attributes doesn't actually hurt, but it adds useless // clutter to the IR. @@ -1901,21 +1995,19 @@ static void adjustCallerStackProbes(Function &Caller, const Function &Callee) { /// that is no larger. static void adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { - if (Callee.hasFnAttribute("stack-probe-size")) { - uint64_t CalleeStackProbeSize; - Callee.getFnAttribute("stack-probe-size") - .getValueAsString() - .getAsInteger(0, CalleeStackProbeSize); - if (Caller.hasFnAttribute("stack-probe-size")) { - uint64_t CallerStackProbeSize; - Caller.getFnAttribute("stack-probe-size") - .getValueAsString() - .getAsInteger(0, CallerStackProbeSize); + Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size"); + if (CalleeAttr.isValid()) { + Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size"); + if (CallerAttr.isValid()) { + uint64_t CallerStackProbeSize, CalleeStackProbeSize; + CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize); + CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize); + if (CallerStackProbeSize > CalleeStackProbeSize) { - Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + Caller.addFnAttr(CalleeAttr); } } else { - Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + Caller.addFnAttr(CalleeAttr); } } } @@ -1931,18 +2023,15 @@ adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { /// handled as part of inline cost analysis. static void adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) { - if (Caller.hasFnAttribute("min-legal-vector-width")) { - if (Callee.hasFnAttribute("min-legal-vector-width")) { - uint64_t CallerVectorWidth; - Caller.getFnAttribute("min-legal-vector-width") - .getValueAsString() - .getAsInteger(0, CallerVectorWidth); - uint64_t CalleeVectorWidth; - Callee.getFnAttribute("min-legal-vector-width") - .getValueAsString() - .getAsInteger(0, CalleeVectorWidth); + Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width"); + if (CallerAttr.isValid()) { + Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width"); + if (CalleeAttr.isValid()) { + uint64_t CallerVectorWidth, CalleeVectorWidth; + CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth); + CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth); if (CallerVectorWidth < CalleeVectorWidth) - Caller.addFnAttr(Callee.getFnAttribute("min-legal-vector-width")); + Caller.addFnAttr(CalleeAttr); } else { // If the callee doesn't have the attribute then we don't know anything // and must drop the attribute from the caller. @@ -2009,7 +2098,25 @@ bool AttributeFuncs::areInlineCompatible(const Function &Caller, return hasCompatibleFnAttrs(Caller, Callee); } +bool AttributeFuncs::areOutlineCompatible(const Function &A, + const Function &B) { + return hasCompatibleFnAttrs(A, B); +} + void AttributeFuncs::mergeAttributesForInlining(Function &Caller, const Function &Callee) { mergeFnAttrs(Caller, Callee); } + +void AttributeFuncs::mergeAttributesForOutlining(Function &Base, + const Function &ToMerge) { + + // We merge functions so that they meet the most general case. + // For example, if the NoNansFPMathAttr is set in one function, but not in + // the other, in the merged function we can say that the NoNansFPMathAttr + // is not set. + // However if we have the SpeculativeLoadHardeningAttr set true in one + // function, but not the other, we make sure that the function retains + // that aspect in the merged function. + mergeFnAttrs(Base, ToMerge); +} diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 1e8fdb506619..23e7af6287b6 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsAArch64.h" #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/IntrinsicsX86.h" @@ -68,6 +69,19 @@ static bool UpgradeX86IntrinsicsWith8BitMask(Function *F, Intrinsic::ID IID, return true; } +// Upgrade the declaration of fp compare intrinsics that change return type +// from scalar to vXi1 mask. +static bool UpgradeX86MaskedFPCompare(Function *F, Intrinsic::ID IID, + Function *&NewFn) { + // Check if the return type is a vector. + if (F->getReturnType()->isVectorTy()) + return false; + + rename(F); + NewFn = Intrinsic::getDeclaration(F->getParent(), IID); + return true; +} + static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { // All of the intrinsics matches below should be marked with which llvm // version started autoupgrading them. At some point in the future we would @@ -241,7 +255,7 @@ static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { Name.startswith("avx512.mask.cmp.d") || // Added in 5.0 Name.startswith("avx512.mask.cmp.q") || // Added in 5.0 Name.startswith("avx512.mask.cmp.w") || // Added in 5.0 - Name.startswith("avx512.mask.cmp.p") || // Added in 7.0 + Name.startswith("avx512.cmp.p") || // Added in 12.0 Name.startswith("avx512.mask.ucmp.") || // Added in 5.0 Name.startswith("avx512.cvtb2mask.") || // Added in 7.0 Name.startswith("avx512.cvtw2mask.") || // Added in 7.0 @@ -456,6 +470,24 @@ static bool UpgradeX86IntrinsicFunction(Function *F, StringRef Name, if (Name == "avx2.mpsadbw") // Added in 3.6 return UpgradeX86IntrinsicsWith8BitMask(F, Intrinsic::x86_avx2_mpsadbw, NewFn); + if (Name == "avx512.mask.cmp.pd.128") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_pd_128, + NewFn); + if (Name == "avx512.mask.cmp.pd.256") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_pd_256, + NewFn); + if (Name == "avx512.mask.cmp.pd.512") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_pd_512, + NewFn); + if (Name == "avx512.mask.cmp.ps.128") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_ps_128, + NewFn); + if (Name == "avx512.mask.cmp.ps.256") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_ps_256, + NewFn); + if (Name == "avx512.mask.cmp.ps.512") // Added in 7.0 + return UpgradeX86MaskedFPCompare(F, Intrinsic::x86_avx512_mask_cmp_ps_512, + NewFn); // frcz.ss/sd may need to have an argument dropped. Added in 3.2 if (Name.startswith("xop.vfrcz.ss") && F->arg_size() == 2) { @@ -601,6 +633,63 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { return true; } } + + // Changed in 12.0: bfdot accept v4bf16 and v8bf16 instead of v8i8 and v16i8 + // respectively + if ((Name.startswith("arm.neon.bfdot.") || + Name.startswith("aarch64.neon.bfdot.")) && + Name.endswith("i8")) { + Intrinsic::ID IID = + StringSwitch<Intrinsic::ID>(Name) + .Cases("arm.neon.bfdot.v2f32.v8i8", + "arm.neon.bfdot.v4f32.v16i8", + Intrinsic::arm_neon_bfdot) + .Cases("aarch64.neon.bfdot.v2f32.v8i8", + "aarch64.neon.bfdot.v4f32.v16i8", + Intrinsic::aarch64_neon_bfdot) + .Default(Intrinsic::not_intrinsic); + if (IID == Intrinsic::not_intrinsic) + break; + + size_t OperandWidth = F->getReturnType()->getPrimitiveSizeInBits(); + assert((OperandWidth == 64 || OperandWidth == 128) && + "Unexpected operand width"); + LLVMContext &Ctx = F->getParent()->getContext(); + std::array<Type *, 2> Tys {{ + F->getReturnType(), + FixedVectorType::get(Type::getBFloatTy(Ctx), OperandWidth / 16) + }}; + NewFn = Intrinsic::getDeclaration(F->getParent(), IID, Tys); + return true; + } + + // Changed in 12.0: bfmmla, bfmlalb and bfmlalt are not polymorphic anymore + // and accept v8bf16 instead of v16i8 + if ((Name.startswith("arm.neon.bfm") || + Name.startswith("aarch64.neon.bfm")) && + Name.endswith(".v4f32.v16i8")) { + Intrinsic::ID IID = + StringSwitch<Intrinsic::ID>(Name) + .Case("arm.neon.bfmmla.v4f32.v16i8", + Intrinsic::arm_neon_bfmmla) + .Case("arm.neon.bfmlalb.v4f32.v16i8", + Intrinsic::arm_neon_bfmlalb) + .Case("arm.neon.bfmlalt.v4f32.v16i8", + Intrinsic::arm_neon_bfmlalt) + .Case("aarch64.neon.bfmmla.v4f32.v16i8", + Intrinsic::aarch64_neon_bfmmla) + .Case("aarch64.neon.bfmlalb.v4f32.v16i8", + Intrinsic::aarch64_neon_bfmlalb) + .Case("aarch64.neon.bfmlalt.v4f32.v16i8", + Intrinsic::aarch64_neon_bfmlalt) + .Default(Intrinsic::not_intrinsic); + if (IID == Intrinsic::not_intrinsic) + break; + + std::array<Type *, 0> Tys; + NewFn = Intrinsic::getDeclaration(F->getParent(), IID, Tys); + return true; + } break; } @@ -629,18 +718,42 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { } case 'e': { SmallVector<StringRef, 2> Groups; - static const Regex R("^experimental.vector.reduce.([a-z]+)\\.[fi][0-9]+"); + static const Regex R("^experimental.vector.reduce.([a-z]+)\\.[a-z][0-9]+"); if (R.match(Name, &Groups)) { + Intrinsic::ID ID; + ID = StringSwitch<Intrinsic::ID>(Groups[1]) + .Case("add", Intrinsic::vector_reduce_add) + .Case("mul", Intrinsic::vector_reduce_mul) + .Case("and", Intrinsic::vector_reduce_and) + .Case("or", Intrinsic::vector_reduce_or) + .Case("xor", Intrinsic::vector_reduce_xor) + .Case("smax", Intrinsic::vector_reduce_smax) + .Case("smin", Intrinsic::vector_reduce_smin) + .Case("umax", Intrinsic::vector_reduce_umax) + .Case("umin", Intrinsic::vector_reduce_umin) + .Case("fmax", Intrinsic::vector_reduce_fmax) + .Case("fmin", Intrinsic::vector_reduce_fmin) + .Default(Intrinsic::not_intrinsic); + if (ID != Intrinsic::not_intrinsic) { + rename(F); + auto Args = F->getFunctionType()->params(); + NewFn = Intrinsic::getDeclaration(F->getParent(), ID, {Args[0]}); + return true; + } + } + static const Regex R2( + "^experimental.vector.reduce.v2.([a-z]+)\\.[fi][0-9]+"); + Groups.clear(); + if (R2.match(Name, &Groups)) { Intrinsic::ID ID = Intrinsic::not_intrinsic; if (Groups[1] == "fadd") - ID = Intrinsic::experimental_vector_reduce_v2_fadd; + ID = Intrinsic::vector_reduce_fadd; if (Groups[1] == "fmul") - ID = Intrinsic::experimental_vector_reduce_v2_fmul; - + ID = Intrinsic::vector_reduce_fmul; if (ID != Intrinsic::not_intrinsic) { rename(F); auto Args = F->getFunctionType()->params(); - Type *Tys[] = {F->getFunctionType()->getReturnType(), Args[1]}; + Type *Tys[] = {Args[1]}; NewFn = Intrinsic::getDeclaration(F->getParent(), ID, Tys); return true; } @@ -900,7 +1013,7 @@ GlobalVariable *llvm::UpgradeGlobalVariable(GlobalVariable *GV) { // to byte shuffles. static Value *UpgradeX86PSLLDQIntrinsics(IRBuilder<> &Builder, Value *Op, unsigned Shift) { - auto *ResultTy = cast<VectorType>(Op->getType()); + auto *ResultTy = cast<FixedVectorType>(Op->getType()); unsigned NumElts = ResultTy->getNumElements() * 8; // Bitcast from a 64-bit element type to a byte element type. @@ -934,7 +1047,7 @@ static Value *UpgradeX86PSLLDQIntrinsics(IRBuilder<> &Builder, // to byte shuffles. static Value *UpgradeX86PSRLDQIntrinsics(IRBuilder<> &Builder, Value *Op, unsigned Shift) { - auto *ResultTy = cast<VectorType>(Op->getType()); + auto *ResultTy = cast<FixedVectorType>(Op->getType()); unsigned NumElts = ResultTy->getNumElements() * 8; // Bitcast from a 64-bit element type to a byte element type. @@ -966,19 +1079,19 @@ static Value *UpgradeX86PSRLDQIntrinsics(IRBuilder<> &Builder, Value *Op, static Value *getX86MaskVec(IRBuilder<> &Builder, Value *Mask, unsigned NumElts) { + assert(isPowerOf2_32(NumElts) && "Expected power-of-2 mask elements"); llvm::VectorType *MaskTy = FixedVectorType::get( Builder.getInt1Ty(), cast<IntegerType>(Mask->getType())->getBitWidth()); Mask = Builder.CreateBitCast(Mask, MaskTy); - // If we have less than 8 elements, then the starting mask was an i8 and - // we need to extract down to the right number of elements. - if (NumElts < 8) { + // If we have less than 8 elements (1, 2 or 4), then the starting mask was an + // i8 and we need to extract down to the right number of elements. + if (NumElts <= 4) { int Indices[4]; for (unsigned i = 0; i != NumElts; ++i) Indices[i] = i; - Mask = Builder.CreateShuffleVector(Mask, Mask, - makeArrayRef(Indices, NumElts), - "extract"); + Mask = Builder.CreateShuffleVector( + Mask, Mask, makeArrayRef(Indices, NumElts), "extract"); } return Mask; @@ -992,7 +1105,7 @@ static Value *EmitX86Select(IRBuilder<> &Builder, Value *Mask, return Op0; Mask = getX86MaskVec(Builder, Mask, - cast<VectorType>(Op0->getType())->getNumElements()); + cast<FixedVectorType>(Op0->getType())->getNumElements()); return Builder.CreateSelect(Mask, Op0, Op1); } @@ -1019,7 +1132,7 @@ static Value *UpgradeX86ALIGNIntrinsics(IRBuilder<> &Builder, Value *Op0, bool IsVALIGN) { unsigned ShiftVal = cast<llvm::ConstantInt>(Shift)->getZExtValue(); - unsigned NumElts = cast<VectorType>(Op0->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Op0->getType())->getNumElements(); assert((IsVALIGN || NumElts % 16 == 0) && "Illegal NumElts for PALIGNR!"); assert((!IsVALIGN || NumElts <= 16) && "NumElts too large for VALIGN!"); assert(isPowerOf2_32(NumElts) && "NumElts not a power of 2!"); @@ -1120,15 +1233,11 @@ static Value *UpgradeX86VPERMT2Intrinsics(IRBuilder<> &Builder, CallInst &CI, return EmitX86Select(Builder, CI.getArgOperand(3), V, PassThru); } -static Value *UpgradeX86AddSubSatIntrinsics(IRBuilder<> &Builder, CallInst &CI, - bool IsSigned, bool IsAddition) { +static Value *UpgradeX86BinaryIntrinsics(IRBuilder<> &Builder, CallInst &CI, + Intrinsic::ID IID) { Type *Ty = CI.getType(); Value *Op0 = CI.getOperand(0); Value *Op1 = CI.getOperand(1); - - Intrinsic::ID IID = - IsSigned ? (IsAddition ? Intrinsic::sadd_sat : Intrinsic::ssub_sat) - : (IsAddition ? Intrinsic::uadd_sat : Intrinsic::usub_sat); Function *Intrin = Intrinsic::getDeclaration(CI.getModule(), IID, Ty); Value *Res = Builder.CreateCall(Intrin, {Op0, Op1}); @@ -1150,7 +1259,7 @@ static Value *upgradeX86Rotate(IRBuilder<> &Builder, CallInst &CI, // Funnel shifts amounts are treated as modulo and types are all power-of-2 so // we only care about the lowest log2 bits anyway. if (Amt->getType() != Ty) { - unsigned NumElts = cast<VectorType>(Ty)->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Ty)->getNumElements(); Amt = Builder.CreateIntCast(Amt, Ty->getScalarType(), false); Amt = Builder.CreateVectorSplat(NumElts, Amt); } @@ -1220,7 +1329,7 @@ static Value *upgradeX86ConcatShift(IRBuilder<> &Builder, CallInst &CI, // Funnel shifts amounts are treated as modulo and types are all power-of-2 so // we only care about the lowest log2 bits anyway. if (Amt->getType() != Ty) { - unsigned NumElts = cast<VectorType>(Ty)->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Ty)->getNumElements(); Amt = Builder.CreateIntCast(Amt, Ty->getScalarType(), false); Amt = Builder.CreateVectorSplat(NumElts, Amt); } @@ -1257,7 +1366,7 @@ static Value *UpgradeMaskedStore(IRBuilder<> &Builder, return Builder.CreateAlignedStore(Data, Ptr, Alignment); // Convert the mask from an integer type to a vector of i1. - unsigned NumElts = cast<VectorType>(Data->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Data->getType())->getNumElements(); Mask = getX86MaskVec(Builder, Mask, NumElts); return Builder.CreateMaskedStore(Data, Ptr, Alignment, Mask); } @@ -1280,35 +1389,19 @@ static Value *UpgradeMaskedLoad(IRBuilder<> &Builder, return Builder.CreateAlignedLoad(ValTy, Ptr, Alignment); // Convert the mask from an integer type to a vector of i1. - unsigned NumElts = cast<VectorType>(Passthru->getType())->getNumElements(); + unsigned NumElts = + cast<FixedVectorType>(Passthru->getType())->getNumElements(); Mask = getX86MaskVec(Builder, Mask, NumElts); return Builder.CreateMaskedLoad(Ptr, Alignment, Mask, Passthru); } static Value *upgradeAbs(IRBuilder<> &Builder, CallInst &CI) { + Type *Ty = CI.getType(); Value *Op0 = CI.getArgOperand(0); - llvm::Type *Ty = Op0->getType(); - Value *Zero = llvm::Constant::getNullValue(Ty); - Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_SGT, Op0, Zero); - Value *Neg = Builder.CreateNeg(Op0); - Value *Res = Builder.CreateSelect(Cmp, Op0, Neg); - + Function *F = Intrinsic::getDeclaration(CI.getModule(), Intrinsic::abs, Ty); + Value *Res = Builder.CreateCall(F, {Op0, Builder.getInt1(false)}); if (CI.getNumArgOperands() == 3) - Res = EmitX86Select(Builder,CI.getArgOperand(2), Res, CI.getArgOperand(1)); - - return Res; -} - -static Value *upgradeIntMinMax(IRBuilder<> &Builder, CallInst &CI, - ICmpInst::Predicate Pred) { - Value *Op0 = CI.getArgOperand(0); - Value *Op1 = CI.getArgOperand(1); - Value *Cmp = Builder.CreateICmp(Pred, Op0, Op1); - Value *Res = Builder.CreateSelect(Cmp, Op0, Op1); - - if (CI.getNumArgOperands() == 4) - Res = EmitX86Select(Builder, CI.getArgOperand(3), Res, CI.getArgOperand(2)); - + Res = EmitX86Select(Builder, CI.getArgOperand(2), Res, CI.getArgOperand(1)); return Res; } @@ -1344,7 +1437,7 @@ static Value *upgradePMULDQ(IRBuilder<> &Builder, CallInst &CI, bool IsSigned) { // Applying mask on vector of i1's and make sure result is at least 8 bits wide. static Value *ApplyX86MaskOn1BitsVec(IRBuilder<> &Builder, Value *Vec, Value *Mask) { - unsigned NumElts = cast<VectorType>(Vec->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Vec->getType())->getNumElements(); if (Mask) { const auto *C = dyn_cast<Constant>(Mask); if (!C || !C->isAllOnesValue()) @@ -1367,7 +1460,7 @@ static Value *ApplyX86MaskOn1BitsVec(IRBuilder<> &Builder, Value *Vec, static Value *upgradeMaskedCompare(IRBuilder<> &Builder, CallInst &CI, unsigned CC, bool Signed) { Value *Op0 = CI.getArgOperand(0); - unsigned NumElts = cast<VectorType>(Op0->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(Op0->getType())->getNumElements(); Value *Cmp; if (CC == 3) { @@ -1422,7 +1515,7 @@ static Value* upgradeMaskedMove(IRBuilder<> &Builder, CallInst &CI) { static Value* UpgradeMaskToInt(IRBuilder<> &Builder, CallInst &CI) { Value* Op = CI.getArgOperand(0); Type* ReturnOp = CI.getType(); - unsigned NumElts = cast<VectorType>(CI.getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI.getType())->getNumElements(); Value *Mask = getX86MaskVec(Builder, Op, NumElts); return Builder.CreateSExt(Mask, ReturnOp, "vpmovm2"); } @@ -1676,7 +1769,6 @@ void llvm::UpgradeInlineAsmString(std::string *AsmStr) { (Pos = AsmStr->find("# marker")) != std::string::npos) { AsmStr->replace(Pos, 1, ";"); } - return; } /// Upgrade a call to an old intrinsic. All argument and return casting must be @@ -1871,8 +1963,8 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Rep = Builder.CreateICmp(Pred, Rep, Zero); Rep = ApplyX86MaskOn1BitsVec(Builder, Rep, Mask); } else if (IsX86 && (Name.startswith("avx512.mask.pbroadcast"))){ - unsigned NumElts = - cast<VectorType>(CI->getArgOperand(1)->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getArgOperand(1)->getType()) + ->getNumElements(); Rep = Builder.CreateVectorSplat(NumElts, CI->getArgOperand(0)); Rep = EmitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); @@ -2000,38 +2092,36 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), { CI->getOperand(0), CI->getArgOperand(1) }); Rep = ApplyX86MaskOn1BitsVec(Builder, Rep, CI->getArgOperand(2)); - } else if (IsX86 && Name.startswith("avx512.mask.cmp.p")) { - Type *OpTy = CI->getArgOperand(0)->getType(); + } else if (IsX86 && Name.startswith("avx512.cmp.p")) { + SmallVector<Value *, 4> Args(CI->arg_operands().begin(), + CI->arg_operands().end()); + Type *OpTy = Args[0]->getType(); unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); unsigned EltWidth = OpTy->getScalarSizeInBits(); Intrinsic::ID IID; if (VecWidth == 128 && EltWidth == 32) - IID = Intrinsic::x86_avx512_cmp_ps_128; + IID = Intrinsic::x86_avx512_mask_cmp_ps_128; else if (VecWidth == 256 && EltWidth == 32) - IID = Intrinsic::x86_avx512_cmp_ps_256; + IID = Intrinsic::x86_avx512_mask_cmp_ps_256; else if (VecWidth == 512 && EltWidth == 32) - IID = Intrinsic::x86_avx512_cmp_ps_512; + IID = Intrinsic::x86_avx512_mask_cmp_ps_512; else if (VecWidth == 128 && EltWidth == 64) - IID = Intrinsic::x86_avx512_cmp_pd_128; + IID = Intrinsic::x86_avx512_mask_cmp_pd_128; else if (VecWidth == 256 && EltWidth == 64) - IID = Intrinsic::x86_avx512_cmp_pd_256; + IID = Intrinsic::x86_avx512_mask_cmp_pd_256; else if (VecWidth == 512 && EltWidth == 64) - IID = Intrinsic::x86_avx512_cmp_pd_512; + IID = Intrinsic::x86_avx512_mask_cmp_pd_512; else llvm_unreachable("Unexpected intrinsic"); - SmallVector<Value *, 4> Args; - Args.push_back(CI->getArgOperand(0)); - Args.push_back(CI->getArgOperand(1)); - Args.push_back(CI->getArgOperand(2)); - if (CI->getNumArgOperands() == 5) - Args.push_back(CI->getArgOperand(4)); + Value *Mask = Constant::getAllOnesValue(CI->getType()); + if (VecWidth == 512) + std::swap(Mask, Args.back()); + Args.push_back(Mask); Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), Args); - Rep = ApplyX86MaskOn1BitsVec(Builder, Rep, CI->getArgOperand(3)); - } else if (IsX86 && Name.startswith("avx512.mask.cmp.") && - Name[16] != 'p') { + } else if (IsX86 && Name.startswith("avx512.mask.cmp.")) { // Integer compare intrinsics. unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); Rep = upgradeMaskedCompare(Builder, *CI, Imm, true); @@ -2057,25 +2147,25 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name == "sse41.pmaxsd" || Name.startswith("avx2.pmaxs") || Name.startswith("avx512.mask.pmaxs"))) { - Rep = upgradeIntMinMax(Builder, *CI, ICmpInst::ICMP_SGT); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::smax); } else if (IsX86 && (Name == "sse2.pmaxu.b" || Name == "sse41.pmaxuw" || Name == "sse41.pmaxud" || Name.startswith("avx2.pmaxu") || Name.startswith("avx512.mask.pmaxu"))) { - Rep = upgradeIntMinMax(Builder, *CI, ICmpInst::ICMP_UGT); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::umax); } else if (IsX86 && (Name == "sse41.pminsb" || Name == "sse2.pmins.w" || Name == "sse41.pminsd" || Name.startswith("avx2.pmins") || Name.startswith("avx512.mask.pmins"))) { - Rep = upgradeIntMinMax(Builder, *CI, ICmpInst::ICMP_SLT); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::smin); } else if (IsX86 && (Name == "sse2.pminu.b" || Name == "sse41.pminuw" || Name == "sse41.pminud" || Name.startswith("avx2.pminu") || Name.startswith("avx512.mask.pminu"))) { - Rep = upgradeIntMinMax(Builder, *CI, ICmpInst::ICMP_ULT); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::umin); } else if (IsX86 && (Name == "sse2.pmulu.dq" || Name == "avx2.pmulu.dq" || Name == "avx512.pmulu.dq.512" || @@ -2122,9 +2212,9 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name == "avx.cvt.ps2.pd.256" || Name == "avx512.mask.cvtps2pd.128" || Name == "avx512.mask.cvtps2pd.256")) { - auto *DstTy = cast<VectorType>(CI->getType()); + auto *DstTy = cast<FixedVectorType>(CI->getType()); Rep = CI->getArgOperand(0); - auto *SrcTy = cast<VectorType>(Rep->getType()); + auto *SrcTy = cast<FixedVectorType>(Rep->getType()); unsigned NumDstElts = DstTy->getNumElements(); if (NumDstElts < SrcTy->getNumElements()) { @@ -2154,9 +2244,9 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { CI->getArgOperand(1)); } else if (IsX86 && (Name.startswith("avx512.mask.vcvtph2ps.") || Name.startswith("vcvtph2ps."))) { - auto *DstTy = cast<VectorType>(CI->getType()); + auto *DstTy = cast<FixedVectorType>(CI->getType()); Rep = CI->getArgOperand(0); - auto *SrcTy = cast<VectorType>(Rep->getType()); + auto *SrcTy = cast<FixedVectorType>(Rep->getType()); unsigned NumDstElts = DstTy->getNumElements(); if (NumDstElts != SrcTy->getNumElements()) { assert(NumDstElts == 4 && "Unexpected vector size"); @@ -2177,7 +2267,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { CI->getArgOperand(1),CI->getArgOperand(2), /*Aligned*/true); } else if (IsX86 && Name.startswith("avx512.mask.expand.load.")) { - auto *ResultTy = cast<VectorType>(CI->getType()); + auto *ResultTy = cast<FixedVectorType>(CI->getType()); Type *PtrTy = ResultTy->getElementType(); // Cast the pointer to element type. @@ -2199,8 +2289,9 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Value *Ptr = Builder.CreateBitCast(CI->getOperand(0), llvm::PointerType::getUnqual(PtrTy)); - Value *MaskVec = getX86MaskVec(Builder, CI->getArgOperand(2), - ResultTy->getNumElements()); + Value *MaskVec = + getX86MaskVec(Builder, CI->getArgOperand(2), + cast<FixedVectorType>(ResultTy)->getNumElements()); Function *CSt = Intrinsic::getDeclaration(F->getParent(), Intrinsic::masked_compressstore, @@ -2208,7 +2299,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Rep = Builder.CreateCall(CSt, { CI->getArgOperand(1), Ptr, MaskVec }); } else if (IsX86 && (Name.startswith("avx512.mask.compress.") || Name.startswith("avx512.mask.expand."))) { - auto *ResultTy = cast<VectorType>(CI->getType()); + auto *ResultTy = cast<FixedVectorType>(CI->getType()); Value *MaskVec = getX86MaskVec(Builder, CI->getArgOperand(2), ResultTy->getNumElements()); @@ -2288,7 +2379,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { } else if (IsX86 && (Name.startswith("avx.vbroadcast.s") || Name.startswith("avx512.vbroadcast.s"))) { // Replace broadcasts with a series of insertelements. - auto *VecTy = cast<VectorType>(CI->getType()); + auto *VecTy = cast<FixedVectorType>(CI->getType()); Type *EltTy = VecTy->getElementType(); unsigned EltNum = VecTy->getNumElements(); Value *Cast = Builder.CreateBitCast(CI->getArgOperand(0), @@ -2305,8 +2396,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx2.pmovzx") || Name.startswith("avx512.mask.pmovsx") || Name.startswith("avx512.mask.pmovzx"))) { - VectorType *SrcTy = cast<VectorType>(CI->getArgOperand(0)->getType()); - VectorType *DstTy = cast<VectorType>(CI->getType()); + auto *DstTy = cast<FixedVectorType>(CI->getType()); unsigned NumDstElts = DstTy->getNumElements(); // Extract a subvector of the first NumDstElts lanes and sign/zero extend. @@ -2314,8 +2404,8 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { for (unsigned i = 0; i != NumDstElts; ++i) ShuffleMask[i] = i; - Value *SV = Builder.CreateShuffleVector( - CI->getArgOperand(0), UndefValue::get(SrcTy), ShuffleMask); + Value *SV = + Builder.CreateShuffleVector(CI->getArgOperand(0), ShuffleMask); bool DoSext = (StringRef::npos != Name.find("pmovsx")); Rep = DoSext ? Builder.CreateSExt(SV, DstTy) @@ -2342,12 +2432,10 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { PointerType::getUnqual(VT)); Value *Load = Builder.CreateAlignedLoad(VT, Op, Align(1)); if (NumSrcElts == 2) - Rep = Builder.CreateShuffleVector( - Load, UndefValue::get(Load->getType()), ArrayRef<int>{0, 1, 0, 1}); + Rep = Builder.CreateShuffleVector(Load, ArrayRef<int>{0, 1, 0, 1}); else - Rep = - Builder.CreateShuffleVector(Load, UndefValue::get(Load->getType()), - ArrayRef<int>{0, 1, 2, 3, 0, 1, 2, 3}); + Rep = Builder.CreateShuffleVector( + Load, ArrayRef<int>{0, 1, 2, 3, 0, 1, 2, 3}); } else if (IsX86 && (Name.startswith("avx512.mask.shuf.i") || Name.startswith("avx512.mask.shuf.f"))) { unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); @@ -2373,8 +2461,10 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { }else if (IsX86 && (Name.startswith("avx512.mask.broadcastf") || Name.startswith("avx512.mask.broadcasti"))) { unsigned NumSrcElts = - cast<VectorType>(CI->getArgOperand(0)->getType())->getNumElements(); - unsigned NumDstElts = cast<VectorType>(CI->getType())->getNumElements(); + cast<FixedVectorType>(CI->getArgOperand(0)->getType()) + ->getNumElements(); + unsigned NumDstElts = + cast<FixedVectorType>(CI->getType())->getNumElements(); SmallVector<int, 8> ShuffleMask(NumDstElts); for (unsigned i = 0; i != NumDstElts; ++i) @@ -2393,30 +2483,31 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Value *Op = CI->getArgOperand(0); ElementCount EC = cast<VectorType>(CI->getType())->getElementCount(); Type *MaskTy = VectorType::get(Type::getInt32Ty(C), EC); - Rep = Builder.CreateShuffleVector(Op, UndefValue::get(Op->getType()), - Constant::getNullValue(MaskTy)); + SmallVector<int, 8> M; + ShuffleVectorInst::getShuffleMask(Constant::getNullValue(MaskTy), M); + Rep = Builder.CreateShuffleVector(Op, M); if (CI->getNumArgOperands() == 3) Rep = EmitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); } else if (IsX86 && (Name.startswith("sse2.padds.") || - Name.startswith("sse2.psubs.") || Name.startswith("avx2.padds.") || - Name.startswith("avx2.psubs.") || Name.startswith("avx512.padds.") || + Name.startswith("avx512.mask.padds."))) { + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::sadd_sat); + } else if (IsX86 && (Name.startswith("sse2.psubs.") || + Name.startswith("avx2.psubs.") || Name.startswith("avx512.psubs.") || - Name.startswith("avx512.mask.padds.") || Name.startswith("avx512.mask.psubs."))) { - bool IsAdd = Name.contains(".padds"); - Rep = UpgradeX86AddSubSatIntrinsics(Builder, *CI, true, IsAdd); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::ssub_sat); } else if (IsX86 && (Name.startswith("sse2.paddus.") || - Name.startswith("sse2.psubus.") || Name.startswith("avx2.paddus.") || + Name.startswith("avx512.mask.paddus."))) { + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::uadd_sat); + } else if (IsX86 && (Name.startswith("sse2.psubus.") || Name.startswith("avx2.psubus.") || - Name.startswith("avx512.mask.paddus.") || Name.startswith("avx512.mask.psubus."))) { - bool IsAdd = Name.contains(".paddus"); - Rep = UpgradeX86AddSubSatIntrinsics(Builder, *CI, false, IsAdd); + Rep = UpgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::usub_sat); } else if (IsX86 && Name.startswith("avx512.mask.palignr.")) { Rep = UpgradeX86ALIGNIntrinsics(Builder, CI->getArgOperand(0), CI->getArgOperand(1), @@ -2463,7 +2554,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Value *Op0 = CI->getArgOperand(0); Value *Op1 = CI->getArgOperand(1); unsigned Imm = cast <ConstantInt>(CI->getArgOperand(2))->getZExtValue(); - VectorType *VecTy = cast<VectorType>(CI->getType()); + auto *VecTy = cast<FixedVectorType>(CI->getType()); unsigned NumElts = VecTy->getNumElements(); SmallVector<int, 16> Idxs(NumElts); @@ -2477,21 +2568,22 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Value *Op0 = CI->getArgOperand(0); Value *Op1 = CI->getArgOperand(1); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); - unsigned DstNumElts = cast<VectorType>(CI->getType())->getNumElements(); - unsigned SrcNumElts = cast<VectorType>(Op1->getType())->getNumElements(); + unsigned DstNumElts = + cast<FixedVectorType>(CI->getType())->getNumElements(); + unsigned SrcNumElts = + cast<FixedVectorType>(Op1->getType())->getNumElements(); unsigned Scale = DstNumElts / SrcNumElts; // Mask off the high bits of the immediate value; hardware ignores those. Imm = Imm % Scale; // Extend the second operand into a vector the size of the destination. - Value *UndefV = UndefValue::get(Op1->getType()); SmallVector<int, 8> Idxs(DstNumElts); for (unsigned i = 0; i != SrcNumElts; ++i) Idxs[i] = i; for (unsigned i = SrcNumElts; i != DstNumElts; ++i) Idxs[i] = SrcNumElts; - Rep = Builder.CreateShuffleVector(Op1, UndefV, Idxs); + Rep = Builder.CreateShuffleVector(Op1, Idxs); // Insert the second operand into the first operand. @@ -2521,8 +2613,10 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.vextract"))) { Value *Op0 = CI->getArgOperand(0); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); - unsigned DstNumElts = cast<VectorType>(CI->getType())->getNumElements(); - unsigned SrcNumElts = cast<VectorType>(Op0->getType())->getNumElements(); + unsigned DstNumElts = + cast<FixedVectorType>(CI->getType())->getNumElements(); + unsigned SrcNumElts = + cast<FixedVectorType>(Op0->getType())->getNumElements(); unsigned Scale = SrcNumElts / DstNumElts; // Mask off the high bits of the immediate value; hardware ignores those. @@ -2545,7 +2639,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.perm.di."))) { Value *Op0 = CI->getArgOperand(0); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); - VectorType *VecTy = cast<VectorType>(CI->getType()); + auto *VecTy = cast<FixedVectorType>(CI->getType()); unsigned NumElts = VecTy->getNumElements(); SmallVector<int, 8> Idxs(NumElts); @@ -2569,7 +2663,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { uint8_t Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); - unsigned NumElts = cast<VectorType>(CI->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); unsigned HalfSize = NumElts / 2; SmallVector<int, 8> ShuffleMask(NumElts); @@ -2599,7 +2693,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.pshuf.d."))) { Value *Op0 = CI->getArgOperand(0); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); - VectorType *VecTy = cast<VectorType>(CI->getType()); + auto *VecTy = cast<FixedVectorType>(CI->getType()); unsigned NumElts = VecTy->getNumElements(); // Calculate the size of each index in the immediate. unsigned IdxSize = 64 / VecTy->getScalarSizeInBits(); @@ -2621,7 +2715,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.pshufl.w."))) { Value *Op0 = CI->getArgOperand(0); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); - unsigned NumElts = cast<VectorType>(CI->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); SmallVector<int, 16> Idxs(NumElts); for (unsigned l = 0; l != NumElts; l += 8) { @@ -2640,7 +2734,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.pshufh.w."))) { Value *Op0 = CI->getArgOperand(0); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); - unsigned NumElts = cast<VectorType>(CI->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); SmallVector<int, 16> Idxs(NumElts); for (unsigned l = 0; l != NumElts; l += 8) { @@ -2659,7 +2753,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Value *Op0 = CI->getArgOperand(0); Value *Op1 = CI->getArgOperand(1); unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); - unsigned NumElts = cast<VectorType>(CI->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); unsigned NumLaneElts = 128/CI->getType()->getScalarSizeInBits(); unsigned HalfLaneElts = NumLaneElts / 2; @@ -2684,7 +2778,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.movshdup") || Name.startswith("avx512.mask.movsldup"))) { Value *Op0 = CI->getArgOperand(0); - unsigned NumElts = cast<VectorType>(CI->getType())->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); unsigned NumLaneElts = 128/CI->getType()->getScalarSizeInBits(); unsigned Offset = 0; @@ -2706,7 +2800,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.unpckl."))) { Value *Op0 = CI->getArgOperand(0); Value *Op1 = CI->getArgOperand(1); - int NumElts = cast<VectorType>(CI->getType())->getNumElements(); + int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); int NumLaneElts = 128/CI->getType()->getScalarSizeInBits(); SmallVector<int, 64> Idxs(NumElts); @@ -2722,7 +2816,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Name.startswith("avx512.mask.unpckh."))) { Value *Op0 = CI->getArgOperand(0); Value *Op1 = CI->getArgOperand(1); - int NumElts = cast<VectorType>(CI->getType())->getNumElements(); + int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); int NumLaneElts = 128/CI->getType()->getScalarSizeInBits(); SmallVector<int, 64> Idxs(NumElts); @@ -3290,7 +3384,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), Ops); } else { - int NumElts = cast<VectorType>(CI->getType())->getNumElements(); + int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); Value *Ops[] = { CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2) }; @@ -3547,28 +3641,6 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { DefaultCase(); return; } - case Intrinsic::experimental_vector_reduce_v2_fmul: { - SmallVector<Value *, 2> Args; - if (CI->isFast()) - Args.push_back(ConstantFP::get(CI->getOperand(0)->getType(), 1.0)); - else - Args.push_back(CI->getOperand(0)); - Args.push_back(CI->getOperand(1)); - NewCall = Builder.CreateCall(NewFn, Args); - cast<Instruction>(NewCall)->copyFastMathFlags(CI); - break; - } - case Intrinsic::experimental_vector_reduce_v2_fadd: { - SmallVector<Value *, 2> Args; - if (CI->isFast()) - Args.push_back(Constant::getNullValue(CI->getOperand(0)->getType())); - else - Args.push_back(CI->getOperand(0)); - Args.push_back(CI->getOperand(1)); - NewCall = Builder.CreateCall(NewFn, Args); - cast<Instruction>(NewCall)->copyFastMathFlags(CI); - break; - } case Intrinsic::arm_neon_vld1: case Intrinsic::arm_neon_vld2: case Intrinsic::arm_neon_vld3: @@ -3589,6 +3661,30 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { break; } + case Intrinsic::arm_neon_bfdot: + case Intrinsic::arm_neon_bfmmla: + case Intrinsic::arm_neon_bfmlalb: + case Intrinsic::arm_neon_bfmlalt: + case Intrinsic::aarch64_neon_bfdot: + case Intrinsic::aarch64_neon_bfmmla: + case Intrinsic::aarch64_neon_bfmlalb: + case Intrinsic::aarch64_neon_bfmlalt: { + SmallVector<Value *, 3> Args; + assert(CI->getNumArgOperands() == 3 && + "Mismatch between function args and call args"); + size_t OperandWidth = + CI->getArgOperand(1)->getType()->getPrimitiveSizeInBits(); + assert((OperandWidth == 64 || OperandWidth == 128) && + "Unexpected operand width"); + Type *NewTy = FixedVectorType::get(Type::getBFloatTy(C), OperandWidth / 16); + auto Iter = CI->arg_operands().begin(); + Args.push_back(*Iter++); + Args.push_back(Builder.CreateBitCast(*Iter++, NewTy)); + Args.push_back(Builder.CreateBitCast(*Iter++, NewTy)); + NewCall = Builder.CreateCall(NewFn, Args); + break; + } + case Intrinsic::bitreverse: NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0)}); break; @@ -3691,11 +3787,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { // Replace the original call result with the first result of the new call. Value *TSC = Builder.CreateExtractValue(NewCall, 0); - std::string Name = std::string(CI->getName()); - if (!Name.empty()) { - CI->setName(Name + ".old"); - NewCall->setName(Name); - } + NewCall->takeName(CI); CI->replaceAllUsesWith(TSC); CI->eraseFromParent(); return; @@ -3718,6 +3810,27 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { break; } + case Intrinsic::x86_avx512_mask_cmp_pd_128: + case Intrinsic::x86_avx512_mask_cmp_pd_256: + case Intrinsic::x86_avx512_mask_cmp_pd_512: + case Intrinsic::x86_avx512_mask_cmp_ps_128: + case Intrinsic::x86_avx512_mask_cmp_ps_256: + case Intrinsic::x86_avx512_mask_cmp_ps_512: { + SmallVector<Value *, 4> Args(CI->arg_operands().begin(), + CI->arg_operands().end()); + unsigned NumElts = + cast<FixedVectorType>(Args[0]->getType())->getNumElements(); + Args[3] = getX86MaskVec(Builder, Args[3], NumElts); + + NewCall = Builder.CreateCall(NewFn, Args); + Value *Res = ApplyX86MaskOn1BitsVec(Builder, NewCall, nullptr); + + NewCall->takeName(CI); + CI->replaceAllUsesWith(Res); + CI->eraseFromParent(); + return; + } + case Intrinsic::thread_pointer: { NewCall = Builder.CreateCall(NewFn, {}); break; @@ -3766,11 +3879,7 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { } assert(NewCall && "Should have either set this variable or returned through " "the default case"); - std::string Name = std::string(CI->getName()); - if (!Name.empty()) { - CI->setName(Name + ".old"); - NewCall->setName(Name); - } + NewCall->takeName(CI); CI->replaceAllUsesWith(NewCall); CI->eraseFromParent(); } @@ -3784,8 +3893,8 @@ void llvm::UpgradeCallsToIntrinsic(Function *F) { if (UpgradeIntrinsicFunction(F, NewFn)) { // Replace all users of the old function with the new function or new // instructions. This is not a range loop because the call is deleted. - for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE; ) - if (CallInst *CI = dyn_cast<CallInst>(*UI++)) + for (User *U : make_early_inc_range(F->users())) + if (CallInst *CI = dyn_cast<CallInst>(U)) UpgradeIntrinsicCall(CI, NewFn); // Remove old function, no longer used, from the module. @@ -3921,8 +4030,8 @@ void llvm::UpgradeARCRuntime(Module &M) { Function *NewFn = llvm::Intrinsic::getDeclaration(&M, IntrinsicFunc); - for (auto I = Fn->user_begin(), E = Fn->user_end(); I != E;) { - CallInst *CI = dyn_cast<CallInst>(*I++); + for (User *U : make_early_inc_range(Fn->users())) { + CallInst *CI = dyn_cast<CallInst>(U); if (!CI || CI->getCalledFunction() != Fn) continue; @@ -3963,7 +4072,7 @@ void llvm::UpgradeARCRuntime(Module &M) { // Create a call instruction that calls the new function. CallInst *NewCall = Builder.CreateCall(NewFuncTy, NewFn, Args); NewCall->setTailCallKind(cast<CallInst>(CI)->getTailCallKind()); - NewCall->setName(CI->getName()); + NewCall->takeName(CI); // Bitcast the return value back to the type of the old call. Value *NewRetVal = Builder.CreateBitCast(NewCall, CI->getType()); @@ -4202,6 +4311,13 @@ void llvm::UpgradeFunctionAttributes(Function &F) { StrictFPUpgradeVisitor SFPV; SFPV.visit(F); } + + if (F.getCallingConv() == CallingConv::X86_INTR && + !F.arg_empty() && !F.hasParamAttribute(0, Attribute::ByVal)) { + Type *ByValTy = cast<PointerType>(F.getArg(0)->getType())->getElementType(); + Attribute NewAttr = Attribute::getWithByValType(F.getContext(), ByValTy); + F.addParamAttr(0, NewAttr); + } } static bool isOldLoopArgument(Metadata *MD) { @@ -4267,11 +4383,17 @@ MDNode *llvm::upgradeInstructionLoopAttachment(MDNode &N) { } std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) { - std::string AddrSpaces = "-p270:32:32-p271:32:32-p272:64:64"; + Triple T(TT); + // For AMDGPU we uprgrade older DataLayouts to include the default globals + // address space of 1. + if (T.isAMDGPU() && !DL.contains("-G") && !DL.startswith("G")) { + return DL.empty() ? std::string("G1") : (DL + "-G1").str(); + } + std::string AddrSpaces = "-p270:32:32-p271:32:32-p272:64:64"; // If X86, and the datalayout matches the expected format, add pointer size // address spaces to the datalayout. - if (!Triple(TT).isX86() || DL.contains(AddrSpaces)) + if (!T.isX86() || DL.contains(AddrSpaces)) return std::string(DL); SmallVector<StringRef, 4> Groups; @@ -4279,9 +4401,7 @@ std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) { if (!R.match(DL, &Groups)) return std::string(DL); - SmallString<1024> Buf; - std::string Res = (Groups[1] + AddrSpaces + Groups[3]).toStringRef(Buf).str(); - return Res; + return (Groups[1] + AddrSpaces + Groups[3]).str(); } void llvm::UpgradeAttributes(AttrBuilder &B) { diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index 64f1d3f3100c..00ef10dd53af 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -97,18 +97,20 @@ void BasicBlock::setParent(Function *parent) { iterator_range<filter_iterator<BasicBlock::const_iterator, std::function<bool(const Instruction &)>>> -BasicBlock::instructionsWithoutDebug() const { - std::function<bool(const Instruction &)> Fn = [](const Instruction &I) { - return !isa<DbgInfoIntrinsic>(I); +BasicBlock::instructionsWithoutDebug(bool SkipPseudoOp) const { + std::function<bool(const Instruction &)> Fn = [=](const Instruction &I) { + return !isa<DbgInfoIntrinsic>(I) && + !(SkipPseudoOp && isa<PseudoProbeInst>(I)); }; return make_filter_range(*this, Fn); } -iterator_range<filter_iterator<BasicBlock::iterator, - std::function<bool(Instruction &)>>> -BasicBlock::instructionsWithoutDebug() { - std::function<bool(Instruction &)> Fn = [](Instruction &I) { - return !isa<DbgInfoIntrinsic>(I); +iterator_range< + filter_iterator<BasicBlock::iterator, std::function<bool(Instruction &)>>> +BasicBlock::instructionsWithoutDebug(bool SkipPseudoOp) { + std::function<bool(Instruction &)> Fn = [=](Instruction &I) { + return !isa<DbgInfoIntrinsic>(I) && + !(SkipPseudoOp && isa<PseudoProbeInst>(I)); }; return make_filter_range(*this, Fn); } @@ -128,15 +130,11 @@ iplist<BasicBlock>::iterator BasicBlock::eraseFromParent() { return getParent()->getBasicBlockList().erase(getIterator()); } -/// Unlink this basic block from its current function and -/// insert it into the function that MovePos lives in, right before MovePos. void BasicBlock::moveBefore(BasicBlock *MovePos) { MovePos->getParent()->getBasicBlockList().splice( MovePos->getIterator(), getParent()->getBasicBlockList(), getIterator()); } -/// Unlink this basic block from its current function and -/// insert it into the function that MovePos lives in, right after MovePos. void BasicBlock::moveAfter(BasicBlock *MovePos) { MovePos->getParent()->getBasicBlockList().splice( ++MovePos->getIterator(), getParent()->getBasicBlockList(), @@ -218,14 +216,21 @@ const Instruction* BasicBlock::getFirstNonPHI() const { return nullptr; } -const Instruction* BasicBlock::getFirstNonPHIOrDbg() const { - for (const Instruction &I : *this) - if (!isa<PHINode>(I) && !isa<DbgInfoIntrinsic>(I)) - return &I; +const Instruction *BasicBlock::getFirstNonPHIOrDbg(bool SkipPseudoOp) const { + for (const Instruction &I : *this) { + if (isa<PHINode>(I) || isa<DbgInfoIntrinsic>(I)) + continue; + + if (SkipPseudoOp && isa<PseudoProbeInst>(I)) + continue; + + return &I; + } return nullptr; } -const Instruction* BasicBlock::getFirstNonPHIOrDbgOrLifetime() const { +const Instruction * +BasicBlock::getFirstNonPHIOrDbgOrLifetime(bool SkipPseudoOp) const { for (const Instruction &I : *this) { if (isa<PHINode>(I) || isa<DbgInfoIntrinsic>(I)) continue; @@ -233,6 +238,9 @@ const Instruction* BasicBlock::getFirstNonPHIOrDbgOrLifetime() const { if (I.isLifetimeStartOrEnd()) continue; + if (SkipPseudoOp && isa<PseudoProbeInst>(I)) + continue; + return &I; } return nullptr; @@ -253,8 +261,6 @@ void BasicBlock::dropAllReferences() { I.dropAllReferences(); } -/// If this basic block has a single predecessor block, -/// return the block, otherwise return a null pointer. const BasicBlock *BasicBlock::getSinglePredecessor() const { const_pred_iterator PI = pred_begin(this), E = pred_end(this); if (PI == E) return nullptr; // No preds. @@ -263,11 +269,6 @@ const BasicBlock *BasicBlock::getSinglePredecessor() const { return (PI == E) ? ThePred : nullptr /*multiple preds*/; } -/// If this basic block has a unique predecessor block, -/// return the block, otherwise return a null pointer. -/// Note that unique predecessor doesn't mean single edge, there can be -/// multiple edges from the unique predecessor to this block (for example -/// a switch statement with multiple cases having the same destination). const BasicBlock *BasicBlock::getUniquePredecessor() const { const_pred_iterator PI = pred_begin(this), E = pred_end(this); if (PI == E) return nullptr; // No preds. @@ -317,38 +318,31 @@ iterator_range<BasicBlock::phi_iterator> BasicBlock::phis() { return make_range<phi_iterator>(P, nullptr); } -/// Update PHI nodes in this BasicBlock before removal of predecessor \p Pred. -/// Note that this function does not actually remove the predecessor. -/// -/// If \p KeepOneInputPHIs is true then don't remove PHIs that are left with -/// zero or one incoming values, and don't simplify PHIs with all incoming -/// values the same. void BasicBlock::removePredecessor(BasicBlock *Pred, bool KeepOneInputPHIs) { // Use hasNUsesOrMore to bound the cost of this assertion for complex CFGs. - assert((hasNUsesOrMore(16) || - find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) && + assert((hasNUsesOrMore(16) || llvm::is_contained(predecessors(this), Pred)) && "Pred is not a predecessor!"); // Return early if there are no PHI nodes to update. - if (!isa<PHINode>(begin())) + if (empty() || !isa<PHINode>(begin())) return; + unsigned NumPreds = cast<PHINode>(front()).getNumIncomingValues(); + for (PHINode &Phi : make_early_inc_range(phis())) { + Phi.removeIncomingValue(Pred, !KeepOneInputPHIs); + if (KeepOneInputPHIs) + continue; + + // If we have a single predecessor, removeIncomingValue may have erased the + // PHI node itself. + if (NumPreds == 1) + continue; - // Update all PHI nodes. - for (iterator II = begin(); isa<PHINode>(II);) { - PHINode *PN = cast<PHINode>(II++); - PN->removeIncomingValue(Pred, !KeepOneInputPHIs); - if (!KeepOneInputPHIs) { - // If we have a single predecessor, removeIncomingValue erased the PHI - // node itself. - if (NumPreds > 1) { - if (Value *PNV = PN->hasConstantValue()) { - // Replace the PHI node with its constant value. - PN->replaceAllUsesWith(PNV); - PN->eraseFromParent(); - } - } + // Try to replace the PHI node with a constant value. + if (Value *PhiConstant = Phi.hasConstantValue()) { + Phi.replaceAllUsesWith(PhiConstant); + Phi.eraseFromParent(); } } } @@ -378,18 +372,11 @@ bool BasicBlock::isLegalToHoistInto() const { return !Term->isExceptionalTerminator(); } -/// This splits a basic block into two at the specified -/// instruction. Note that all instructions BEFORE the specified iterator stay -/// as part of the original basic block, an unconditional branch is added to -/// the new BB, and the rest of the instructions in the BB are moved to the new -/// BB, including the old terminator. This invalidates the iterator. -/// -/// Note that this only works on well formed basic blocks (must have a -/// terminator), and 'I' must not be the end of instruction list (which would -/// cause a degenerate basic block to be formed, having a terminator inside of -/// the basic block). -/// -BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) { +BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName, + bool Before) { + if (Before) + return splitBasicBlockBefore(I, BBName); + assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!"); assert(I != InstList.end() && "Trying to get me to create degenerate basic block!"); @@ -416,6 +403,40 @@ BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) { return New; } +BasicBlock *BasicBlock::splitBasicBlockBefore(iterator I, const Twine &BBName) { + assert(getTerminator() && + "Can't use splitBasicBlockBefore on degenerate BB!"); + assert(I != InstList.end() && + "Trying to get me to create degenerate basic block!"); + + assert((!isa<PHINode>(*I) || getSinglePredecessor()) && + "cannot split on multi incoming phis"); + + BasicBlock *New = BasicBlock::Create(getContext(), BBName, getParent(), this); + // Save DebugLoc of split point before invalidating iterator. + DebugLoc Loc = I->getDebugLoc(); + // Move all of the specified instructions from the original basic block into + // the new basic block. + New->getInstList().splice(New->end(), this->getInstList(), begin(), I); + + // Loop through all of the predecessors of the 'this' block (which will be the + // predecessors of the New block), replace the specified successor 'this' + // block to point at the New block and update any PHI nodes in 'this' block. + // If there were PHI nodes in 'this' block, the PHI nodes are updated + // to reflect that the incoming branches will be from the New block and not + // from predecessors of the 'this' block. + for (BasicBlock *Pred : predecessors(this)) { + Instruction *TI = Pred->getTerminator(); + TI->replaceSuccessorWith(this, New); + this->replacePhiUsesWith(Pred, New); + } + // Add a branch instruction from "New" to "this" Block. + BranchInst *BI = BranchInst::Create(this, New); + BI->setDebugLoc(Loc); + + return New; +} + void BasicBlock::replacePhiUsesWith(BasicBlock *Old, BasicBlock *New) { // N.B. This might not be a complete BasicBlock, so don't assume // that it ends with a non-phi instruction. @@ -443,13 +464,10 @@ void BasicBlock::replaceSuccessorsPhiUsesWith(BasicBlock *New) { this->replaceSuccessorsPhiUsesWith(this, New); } -/// Return true if this basic block is a landing pad. I.e., it's -/// the destination of the 'unwind' edge of an invoke instruction. bool BasicBlock::isLandingPad() const { return isa<LandingPadInst>(getFirstNonPHI()); } -/// Return the landingpad instruction associated with the landing pad. const LandingPadInst *BasicBlock::getLandingPadInst() const { return dyn_cast<LandingPadInst>(getFirstNonPHI()); } diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index f02246cda7fc..03cb108cc485 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -522,6 +522,9 @@ static Constant *getFoldedOffsetOf(Type *Ty, Constant *FieldNo, Type *DestTy, Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, Type *DestTy) { + if (isa<PoisonValue>(V)) + return PoisonValue::get(DestTy); + if (isa<UndefValue>(V)) { // zext(undef) = 0, because the top bits will be zero. // sext(undef) = 0, because the top bits will all be the same. @@ -532,7 +535,7 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, return UndefValue::get(DestTy); } - if (V->isNullValue() && !DestTy->isX86_MMXTy() && + if (V->isNullValue() && !DestTy->isX86_MMXTy() && !DestTy->isX86_AMXTy() && opc != Instruction::AddrSpaceCast) return Constant::getNullValue(DestTy); @@ -627,7 +630,7 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, V.convertToInteger(IntVal, APFloat::rmTowardZero, &ignored)) { // Undefined behavior invoked - the destination type can't represent // the input constant. - return UndefValue::get(DestTy); + return PoisonValue::get(DestTy); } return ConstantInt::get(FPC->getContext(), IntVal); } @@ -759,7 +762,9 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond, Constant *V2Element = ConstantExpr::getExtractElement(V2, ConstantInt::get(Ty, i)); auto *Cond = cast<Constant>(CondV->getOperand(i)); - if (V1Element == V2Element) { + if (isa<PoisonValue>(Cond)) { + V = PoisonValue::get(V1Element->getType()); + } else if (V1Element == V2Element) { V = V1Element; } else if (isa<UndefValue>(Cond)) { V = isa<UndefValue>(V1Element) ? V1Element : V2Element; @@ -775,6 +780,9 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond, return ConstantVector::get(Result); } + if (isa<PoisonValue>(Cond)) + return PoisonValue::get(V1->getType()); + if (isa<UndefValue>(Cond)) { if (isa<UndefValue>(V1)) return V1; return V2; @@ -782,9 +790,17 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond, if (V1 == V2) return V1; + if (isa<PoisonValue>(V1)) + return V2; + if (isa<PoisonValue>(V2)) + return V1; + // If the true or false value is undef, we can fold to the other value as // long as the other value isn't poison. auto NotPoison = [](Constant *C) { + if (isa<PoisonValue>(C)) + return false; + // TODO: We can analyze ConstExpr by opcode to determine if there is any // possibility of poison. if (isa<ConstantExpr>(C)) @@ -795,7 +811,7 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond, return true; if (C->getType()->isVectorTy()) - return !C->containsUndefElement() && !C->containsConstantExpression(); + return !C->containsPoisonElement() && !C->containsConstantExpression(); // TODO: Recursively analyze aggregates or other constants. return false; @@ -821,9 +837,13 @@ Constant *llvm::ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx) { auto *ValVTy = cast<VectorType>(Val->getType()); + // extractelt poison, C -> poison + // extractelt C, undef -> poison + if (isa<PoisonValue>(Val) || isa<UndefValue>(Idx)) + return PoisonValue::get(ValVTy->getElementType()); + // extractelt undef, C -> undef - // extractelt C, undef -> undef - if (isa<UndefValue>(Val) || isa<UndefValue>(Idx)) + if (isa<UndefValue>(Val)) return UndefValue::get(ValVTy->getElementType()); auto *CIdx = dyn_cast<ConstantInt>(Idx); @@ -831,9 +851,9 @@ Constant *llvm::ConstantFoldExtractElementInstruction(Constant *Val, return nullptr; if (auto *ValFVTy = dyn_cast<FixedVectorType>(Val->getType())) { - // ee({w,x,y,z}, wrong_value) -> undef + // ee({w,x,y,z}, wrong_value) -> poison if (CIdx->uge(ValFVTy->getNumElements())) - return UndefValue::get(ValFVTy->getElementType()); + return PoisonValue::get(ValFVTy->getElementType()); } // ee (gep (ptr, idx0, ...), idx) -> gep (ee (ptr, idx), ee (idx0, idx), ...) @@ -853,6 +873,15 @@ Constant *llvm::ConstantFoldExtractElementInstruction(Constant *Val, } return CE->getWithOperands(Ops, ValVTy->getElementType(), false, Ops[0]->getType()->getPointerElementType()); + } else if (CE->getOpcode() == Instruction::InsertElement) { + if (const auto *IEIdx = dyn_cast<ConstantInt>(CE->getOperand(2))) { + if (APSInt::isSameValue(APSInt(IEIdx->getValue()), + APSInt(CIdx->getValue()))) { + return CE->getOperand(1); + } else { + return ConstantExpr::getExtractElement(CE->getOperand(0), CIdx); + } + } } } @@ -873,7 +902,7 @@ Constant *llvm::ConstantFoldInsertElementInstruction(Constant *Val, Constant *Elt, Constant *Idx) { if (isa<UndefValue>(Idx)) - return UndefValue::get(Val->getType()); + return PoisonValue::get(Val->getType()); ConstantInt *CIdx = dyn_cast<ConstantInt>(Idx); if (!CIdx) return nullptr; @@ -887,7 +916,7 @@ Constant *llvm::ConstantFoldInsertElementInstruction(Constant *Val, unsigned NumElts = ValTy->getNumElements(); if (CIdx->uge(NumElts)) - return UndefValue::get(Val->getType()); + return PoisonValue::get(Val->getType()); SmallVector<Constant*, 16> Result; Result.reserve(NumElts); @@ -910,7 +939,8 @@ Constant *llvm::ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2, ArrayRef<int> Mask) { auto *V1VTy = cast<VectorType>(V1->getType()); unsigned MaskNumElts = Mask.size(); - ElementCount MaskEltCount = {MaskNumElts, isa<ScalableVectorType>(V1VTy)}; + auto MaskEltCount = + ElementCount::get(MaskNumElts, isa<ScalableVectorType>(V1VTy)); Type *EltTy = V1VTy->getElementType(); // Undefined shuffle mask -> undefined value. @@ -921,7 +951,7 @@ Constant *llvm::ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2, // If the mask is all zeros this is a splat, no need to go through all // elements. if (all_of(Mask, [](int Elt) { return Elt == 0; }) && - !MaskEltCount.Scalable) { + !MaskEltCount.isScalable()) { Type *Ty = IntegerType::get(V1->getContext(), 32); Constant *Elt = ConstantExpr::getExtractElement(V1, ConstantInt::get(Ty, 0)); @@ -932,7 +962,7 @@ Constant *llvm::ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2, if (isa<ScalableVectorType>(V1VTy)) return nullptr; - unsigned SrcNumElts = V1VTy->getElementCount().Min; + unsigned SrcNumElts = V1VTy->getElementCount().getKnownMinValue(); // Loop over the shuffle mask, evaluating each element. SmallVector<Constant*, 32> Result; @@ -1074,6 +1104,17 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, return C1; } + // Binary operations propagate poison. + // FIXME: Currently, or/and i1 poison aren't folded into poison because + // it causes miscompilation when combined with another optimization in + // InstCombine (select i1 -> and/or). The select fold is wrong, but + // fixing it requires an effort, so temporarily disable this until it is + // fixed. + bool PoisonFold = !C1->getType()->isIntegerTy(1) || + (Opcode != Instruction::Or && Opcode != Instruction::And); + if (PoisonFold && (isa<PoisonValue>(C1) || isa<PoisonValue>(C2))) + return PoisonValue::get(C1->getType()); + // Handle scalar UndefValue and scalable vector UndefValue. Fixed-length // vectors are always evaluated per element. bool IsScalableVector = isa<ScalableVectorType>(C1->getType()); @@ -1110,23 +1151,21 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, } case Instruction::SDiv: case Instruction::UDiv: - // X / undef -> undef - if (isa<UndefValue>(C2)) - return C2; - // undef / 0 -> undef + // X / undef -> poison + // X / 0 -> poison + if (match(C2, m_CombineOr(m_Undef(), m_Zero()))) + return PoisonValue::get(C2->getType()); // undef / 1 -> undef - if (match(C2, m_Zero()) || match(C2, m_One())) + if (match(C2, m_One())) return C1; // undef / X -> 0 otherwise return Constant::getNullValue(C1->getType()); case Instruction::URem: case Instruction::SRem: - // X % undef -> undef - if (match(C2, m_Undef())) - return C2; - // undef % 0 -> undef - if (match(C2, m_Zero())) - return C1; + // X % undef -> poison + // X % 0 -> poison + if (match(C2, m_CombineOr(m_Undef(), m_Zero()))) + return PoisonValue::get(C2->getType()); // undef % X -> 0 otherwise return Constant::getNullValue(C1->getType()); case Instruction::Or: // X | undef -> -1 @@ -1134,28 +1173,28 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, return C1; return Constant::getAllOnesValue(C1->getType()); // undef | X -> ~0 case Instruction::LShr: - // X >>l undef -> undef + // X >>l undef -> poison if (isa<UndefValue>(C2)) - return C2; + return PoisonValue::get(C2->getType()); // undef >>l 0 -> undef if (match(C2, m_Zero())) return C1; // undef >>l X -> 0 return Constant::getNullValue(C1->getType()); case Instruction::AShr: - // X >>a undef -> undef + // X >>a undef -> poison if (isa<UndefValue>(C2)) - return C2; + return PoisonValue::get(C2->getType()); // undef >>a 0 -> undef if (match(C2, m_Zero())) return C1; - // TODO: undef >>a X -> undef if the shift is exact + // TODO: undef >>a X -> poison if the shift is exact // undef >>a X -> 0 return Constant::getNullValue(C1->getType()); case Instruction::Shl: // X << undef -> undef if (isa<UndefValue>(C2)) - return C2; + return PoisonValue::get(C2->getType()); // undef << 0 -> undef if (match(C2, m_Zero())) return C1; @@ -1208,14 +1247,14 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, if (CI2->isOne()) return C1; // X / 1 == X if (CI2->isZero()) - return UndefValue::get(CI2->getType()); // X / 0 == undef + return PoisonValue::get(CI2->getType()); // X / 0 == poison break; case Instruction::URem: case Instruction::SRem: if (CI2->isOne()) return Constant::getNullValue(CI2->getType()); // X % 1 == 0 if (CI2->isZero()) - return UndefValue::get(CI2->getType()); // X % 0 == undef + return PoisonValue::get(CI2->getType()); // X % 0 == poison break; case Instruction::And: if (CI2->isZero()) return C2; // X & 0 == 0 @@ -1329,7 +1368,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, case Instruction::SDiv: assert(!CI2->isZero() && "Div by zero handled above"); if (C2V.isAllOnesValue() && C1V.isMinSignedValue()) - return UndefValue::get(CI1->getType()); // MIN_INT / -1 -> undef + return PoisonValue::get(CI1->getType()); // MIN_INT / -1 -> poison return ConstantInt::get(CI1->getContext(), C1V.sdiv(C2V)); case Instruction::URem: assert(!CI2->isZero() && "Div by zero handled above"); @@ -1337,7 +1376,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, case Instruction::SRem: assert(!CI2->isZero() && "Div by zero handled above"); if (C2V.isAllOnesValue() && C1V.isMinSignedValue()) - return UndefValue::get(CI1->getType()); // MIN_INT % -1 -> undef + return PoisonValue::get(CI1->getType()); // MIN_INT % -1 -> poison return ConstantInt::get(CI1->getContext(), C1V.srem(C2V)); case Instruction::And: return ConstantInt::get(CI1->getContext(), C1V & C2V); @@ -1348,15 +1387,15 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, case Instruction::Shl: if (C2V.ult(C1V.getBitWidth())) return ConstantInt::get(CI1->getContext(), C1V.shl(C2V)); - return UndefValue::get(C1->getType()); // too big shift is undef + return PoisonValue::get(C1->getType()); // too big shift is poison case Instruction::LShr: if (C2V.ult(C1V.getBitWidth())) return ConstantInt::get(CI1->getContext(), C1V.lshr(C2V)); - return UndefValue::get(C1->getType()); // too big shift is undef + return PoisonValue::get(C1->getType()); // too big shift is poison case Instruction::AShr: if (C2V.ult(C1V.getBitWidth())) return ConstantInt::get(CI1->getContext(), C1V.ashr(C2V)); - return UndefValue::get(C1->getType()); // too big shift is undef + return PoisonValue::get(C1->getType()); // too big shift is poison } } @@ -1398,16 +1437,11 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, return ConstantFP::get(C1->getContext(), C3V); } } - } else if (IsScalableVector) { - // Do not iterate on scalable vector. The number of elements is unknown at - // compile-time. - // FIXME: this branch can potentially be removed - return nullptr; - } else if (auto *VTy = dyn_cast<FixedVectorType>(C1->getType())) { + } else if (auto *VTy = dyn_cast<VectorType>(C1->getType())) { // Fast path for splatted constants. if (Constant *C2Splat = C2->getSplatValue()) { if (Instruction::isIntDivRem(Opcode) && C2Splat->isNullValue()) - return UndefValue::get(VTy); + return PoisonValue::get(VTy); if (Constant *C1Splat = C1->getSplatValue()) { return ConstantVector::getSplat( VTy->getElementCount(), @@ -1415,22 +1449,24 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, } } - // Fold each element and create a vector constant from those constants. - SmallVector<Constant*, 16> Result; - Type *Ty = IntegerType::get(VTy->getContext(), 32); - for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) { - Constant *ExtractIdx = ConstantInt::get(Ty, i); - Constant *LHS = ConstantExpr::getExtractElement(C1, ExtractIdx); - Constant *RHS = ConstantExpr::getExtractElement(C2, ExtractIdx); + if (auto *FVTy = dyn_cast<FixedVectorType>(VTy)) { + // Fold each element and create a vector constant from those constants. + SmallVector<Constant*, 16> Result; + Type *Ty = IntegerType::get(FVTy->getContext(), 32); + for (unsigned i = 0, e = FVTy->getNumElements(); i != e; ++i) { + Constant *ExtractIdx = ConstantInt::get(Ty, i); + Constant *LHS = ConstantExpr::getExtractElement(C1, ExtractIdx); + Constant *RHS = ConstantExpr::getExtractElement(C2, ExtractIdx); - // If any element of a divisor vector is zero, the whole op is undef. - if (Instruction::isIntDivRem(Opcode) && RHS->isNullValue()) - return UndefValue::get(VTy); + // If any element of a divisor vector is zero, the whole op is poison. + if (Instruction::isIntDivRem(Opcode) && RHS->isNullValue()) + return PoisonValue::get(VTy); - Result.push_back(ConstantExpr::get(Opcode, LHS, RHS)); - } + Result.push_back(ConstantExpr::get(Opcode, LHS, RHS)); + } - return ConstantVector::get(Result); + return ConstantVector::get(Result); + } } if (ConstantExpr *CE1 = dyn_cast<ConstantExpr>(C1)) { @@ -1609,7 +1645,7 @@ static FCmpInst::Predicate evaluateFCmpRelation(Constant *V1, Constant *V2) { static ICmpInst::Predicate areGlobalsPotentiallyEqual(const GlobalValue *GV1, const GlobalValue *GV2) { auto isGlobalUnsafeForEquality = [](const GlobalValue *GV) { - if (GV->hasExternalWeakLinkage() || GV->hasWeakAnyLinkage()) + if (GV->isInterposable() || GV->hasGlobalUnnamedAddr()) return true; if (const auto *GVar = dyn_cast<GlobalVariable>(GV)) { Type *Ty = GVar->getValueType(); @@ -1744,9 +1780,15 @@ static ICmpInst::Predicate evaluateICmpRelation(Constant *V1, Constant *V2, case Instruction::FPToSI: break; // We can't evaluate floating point casts or truncations. + case Instruction::BitCast: + // If this is a global value cast, check to see if the RHS is also a + // GlobalValue. + if (const GlobalValue *GV = dyn_cast<GlobalValue>(CE1Op0)) + if (const GlobalValue *GV2 = dyn_cast<GlobalValue>(V2)) + return areGlobalsPotentiallyEqual(GV, GV2); + LLVM_FALLTHROUGH; case Instruction::UIToFP: case Instruction::SIToFP: - case Instruction::BitCast: case Instruction::ZExt: case Instruction::SExt: // We can't evaluate floating point casts or truncations. @@ -1909,6 +1951,9 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, return Constant::getAllOnesValue(ResultTy); // Handle some degenerate cases first + if (isa<PoisonValue>(C1) || isa<PoisonValue>(C2)) + return PoisonValue::get(ResultTy); + if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) { CmpInst::Predicate Predicate = CmpInst::Predicate(pred); bool isIntegerPredicate = ICmpInst::isIntPredicate(Predicate); @@ -2029,11 +2074,6 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, } } else if (auto *C1VTy = dyn_cast<VectorType>(C1->getType())) { - // Do not iterate on scalable vector. The number of elements is unknown at - // compile-time. - if (isa<ScalableVectorType>(C1VTy)) - return nullptr; - // Fast path for splatted constants. if (Constant *C1Splat = C1->getSplatValue()) if (Constant *C2Splat = C2->getSplatValue()) @@ -2041,16 +2081,22 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred, C1VTy->getElementCount(), ConstantExpr::getCompare(pred, C1Splat, C2Splat)); + // Do not iterate on scalable vector. The number of elements is unknown at + // compile-time. + if (isa<ScalableVectorType>(C1VTy)) + return nullptr; + // If we can constant fold the comparison of each element, constant fold // the whole vector comparison. SmallVector<Constant*, 4> ResElts; Type *Ty = IntegerType::get(C1->getContext(), 32); // Compare the elements, producing an i1 result or constant expr. - for (unsigned i = 0, e = C1VTy->getElementCount().Min; i != e; ++i) { + for (unsigned I = 0, E = C1VTy->getElementCount().getKnownMinValue(); + I != E; ++I) { Constant *C1E = - ConstantExpr::getExtractElement(C1, ConstantInt::get(Ty, i)); + ConstantExpr::getExtractElement(C1, ConstantInt::get(Ty, I)); Constant *C2E = - ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, i)); + ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, I)); ResElts.push_back(ConstantExpr::getCompare(pred, C1E, C2E)); } @@ -2293,8 +2339,12 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, Type *GEPTy = GetElementPtrInst::getGEPReturnType( PointeeTy, C, makeArrayRef((Value *const *)Idxs.data(), Idxs.size())); + if (isa<PoisonValue>(C)) + return PoisonValue::get(GEPTy); + if (isa<UndefValue>(C)) - return UndefValue::get(GEPTy); + // If inbounds, we can choose an out-of-bounds pointer as a base pointer. + return InBounds ? PoisonValue::get(GEPTy) : UndefValue::get(GEPTy); Constant *Idx0 = cast<Constant>(Idxs[0]); if (Idxs.size() == 1 && (Idx0->isNullValue() || isa<UndefValue>(Idx0))) diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index eabaaa203927..4b0ad1bd25a0 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Operator.h" #include "llvm/Support/Compiler.h" @@ -412,6 +413,21 @@ bool ConstantRange::contains(const ConstantRange &Other) const { return Other.getUpper().ule(Upper) && Lower.ule(Other.getLower()); } +unsigned ConstantRange::getActiveBits() const { + if (isEmptySet()) + return 0; + + return getUnsignedMax().getActiveBits(); +} + +unsigned ConstantRange::getMinSignedBits() const { + if (isEmptySet()) + return 0; + + return std::max(getSignedMin().getMinSignedBits(), + getSignedMax().getMinSignedBits()); +} + ConstantRange ConstantRange::subtract(const APInt &Val) const { assert(Val.getBitWidth() == getBitWidth() && "Wrong bit width"); // If the set is empty or full, don't modify the endpoints. @@ -835,6 +851,54 @@ ConstantRange ConstantRange::overflowingBinaryOp(Instruction::BinaryOps BinOp, } } +bool ConstantRange::isIntrinsicSupported(Intrinsic::ID IntrinsicID) { + switch (IntrinsicID) { + case Intrinsic::uadd_sat: + case Intrinsic::usub_sat: + case Intrinsic::sadd_sat: + case Intrinsic::ssub_sat: + case Intrinsic::umin: + case Intrinsic::umax: + case Intrinsic::smin: + case Intrinsic::smax: + case Intrinsic::abs: + return true; + default: + return false; + } +} + +ConstantRange ConstantRange::intrinsic(Intrinsic::ID IntrinsicID, + ArrayRef<ConstantRange> Ops) { + switch (IntrinsicID) { + case Intrinsic::uadd_sat: + return Ops[0].uadd_sat(Ops[1]); + case Intrinsic::usub_sat: + return Ops[0].usub_sat(Ops[1]); + case Intrinsic::sadd_sat: + return Ops[0].sadd_sat(Ops[1]); + case Intrinsic::ssub_sat: + return Ops[0].ssub_sat(Ops[1]); + case Intrinsic::umin: + return Ops[0].umin(Ops[1]); + case Intrinsic::umax: + return Ops[0].umax(Ops[1]); + case Intrinsic::smin: + return Ops[0].smin(Ops[1]); + case Intrinsic::smax: + return Ops[0].smax(Ops[1]); + case Intrinsic::abs: { + const APInt *IntMinIsPoison = Ops[1].getSingleElement(); + assert(IntMinIsPoison && "Must be known (immarg)"); + assert(IntMinIsPoison->getBitWidth() == 1 && "Must be boolean"); + return Ops[0].abs(IntMinIsPoison->getBoolValue()); + } + default: + assert(!isIntrinsicSupported(IntrinsicID) && "Shouldn't be supported"); + llvm_unreachable("Unsupported intrinsic"); + } +} + ConstantRange ConstantRange::add(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) @@ -1191,6 +1255,16 @@ ConstantRange ConstantRange::srem(const ConstantRange &RHS) const { return ConstantRange(std::move(Lower), std::move(Upper)); } +ConstantRange ConstantRange::binaryNot() const { + if (isEmptySet()) + return getEmpty(); + + if (isWrappedSet()) + return getFull(); + + return ConstantRange(APInt::getAllOnesValue(getBitWidth())).sub(*this); +} + ConstantRange ConstantRange::binaryAnd(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) @@ -1229,6 +1303,12 @@ ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { if (isSingleElement() && Other.isSingleElement()) return {*getSingleElement() ^ *Other.getSingleElement()}; + // Special-case binary complement, since we can give a precise answer. + if (Other.isSingleElement() && Other.getSingleElement()->isAllOnesValue()) + return binaryNot(); + if (isSingleElement() && getSingleElement()->isAllOnesValue()) + return Other.binaryNot(); + // TODO: replace this with something less conservative return getFull(); } @@ -1418,7 +1498,7 @@ ConstantRange ConstantRange::inverse() const { return ConstantRange(Upper, Lower); } -ConstantRange ConstantRange::abs() const { +ConstantRange ConstantRange::abs(bool IntMinIsPoison) const { if (isEmptySet()) return getEmpty(); @@ -1430,12 +1510,23 @@ ConstantRange ConstantRange::abs() const { else Lo = APIntOps::umin(Lower, -Upper + 1); - // SignedMin is included in the result range. - return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); + // If SignedMin is not poison, then it is included in the result range. + if (IntMinIsPoison) + return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth())); + else + return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); } APInt SMin = getSignedMin(), SMax = getSignedMax(); + // Skip SignedMin if it is poison. + if (IntMinIsPoison && SMin.isMinSignedValue()) { + // The range may become empty if it *only* contains SignedMin. + if (SMax.isMinSignedValue()) + return getEmpty(); + ++SMin; + } + // All non-negative. if (SMin.isNonNegative()) return *this; diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index cbbcca20ea51..6fd205c654a8 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -161,7 +161,7 @@ bool Constant::isNotOneValue() const { // Check that vectors don't contain 1 if (auto *VTy = dyn_cast<VectorType>(this->getType())) { - unsigned NumElts = VTy->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(VTy)->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) { Constant *Elt = this->getAggregateElement(i); if (!Elt || !Elt->isNotOneValue()) @@ -211,7 +211,7 @@ bool Constant::isNotMinSignedValue() const { // Check that vectors don't contain INT_MIN if (auto *VTy = dyn_cast<VectorType>(this->getType())) { - unsigned NumElts = VTy->getNumElements(); + unsigned NumElts = cast<FixedVectorType>(VTy)->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) { Constant *Elt = this->getAggregateElement(i); if (!Elt || !Elt->isNotMinSignedValue()) @@ -227,7 +227,7 @@ bool Constant::isNotMinSignedValue() const { bool Constant::isFiniteNonZeroFP() const { if (auto *CFP = dyn_cast<ConstantFP>(this)) return CFP->getValueAPF().isFiniteNonZero(); - auto *VTy = dyn_cast<VectorType>(getType()); + auto *VTy = dyn_cast<FixedVectorType>(getType()); if (!VTy) return false; for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) { @@ -304,23 +304,42 @@ bool Constant::isElementWiseEqual(Value *Y) const { return isa<UndefValue>(CmpEq) || match(CmpEq, m_One()); } -bool Constant::containsUndefElement() const { - if (auto *VTy = dyn_cast<VectorType>(getType())) { - for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) - if (isa<UndefValue>(getAggregateElement(i))) +static bool +containsUndefinedElement(const Constant *C, + function_ref<bool(const Constant *)> HasFn) { + if (auto *VTy = dyn_cast<VectorType>(C->getType())) { + if (HasFn(C)) + return true; + if (isa<ConstantAggregateZero>(C)) + return false; + if (isa<ScalableVectorType>(C->getType())) + return false; + + for (unsigned i = 0, e = cast<FixedVectorType>(VTy)->getNumElements(); + i != e; ++i) + if (HasFn(C->getAggregateElement(i))) return true; } return false; } +bool Constant::containsUndefOrPoisonElement() const { + return containsUndefinedElement( + this, [&](const auto *C) { return isa<UndefValue>(C); }); +} + +bool Constant::containsPoisonElement() const { + return containsUndefinedElement( + this, [&](const auto *C) { return isa<PoisonValue>(C); }); +} + bool Constant::containsConstantExpression() const { - if (auto *VTy = dyn_cast<VectorType>(getType())) { + if (auto *VTy = dyn_cast<FixedVectorType>(getType())) { for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) if (isa<ConstantExpr>(getAggregateElement(i))) return true; } - return false; } @@ -400,16 +419,23 @@ Constant *Constant::getAllOnesValue(Type *Ty) { } Constant *Constant::getAggregateElement(unsigned Elt) const { - if (const ConstantAggregate *CC = dyn_cast<ConstantAggregate>(this)) + if (const auto *CC = dyn_cast<ConstantAggregate>(this)) return Elt < CC->getNumOperands() ? CC->getOperand(Elt) : nullptr; - if (const ConstantAggregateZero *CAZ = dyn_cast<ConstantAggregateZero>(this)) + // FIXME: getNumElements() will fail for non-fixed vector types. + if (isa<ScalableVectorType>(getType())) + return nullptr; + + if (const auto *CAZ = dyn_cast<ConstantAggregateZero>(this)) return Elt < CAZ->getNumElements() ? CAZ->getElementValue(Elt) : nullptr; - if (const UndefValue *UV = dyn_cast<UndefValue>(this)) + if (const auto *PV = dyn_cast<PoisonValue>(this)) + return Elt < PV->getNumElements() ? PV->getElementValue(Elt) : nullptr; + + if (const auto *UV = dyn_cast<UndefValue>(this)) return Elt < UV->getNumElements() ? UV->getElementValue(Elt) : nullptr; - if (const ConstantDataSequential *CDS =dyn_cast<ConstantDataSequential>(this)) + if (const auto *CDS = dyn_cast<ConstantDataSequential>(this)) return Elt < CDS->getNumElements() ? CDS->getElementAsConstant(Elt) : nullptr; return nullptr; @@ -501,9 +527,15 @@ void llvm::deleteConstant(Constant *C) { case Constant::BlockAddressVal: delete static_cast<BlockAddress *>(C); break; + case Constant::DSOLocalEquivalentVal: + delete static_cast<DSOLocalEquivalent *>(C); + break; case Constant::UndefValueVal: delete static_cast<UndefValue *>(C); break; + case Constant::PoisonValueVal: + delete static_cast<PoisonValue *>(C); + break; case Constant::ConstantExprVal: if (isa<UnaryConstantExpr>(C)) delete static_cast<UnaryConstantExpr *>(C); @@ -646,10 +678,17 @@ bool Constant::needsRelocation() const { return false; // Relative pointers do not need to be dynamically relocated. - if (auto *LHSGV = dyn_cast<GlobalValue>(LHSOp0->stripPointerCasts())) - if (auto *RHSGV = dyn_cast<GlobalValue>(RHSOp0->stripPointerCasts())) + if (auto *RHSGV = + dyn_cast<GlobalValue>(RHSOp0->stripInBoundsConstantOffsets())) { + auto *LHS = LHSOp0->stripInBoundsConstantOffsets(); + if (auto *LHSGV = dyn_cast<GlobalValue>(LHS)) { if (LHSGV->isDSOLocal() && RHSGV->isDSOLocal()) return false; + } else if (isa<DSOLocalEquivalent>(LHS)) { + if (RHSGV->isDSOLocal()) + return false; + } + } } } } @@ -729,6 +768,40 @@ Constant *Constant::replaceUndefsWith(Constant *C, Constant *Replacement) { return ConstantVector::get(NewC); } +Constant *Constant::mergeUndefsWith(Constant *C, Constant *Other) { + assert(C && Other && "Expected non-nullptr constant arguments"); + if (match(C, m_Undef())) + return C; + + Type *Ty = C->getType(); + if (match(Other, m_Undef())) + return UndefValue::get(Ty); + + auto *VTy = dyn_cast<FixedVectorType>(Ty); + if (!VTy) + return C; + + Type *EltTy = VTy->getElementType(); + unsigned NumElts = VTy->getNumElements(); + assert(isa<FixedVectorType>(Other->getType()) && + cast<FixedVectorType>(Other->getType())->getNumElements() == NumElts && + "Type mismatch"); + + bool FoundExtraUndef = false; + SmallVector<Constant *, 32> NewC(NumElts); + for (unsigned I = 0; I != NumElts; ++I) { + NewC[I] = C->getAggregateElement(I); + Constant *OtherEltC = Other->getAggregateElement(I); + assert(NewC[I] && OtherEltC && "Unknown vector element"); + if (!match(NewC[I], m_Undef()) && match(OtherEltC, m_Undef())) { + NewC[I] = UndefValue::get(EltTy); + FoundExtraUndef = true; + } + } + if (FoundExtraUndef) + return ConstantVector::get(NewC); + return C; +} //===----------------------------------------------------------------------===// // ConstantInt @@ -753,6 +826,10 @@ ConstantInt *ConstantInt::getFalse(LLVMContext &Context) { return pImpl->TheFalseVal; } +ConstantInt *ConstantInt::getBool(LLVMContext &Context, bool V) { + return V ? getTrue(Context) : getFalse(Context); +} + Constant *ConstantInt::getTrue(Type *Ty) { assert(Ty->isIntOrIntVectorTy(1) && "Type not i1 or vector of i1."); ConstantInt *TrueC = ConstantInt::getTrue(Ty->getContext()); @@ -769,6 +846,10 @@ Constant *ConstantInt::getFalse(Type *Ty) { return FalseC; } +Constant *ConstantInt::getBool(Type *Ty, bool V) { + return V ? getTrue(Ty) : getFalse(Ty); +} + // Get a ConstantInt from an APInt. ConstantInt *ConstantInt::get(LLVMContext &Context, const APInt &V) { // get an existing value or the insertion position @@ -830,30 +911,12 @@ void ConstantInt::destroyConstantImpl() { // ConstantFP //===----------------------------------------------------------------------===// -static const fltSemantics *TypeToFloatSemantics(Type *Ty) { - if (Ty->isHalfTy()) - return &APFloat::IEEEhalf(); - if (Ty->isBFloatTy()) - return &APFloat::BFloat(); - if (Ty->isFloatTy()) - return &APFloat::IEEEsingle(); - if (Ty->isDoubleTy()) - return &APFloat::IEEEdouble(); - if (Ty->isX86_FP80Ty()) - return &APFloat::x87DoubleExtended(); - else if (Ty->isFP128Ty()) - return &APFloat::IEEEquad(); - - assert(Ty->isPPC_FP128Ty() && "Unknown FP format"); - return &APFloat::PPCDoubleDouble(); -} - Constant *ConstantFP::get(Type *Ty, double V) { LLVMContext &Context = Ty->getContext(); APFloat FV(V); bool ignored; - FV.convert(*TypeToFloatSemantics(Ty->getScalarType()), + FV.convert(Ty->getScalarType()->getFltSemantics(), APFloat::rmNearestTiesToEven, &ignored); Constant *C = get(Context, FV); @@ -879,7 +942,7 @@ Constant *ConstantFP::get(Type *Ty, const APFloat &V) { Constant *ConstantFP::get(Type *Ty, StringRef Str) { LLVMContext &Context = Ty->getContext(); - APFloat FV(*TypeToFloatSemantics(Ty->getScalarType()), Str); + APFloat FV(Ty->getScalarType()->getFltSemantics(), Str); Constant *C = get(Context, FV); // For vectors, broadcast the value. @@ -890,7 +953,7 @@ Constant *ConstantFP::get(Type *Ty, StringRef Str) { } Constant *ConstantFP::getNaN(Type *Ty, bool Negative, uint64_t Payload) { - const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); + const fltSemantics &Semantics = Ty->getScalarType()->getFltSemantics(); APFloat NaN = APFloat::getNaN(Semantics, Negative, Payload); Constant *C = get(Ty->getContext(), NaN); @@ -901,7 +964,7 @@ Constant *ConstantFP::getNaN(Type *Ty, bool Negative, uint64_t Payload) { } Constant *ConstantFP::getQNaN(Type *Ty, bool Negative, APInt *Payload) { - const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); + const fltSemantics &Semantics = Ty->getScalarType()->getFltSemantics(); APFloat NaN = APFloat::getQNaN(Semantics, Negative, Payload); Constant *C = get(Ty->getContext(), NaN); @@ -912,7 +975,7 @@ Constant *ConstantFP::getQNaN(Type *Ty, bool Negative, APInt *Payload) { } Constant *ConstantFP::getSNaN(Type *Ty, bool Negative, APInt *Payload) { - const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); + const fltSemantics &Semantics = Ty->getScalarType()->getFltSemantics(); APFloat NaN = APFloat::getSNaN(Semantics, Negative, Payload); Constant *C = get(Ty->getContext(), NaN); @@ -923,7 +986,7 @@ Constant *ConstantFP::getSNaN(Type *Ty, bool Negative, APInt *Payload) { } Constant *ConstantFP::getNegativeZero(Type *Ty) { - const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); + const fltSemantics &Semantics = Ty->getScalarType()->getFltSemantics(); APFloat NegZero = APFloat::getZero(Semantics, /*Negative=*/true); Constant *C = get(Ty->getContext(), NegZero); @@ -949,24 +1012,7 @@ ConstantFP* ConstantFP::get(LLVMContext &Context, const APFloat& V) { std::unique_ptr<ConstantFP> &Slot = pImpl->FPConstants[V]; if (!Slot) { - Type *Ty; - if (&V.getSemantics() == &APFloat::IEEEhalf()) - Ty = Type::getHalfTy(Context); - else if (&V.getSemantics() == &APFloat::BFloat()) - Ty = Type::getBFloatTy(Context); - else if (&V.getSemantics() == &APFloat::IEEEsingle()) - Ty = Type::getFloatTy(Context); - else if (&V.getSemantics() == &APFloat::IEEEdouble()) - Ty = Type::getDoubleTy(Context); - else if (&V.getSemantics() == &APFloat::x87DoubleExtended()) - Ty = Type::getX86_FP80Ty(Context); - else if (&V.getSemantics() == &APFloat::IEEEquad()) - Ty = Type::getFP128Ty(Context); - else { - assert(&V.getSemantics() == &APFloat::PPCDoubleDouble() && - "Unknown FP format"); - Ty = Type::getPPC_FP128Ty(Context); - } + Type *Ty = Type::getFloatingPointTy(Context, V.getSemantics()); Slot.reset(new ConstantFP(Ty, V)); } @@ -974,7 +1020,7 @@ ConstantFP* ConstantFP::get(LLVMContext &Context, const APFloat& V) { } Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) { - const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); + const fltSemantics &Semantics = Ty->getScalarType()->getFltSemantics(); Constant *C = get(Ty->getContext(), APFloat::getInf(Semantics, Negative)); if (VectorType *VTy = dyn_cast<VectorType>(Ty)) @@ -985,7 +1031,7 @@ Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) { ConstantFP::ConstantFP(Type *Ty, const APFloat &V) : ConstantData(Ty, ConstantFPVal), Val(V) { - assert(&V.getSemantics() == TypeToFloatSemantics(Ty) && + assert(&V.getSemantics() == &Ty->getFltSemantics() && "FP type Mismatch"); } @@ -1029,7 +1075,7 @@ unsigned ConstantAggregateZero::getNumElements() const { if (auto *AT = dyn_cast<ArrayType>(Ty)) return AT->getNumElements(); if (auto *VT = dyn_cast<VectorType>(Ty)) - return VT->getNumElements(); + return cast<FixedVectorType>(VT)->getNumElements(); return Ty->getStructNumElements(); } @@ -1064,11 +1110,37 @@ unsigned UndefValue::getNumElements() const { if (auto *AT = dyn_cast<ArrayType>(Ty)) return AT->getNumElements(); if (auto *VT = dyn_cast<VectorType>(Ty)) - return VT->getNumElements(); + return cast<FixedVectorType>(VT)->getNumElements(); return Ty->getStructNumElements(); } //===----------------------------------------------------------------------===// +// PoisonValue Implementation +//===----------------------------------------------------------------------===// + +PoisonValue *PoisonValue::getSequentialElement() const { + if (ArrayType *ATy = dyn_cast<ArrayType>(getType())) + return PoisonValue::get(ATy->getElementType()); + return PoisonValue::get(cast<VectorType>(getType())->getElementType()); +} + +PoisonValue *PoisonValue::getStructElement(unsigned Elt) const { + return PoisonValue::get(getType()->getStructElementType(Elt)); +} + +PoisonValue *PoisonValue::getElementValue(Constant *C) const { + if (isa<ArrayType>(getType()) || isa<VectorType>(getType())) + return getSequentialElement(); + return getStructElement(cast<ConstantInt>(C)->getZExtValue()); +} + +PoisonValue *PoisonValue::getElementValue(unsigned Idx) const { + if (isa<ArrayType>(getType()) || isa<VectorType>(getType())) + return getSequentialElement(); + return getStructElement(Idx); +} + +//===----------------------------------------------------------------------===// // ConstantXXX Classes //===----------------------------------------------------------------------===// @@ -1246,7 +1318,7 @@ Constant *ConstantStruct::get(StructType *ST, ArrayRef<Constant*> V) { ConstantVector::ConstantVector(VectorType *T, ArrayRef<Constant *> V) : ConstantAggregate(T, ConstantVectorVal, V) { - assert(V.size() == T->getNumElements() && + assert(V.size() == cast<FixedVectorType>(T)->getNumElements() && "Invalid initializer for constant vector"); } @@ -1267,17 +1339,20 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) { Constant *C = V[0]; bool isZero = C->isNullValue(); bool isUndef = isa<UndefValue>(C); + bool isPoison = isa<PoisonValue>(C); if (isZero || isUndef) { for (unsigned i = 1, e = V.size(); i != e; ++i) if (V[i] != C) { - isZero = isUndef = false; + isZero = isUndef = isPoison = false; break; } } if (isZero) return ConstantAggregateZero::get(T); + if (isPoison) + return PoisonValue::get(T); if (isUndef) return UndefValue::get(T); @@ -1292,14 +1367,14 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) { } Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) { - if (!EC.Scalable) { + if (!EC.isScalable()) { // If this splat is compatible with ConstantDataVector, use it instead of // ConstantVector. if ((isa<ConstantFP>(V) || isa<ConstantInt>(V)) && ConstantDataSequential::isElementTypeCompatible(V->getType())) - return ConstantDataVector::getSplat(EC.Min, V); + return ConstantDataVector::getSplat(EC.getKnownMinValue(), V); - SmallVector<Constant *, 32> Elts(EC.Min, V); + SmallVector<Constant *, 32> Elts(EC.getKnownMinValue(), V); return get(Elts); } @@ -1316,7 +1391,7 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) { Constant *UndefV = UndefValue::get(VTy); V = ConstantExpr::getInsertElement(UndefV, V, ConstantInt::get(I32Ty, 0)); // Build shuffle mask to perform the splat. - SmallVector<int, 8> Zeros(EC.Min, 0); + SmallVector<int, 8> Zeros(EC.getKnownMinValue(), 0); // Splat. return ConstantExpr::getShuffleVector(V, UndefV, Zeros); } @@ -1441,6 +1516,8 @@ Constant *ConstantExpr::getWithOperands(ArrayRef<Constant *> Ops, Type *Ty, OnlyIfReducedTy); case Instruction::ExtractValue: return ConstantExpr::getExtractValue(Ops[0], getIndices(), OnlyIfReducedTy); + case Instruction::FNeg: + return ConstantExpr::getFNeg(Ops[0]); case Instruction::ShuffleVector: return ConstantExpr::getShuffleVector(Ops[0], Ops[1], getShuffleMask(), OnlyIfReducedTy); @@ -1601,7 +1678,7 @@ Constant *Constant::getSplatValue(bool AllowUndefs) const { ConstantInt *Index = dyn_cast<ConstantInt>(IElt->getOperand(2)); if (Index && Index->getValue() == 0 && - std::all_of(Mask.begin(), Mask.end(), [](int I) { return I == 0; })) + llvm::all_of(Mask, [](int I) { return I == 0; })) return SplatVal; } } @@ -1673,7 +1750,26 @@ UndefValue *UndefValue::get(Type *Ty) { /// Remove the constant from the constant table. void UndefValue::destroyConstantImpl() { // Free the constant and any dangling references to it. - getContext().pImpl->UVConstants.erase(getType()); + if (getValueID() == UndefValueVal) { + getContext().pImpl->UVConstants.erase(getType()); + } else if (getValueID() == PoisonValueVal) { + getContext().pImpl->PVConstants.erase(getType()); + } + llvm_unreachable("Not a undef or a poison!"); +} + +PoisonValue *PoisonValue::get(Type *Ty) { + std::unique_ptr<PoisonValue> &Entry = Ty->getContext().pImpl->PVConstants[Ty]; + if (!Entry) + Entry.reset(new PoisonValue(Ty)); + + return Entry.get(); +} + +/// Remove the constant from the constant table. +void PoisonValue::destroyConstantImpl() { + // Free the constant and any dangling references to it. + getContext().pImpl->PVConstants.erase(getType()); } BlockAddress *BlockAddress::get(BasicBlock *BB) { @@ -1754,6 +1850,58 @@ Value *BlockAddress::handleOperandChangeImpl(Value *From, Value *To) { return nullptr; } +DSOLocalEquivalent *DSOLocalEquivalent::get(GlobalValue *GV) { + DSOLocalEquivalent *&Equiv = GV->getContext().pImpl->DSOLocalEquivalents[GV]; + if (!Equiv) + Equiv = new DSOLocalEquivalent(GV); + + assert(Equiv->getGlobalValue() == GV && + "DSOLocalFunction does not match the expected global value"); + return Equiv; +} + +DSOLocalEquivalent::DSOLocalEquivalent(GlobalValue *GV) + : Constant(GV->getType(), Value::DSOLocalEquivalentVal, &Op<0>(), 1) { + setOperand(0, GV); +} + +/// Remove the constant from the constant table. +void DSOLocalEquivalent::destroyConstantImpl() { + const GlobalValue *GV = getGlobalValue(); + GV->getContext().pImpl->DSOLocalEquivalents.erase(GV); +} + +Value *DSOLocalEquivalent::handleOperandChangeImpl(Value *From, Value *To) { + assert(From == getGlobalValue() && "Changing value does not match operand."); + assert(isa<Constant>(To) && "Can only replace the operands with a constant"); + + // The replacement is with another global value. + if (const auto *ToObj = dyn_cast<GlobalValue>(To)) { + DSOLocalEquivalent *&NewEquiv = + getContext().pImpl->DSOLocalEquivalents[ToObj]; + if (NewEquiv) + return llvm::ConstantExpr::getBitCast(NewEquiv, getType()); + } + + // If the argument is replaced with a null value, just replace this constant + // with a null value. + if (cast<Constant>(To)->isNullValue()) + return To; + + // The replacement could be a bitcast or an alias to another function. We can + // replace it with a bitcast to the dso_local_equivalent of that function. + auto *Func = cast<Function>(To->stripPointerCastsAndAliases()); + DSOLocalEquivalent *&NewEquiv = getContext().pImpl->DSOLocalEquivalents[Func]; + if (NewEquiv) + return llvm::ConstantExpr::getBitCast(NewEquiv, getType()); + + // Replace this with the new one. + getContext().pImpl->DSOLocalEquivalents.erase(getGlobalValue()); + NewEquiv = this; + setOperand(0, Func); + return nullptr; +} + //---- ConstantExpr::get() implementations. // @@ -2002,8 +2150,8 @@ Constant *ConstantExpr::getPtrToInt(Constant *C, Type *DstTy, "PtrToInt destination must be integer or integer vector"); assert(isa<VectorType>(C->getType()) == isa<VectorType>(DstTy)); if (isa<VectorType>(C->getType())) - assert(cast<VectorType>(C->getType())->getNumElements() == - cast<VectorType>(DstTy)->getNumElements() && + assert(cast<FixedVectorType>(C->getType())->getNumElements() == + cast<FixedVectorType>(DstTy)->getNumElements() && "Invalid cast between a different number of vector elements"); return getFoldedCast(Instruction::PtrToInt, C, DstTy, OnlyIfReduced); } @@ -2016,8 +2164,8 @@ Constant *ConstantExpr::getIntToPtr(Constant *C, Type *DstTy, "IntToPtr destination must be a pointer or pointer vector"); assert(isa<VectorType>(C->getType()) == isa<VectorType>(DstTy)); if (isa<VectorType>(C->getType())) - assert(cast<VectorType>(C->getType())->getNumElements() == - cast<VectorType>(DstTy)->getNumElements() && + assert(cast<VectorType>(C->getType())->getElementCount() == + cast<VectorType>(DstTy)->getElementCount() && "Invalid cast between a different number of vector elements"); return getFoldedCast(Instruction::IntToPtr, C, DstTy, OnlyIfReduced); } @@ -2048,7 +2196,8 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy, Type *MidTy = PointerType::get(DstElemTy, SrcScalarTy->getAddressSpace()); if (VectorType *VT = dyn_cast<VectorType>(DstTy)) { // Handle vectors of pointers. - MidTy = FixedVectorType::get(MidTy, VT->getNumElements()); + MidTy = FixedVectorType::get(MidTy, + cast<FixedVectorType>(VT)->getNumElements()); } C = getBitCast(C, MidTy); } @@ -2245,7 +2394,7 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, unsigned AS = C->getType()->getPointerAddressSpace(); Type *ReqTy = DestTy->getPointerTo(AS); - ElementCount EltCount = {0, false}; + auto EltCount = ElementCount::getFixed(0); if (VectorType *VecTy = dyn_cast<VectorType>(C->getType())) EltCount = VecTy->getElementCount(); else @@ -2253,7 +2402,7 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, if (VectorType *VecTy = dyn_cast<VectorType>(Idx->getType())) EltCount = VecTy->getElementCount(); - if (EltCount.Min != 0) + if (EltCount.isNonZero()) ReqTy = VectorType::get(ReqTy, EltCount); if (OnlyIfReducedTy == ReqTy) @@ -2273,7 +2422,7 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C, if (GTI.isStruct() && Idx->getType()->isVectorTy()) { Idx = Idx->getSplatValue(); - } else if (GTI.isSequential() && EltCount.Min != 0 && + } else if (GTI.isSequential() && EltCount.isNonZero() && !Idx->getType()->isVectorTy()) { Idx = ConstantVector::getSplat(EltCount, Idx); } @@ -2549,6 +2698,11 @@ Constant *ConstantExpr::getXor(Constant *C1, Constant *C2) { return get(Instruction::Xor, C1, C2); } +Constant *ConstantExpr::getUMin(Constant *C1, Constant *C2) { + Constant *Cmp = ConstantExpr::getICmp(CmpInst::ICMP_ULT, C1, C2); + return getSelect(Cmp, C1, C2); +} + Constant *ConstantExpr::getShl(Constant *C1, Constant *C2, bool HasNUW, bool HasNSW) { unsigned Flags = (HasNUW ? OverflowingBinaryOperator::NoUnsignedWrap : 0) | @@ -2566,6 +2720,35 @@ Constant *ConstantExpr::getAShr(Constant *C1, Constant *C2, bool isExact) { isExact ? PossiblyExactOperator::IsExact : 0); } +Constant *ConstantExpr::getExactLogBase2(Constant *C) { + Type *Ty = C->getType(); + const APInt *IVal; + if (match(C, m_APInt(IVal)) && IVal->isPowerOf2()) + return ConstantInt::get(Ty, IVal->logBase2()); + + // FIXME: We can extract pow of 2 of splat constant for scalable vectors. + auto *VecTy = dyn_cast<FixedVectorType>(Ty); + if (!VecTy) + return nullptr; + + SmallVector<Constant *, 4> Elts; + for (unsigned I = 0, E = VecTy->getNumElements(); I != E; ++I) { + Constant *Elt = C->getAggregateElement(I); + if (!Elt) + return nullptr; + // Note that log2(iN undef) is *NOT* iN undef, because log2(iN undef) u< N. + if (isa<UndefValue>(Elt)) { + Elts.push_back(Constant::getNullValue(Ty->getScalarType())); + continue; + } + if (!match(Elt, m_APInt(IVal)) || !IVal->isPowerOf2()) + return nullptr; + Elts.push_back(ConstantInt::get(Ty->getScalarType(), IVal->logBase2())); + } + + return ConstantVector::get(Elts); +} + Constant *ConstantExpr::getBinOpIdentity(unsigned Opcode, Type *Ty, bool AllowRHSConstant) { assert(Instruction::isBinaryOp(Opcode) && "Only binops allowed"); @@ -2690,7 +2873,7 @@ bool ConstantDataSequential::isElementTypeCompatible(Type *Ty) { unsigned ConstantDataSequential::getNumElements() const { if (ArrayType *AT = dyn_cast<ArrayType>(getType())) return AT->getNumElements(); - return cast<VectorType>(getType())->getNumElements(); + return cast<FixedVectorType>(getType())->getNumElements(); } @@ -2739,56 +2922,58 @@ Constant *ConstantDataSequential::getImpl(StringRef Elements, Type *Ty) { // body but different types. For example, 0,0,0,1 could be a 4 element array // of i8, or a 1-element array of i32. They'll both end up in the same /// StringMap bucket, linked up by their Next pointers. Walk the list. - ConstantDataSequential **Entry = &Slot.second; - for (ConstantDataSequential *Node = *Entry; Node; - Entry = &Node->Next, Node = *Entry) - if (Node->getType() == Ty) - return Node; + std::unique_ptr<ConstantDataSequential> *Entry = &Slot.second; + for (; *Entry; Entry = &(*Entry)->Next) + if ((*Entry)->getType() == Ty) + return Entry->get(); // Okay, we didn't get a hit. Create a node of the right class, link it in, // and return it. - if (isa<ArrayType>(Ty)) - return *Entry = new ConstantDataArray(Ty, Slot.first().data()); + if (isa<ArrayType>(Ty)) { + // Use reset because std::make_unique can't access the constructor. + Entry->reset(new ConstantDataArray(Ty, Slot.first().data())); + return Entry->get(); + } assert(isa<VectorType>(Ty)); - return *Entry = new ConstantDataVector(Ty, Slot.first().data()); + // Use reset because std::make_unique can't access the constructor. + Entry->reset(new ConstantDataVector(Ty, Slot.first().data())); + return Entry->get(); } void ConstantDataSequential::destroyConstantImpl() { // Remove the constant from the StringMap. - StringMap<ConstantDataSequential*> &CDSConstants = - getType()->getContext().pImpl->CDSConstants; + StringMap<std::unique_ptr<ConstantDataSequential>> &CDSConstants = + getType()->getContext().pImpl->CDSConstants; - StringMap<ConstantDataSequential*>::iterator Slot = - CDSConstants.find(getRawDataValues()); + auto Slot = CDSConstants.find(getRawDataValues()); assert(Slot != CDSConstants.end() && "CDS not found in uniquing table"); - ConstantDataSequential **Entry = &Slot->getValue(); + std::unique_ptr<ConstantDataSequential> *Entry = &Slot->getValue(); // Remove the entry from the hash table. if (!(*Entry)->Next) { // If there is only one value in the bucket (common case) it must be this // entry, and removing the entry should remove the bucket completely. - assert((*Entry) == this && "Hash mismatch in ConstantDataSequential"); + assert(Entry->get() == this && "Hash mismatch in ConstantDataSequential"); getContext().pImpl->CDSConstants.erase(Slot); - } else { - // Otherwise, there are multiple entries linked off the bucket, unlink the - // node we care about but keep the bucket around. - for (ConstantDataSequential *Node = *Entry; ; - Entry = &Node->Next, Node = *Entry) { - assert(Node && "Didn't find entry in its uniquing hash table!"); - // If we found our entry, unlink it from the list and we're done. - if (Node == this) { - *Entry = Node->Next; - break; - } - } + return; } - // If we were part of a list, make sure that we don't delete the list that is - // still owned by the uniquing map. - Next = nullptr; + // Otherwise, there are multiple entries linked off the bucket, unlink the + // node we care about but keep the bucket around. + while (true) { + std::unique_ptr<ConstantDataSequential> &Node = *Entry; + assert(Node && "Didn't find entry in its uniquing hash table!"); + // If we found our entry, unlink it from the list and we're done. + if (Node.get() == this) { + Node = std::move(Node->Next); + return; + } + + Entry = &Node->Next; + } } /// getFP() constructors - Return a constant of array type with a float @@ -2938,7 +3123,7 @@ Constant *ConstantDataVector::getSplat(unsigned NumElts, Constant *V) { return getFP(V->getType(), Elts); } } - return ConstantVector::getSplat({NumElts, false}, V); + return ConstantVector::getSplat(ElementCount::getFixed(NumElts), V); } @@ -3248,7 +3433,7 @@ Value *ConstantExpr::handleOperandChangeImpl(Value *From, Value *ToV) { } Instruction *ConstantExpr::getAsInstruction() const { - SmallVector<Value *, 4> ValueOperands(op_begin(), op_end()); + SmallVector<Value *, 4> ValueOperands(operands()); ArrayRef<Value*> Ops(ValueOperands); switch (getOpcode()) { diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 6f3bbc80d4fd..90ba69069bae 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm-c/Core.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -146,6 +145,11 @@ LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID, return wrap(Attribute::getWithByValType(Ctx, NULL)); } + if (AttrKind == Attribute::AttrKind::StructRet) { + // Same as byval. + return wrap(Attribute::getWithStructRetType(Ctx, NULL)); + } + return wrap(Attribute::get(Ctx, AttrKind, Val)); } @@ -507,6 +511,8 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) { return LLVMVectorTypeKind; case Type::X86_MMXTyID: return LLVMX86_MMXTypeKind; + case Type::X86_AMXTyID: + return LLVMX86_AMXTypeKind; case Type::TokenTyID: return LLVMTokenTypeKind; case Type::ScalableVectorTyID: @@ -618,6 +624,9 @@ LLVMTypeRef LLVMPPCFP128TypeInContext(LLVMContextRef C) { LLVMTypeRef LLVMX86MMXTypeInContext(LLVMContextRef C) { return (LLVMTypeRef) Type::getX86_MMXTy(*unwrap(C)); } +LLVMTypeRef LLVMX86AMXTypeInContext(LLVMContextRef C) { + return (LLVMTypeRef) Type::getX86_AMXTy(*unwrap(C)); +} LLVMTypeRef LLVMHalfType(void) { return LLVMHalfTypeInContext(LLVMGetGlobalContext()); @@ -643,6 +652,9 @@ LLVMTypeRef LLVMPPCFP128Type(void) { LLVMTypeRef LLVMX86MMXType(void) { return LLVMX86MMXTypeInContext(LLVMGetGlobalContext()); } +LLVMTypeRef LLVMX86AMXType(void) { + return LLVMX86AMXTypeInContext(LLVMGetGlobalContext()); +} /*--.. Operations on function types ........................................--*/ @@ -734,7 +746,11 @@ LLVMBool LLVMIsLiteralStruct(LLVMTypeRef StructTy) { } LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name) { - return wrap(unwrap(M)->getTypeByName(Name)); + return wrap(StructType::getTypeByName(unwrap(M)->getContext(), Name)); +} + +LLVMTypeRef LLVMGetTypeByName2(LLVMContextRef C, const char *Name) { + return wrap(StructType::getTypeByName(*unwrap(C), Name)); } /*--.. Operations on array, pointer, and vector types (sequence types) .....--*/ @@ -759,6 +775,11 @@ LLVMTypeRef LLVMVectorType(LLVMTypeRef ElementType, unsigned ElementCount) { return wrap(FixedVectorType::get(unwrap(ElementType), ElementCount)); } +LLVMTypeRef LLVMScalableVectorType(LLVMTypeRef ElementType, + unsigned ElementCount) { + return wrap(ScalableVectorType::get(unwrap(ElementType), ElementCount)); +} + LLVMTypeRef LLVMGetElementType(LLVMTypeRef WrappedTy) { auto *Ty = unwrap<Type>(WrappedTy); if (auto *PTy = dyn_cast<PointerType>(Ty)) @@ -781,7 +802,7 @@ unsigned LLVMGetPointerAddressSpace(LLVMTypeRef PointerTy) { } unsigned LLVMGetVectorSize(LLVMTypeRef VectorTy) { - return unwrap<VectorType>(VectorTy)->getNumElements(); + return unwrap<VectorType>(VectorTy)->getElementCount().getKnownMinValue(); } /*--.. Operations on other types ...........................................--*/ @@ -816,6 +837,7 @@ LLVMTypeRef LLVMTypeOf(LLVMValueRef Val) { LLVMValueKind LLVMGetValueKind(LLVMValueRef Val) { switch(unwrap(Val)->getValueID()) { +#define LLVM_C_API 1 #define HANDLE_VALUE(Name) \ case Value::Name##Val: \ return LLVM##Name##ValueKind; @@ -925,6 +947,7 @@ LLVMValueMetadataEntry * LLVMInstructionGetAllMetadataOtherThanDebugLoc(LLVMValueRef Value, size_t *NumEntries) { return llvm_getMetadata(NumEntries, [&Value](MetadataEntries &Entries) { + Entries.clear(); unwrap<Instruction>(Value)->getAllMetadata(Entries); }); } @@ -1034,6 +1057,10 @@ LLVMValueRef LLVMGetUndef(LLVMTypeRef Ty) { return wrap(UndefValue::get(unwrap(Ty))); } +LLVMValueRef LLVMGetPoison(LLVMTypeRef Ty) { + return wrap(PoisonValue::get(unwrap(Ty))); +} + LLVMBool LLVMIsConstant(LLVMValueRef Ty) { return isa<Constant>(unwrap(Ty)); } @@ -1048,6 +1075,10 @@ LLVMBool LLVMIsUndef(LLVMValueRef Val) { return isa<UndefValue>(unwrap(Val)); } +LLVMBool LLVMIsPoison(LLVMValueRef Val) { + return isa<PoisonValue>(unwrap(Val)); +} + LLVMValueRef LLVMConstPointerNull(LLVMTypeRef Ty) { return wrap(ConstantPointerNull::get(unwrap<PointerType>(Ty))); } @@ -2034,6 +2065,7 @@ void LLVMSetAlignment(LLVMValueRef V, unsigned Bytes) { LLVMValueMetadataEntry *LLVMGlobalCopyAllMetadata(LLVMValueRef Value, size_t *NumEntries) { return llvm_getMetadata(NumEntries, [&Value](MetadataEntries &Entries) { + Entries.clear(); if (Instruction *Instr = dyn_cast<Instruction>(unwrap(Value))) { Instr->getAllMetadata(Entries); } else { @@ -3952,6 +3984,19 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, singleThread ? SyncScope::SingleThread : SyncScope::System)); } +unsigned LLVMGetNumMaskElements(LLVMValueRef SVInst) { + Value *P = unwrap<Value>(SVInst); + ShuffleVectorInst *I = cast<ShuffleVectorInst>(P); + return I->getShuffleMask().size(); +} + +int LLVMGetMaskValue(LLVMValueRef SVInst, unsigned Elt) { + Value *P = unwrap<Value>(SVInst); + ShuffleVectorInst *I = cast<ShuffleVectorInst>(P); + return I->getMaskValue(Elt); +} + +int LLVMGetUndefMaskElem(void) { return UndefMaskElem; } LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst) { Value *P = unwrap<Value>(AtomicInst); diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 45cbbb3a6037..5104dc349d0b 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -267,6 +267,12 @@ DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits, 0, Encoding, Flags); } +DIStringType *DIBuilder::createStringType(StringRef Name, uint64_t SizeInBits) { + assert(!Name.empty() && "Unable to create type without name"); + return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name, + SizeInBits, 0); +} + DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) { return DIDerivedType::get(VMContext, Tag, "", nullptr, 0, nullptr, FromTy, 0, 0, 0, None, DINode::FlagZero); @@ -519,12 +525,24 @@ DICompositeType *DIBuilder::createEnumerationType( return CTy; } -DICompositeType *DIBuilder::createArrayType(uint64_t Size, - uint32_t AlignInBits, DIType *Ty, - DINodeArray Subscripts) { - auto *R = DICompositeType::get(VMContext, dwarf::DW_TAG_array_type, "", - nullptr, 0, nullptr, Ty, Size, AlignInBits, 0, - DINode::FlagZero, Subscripts, 0, nullptr); +DICompositeType *DIBuilder::createArrayType( + uint64_t Size, uint32_t AlignInBits, DIType *Ty, DINodeArray Subscripts, + PointerUnion<DIExpression *, DIVariable *> DL, + PointerUnion<DIExpression *, DIVariable *> AS, + PointerUnion<DIExpression *, DIVariable *> AL, + PointerUnion<DIExpression *, DIVariable *> RK) { + auto *R = DICompositeType::get( + VMContext, dwarf::DW_TAG_array_type, "", nullptr, 0, + nullptr, Ty, Size, AlignInBits, 0, DINode::FlagZero, + Subscripts, 0, nullptr, nullptr, "", nullptr, + DL.is<DIExpression *>() ? (Metadata *)DL.get<DIExpression *>() + : (Metadata *)DL.get<DIVariable *>(), + AS.is<DIExpression *>() ? (Metadata *)AS.get<DIExpression *>() + : (Metadata *)AS.get<DIVariable *>(), + AL.is<DIExpression *>() ? (Metadata *)AL.get<DIExpression *>() + : (Metadata *)AL.get<DIVariable *>(), + RK.is<DIExpression *>() ? (Metadata *)RK.get<DIExpression *>() + : (Metadata *)RK.get<DIVariable *>()); trackIfUnresolved(R); return R; } @@ -643,6 +661,18 @@ DISubrange *DIBuilder::getOrCreateSubrange(Metadata *CountNode, Metadata *LB, return DISubrange::get(VMContext, CountNode, LB, UB, Stride); } +DIGenericSubrange *DIBuilder::getOrCreateGenericSubrange( + DIGenericSubrange::BoundType CountNode, DIGenericSubrange::BoundType LB, + DIGenericSubrange::BoundType UB, DIGenericSubrange::BoundType Stride) { + auto ConvToMetadata = [&](DIGenericSubrange::BoundType Bound) -> Metadata * { + return Bound.is<DIExpression *>() ? (Metadata *)Bound.get<DIExpression *>() + : (Metadata *)Bound.get<DIVariable *>(); + }; + return DIGenericSubrange::get(VMContext, ConvToMetadata(CountNode), + ConvToMetadata(LB), ConvToMetadata(UB), + ConvToMetadata(Stride)); +} + static void checkGlobalVariableScope(DIScope *Context) { #ifndef NDEBUG if (auto *CT = @@ -844,9 +874,10 @@ DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, StringRef IncludePath, StringRef APINotesFile, - DIFile *File, unsigned LineNo) { + DIFile *File, unsigned LineNo, bool IsDecl) { return DIModule::get(VMContext, File, getNonCompileUnitScope(Scope), Name, - ConfigurationMacros, IncludePath, APINotesFile, LineNo); + ConfigurationMacros, IncludePath, APINotesFile, LineNo, + IsDecl); } DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index c44737c5bfc2..274ea0aa5fd1 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TypeSize.h" @@ -64,7 +65,8 @@ StructLayout::StructLayout(StructType *ST, const DataLayout &DL) { StructAlignment = std::max(TyAlign, StructAlignment); MemberOffsets[i] = StructSize; - StructSize += DL.getTypeAllocSize(Ty); // Consume space for this data item + // Consume space for this data item + StructSize += DL.getTypeAllocSize(Ty).getFixedValue(); } // Add padding to the end of the struct so that it could be put in an array @@ -181,6 +183,7 @@ void DataLayout::reset(StringRef Desc) { AllocaAddrSpace = 0; StackNaturalAlign.reset(); ProgramAddrSpace = 0; + DefaultGlobalsAddrSpace = 0; FunctionPtrAlign.reset(); TheFunctionPtrAlignType = FunctionPtrAlignType::Independent; ManglingMode = MM_None; @@ -188,57 +191,80 @@ void DataLayout::reset(StringRef Desc) { // Default alignments for (const LayoutAlignElem &E : DefaultAlignments) { - setAlignment((AlignTypeEnum)E.AlignType, E.ABIAlign, E.PrefAlign, - E.TypeBitWidth); + if (Error Err = setAlignment((AlignTypeEnum)E.AlignType, E.ABIAlign, + E.PrefAlign, E.TypeBitWidth)) + return report_fatal_error(std::move(Err)); } - setPointerAlignment(0, Align(8), Align(8), 8, 8); + if (Error Err = setPointerAlignment(0, Align(8), Align(8), 8, 8)) + return report_fatal_error(std::move(Err)); - parseSpecifier(Desc); + if (Error Err = parseSpecifier(Desc)) + return report_fatal_error(std::move(Err)); +} + +Expected<DataLayout> DataLayout::parse(StringRef LayoutDescription) { + DataLayout Layout(""); + if (Error Err = Layout.parseSpecifier(LayoutDescription)) + return std::move(Err); + return Layout; +} + +static Error reportError(const Twine &Message) { + return createStringError(inconvertibleErrorCode(), Message); } /// Checked version of split, to ensure mandatory subparts. -static std::pair<StringRef, StringRef> split(StringRef Str, char Separator) { +static Error split(StringRef Str, char Separator, + std::pair<StringRef, StringRef> &Split) { assert(!Str.empty() && "parse error, string can't be empty here"); - std::pair<StringRef, StringRef> Split = Str.split(Separator); + Split = Str.split(Separator); if (Split.second.empty() && Split.first != Str) - report_fatal_error("Trailing separator in datalayout string"); + return reportError("Trailing separator in datalayout string"); if (!Split.second.empty() && Split.first.empty()) - report_fatal_error("Expected token before separator in datalayout string"); - return Split; + return reportError("Expected token before separator in datalayout string"); + return Error::success(); } /// Get an unsigned integer, including error checks. -static unsigned getInt(StringRef R) { - unsigned Result; +template <typename IntTy> static Error getInt(StringRef R, IntTy &Result) { bool error = R.getAsInteger(10, Result); (void)error; if (error) - report_fatal_error("not a number, or does not fit in an unsigned int"); - return Result; + return reportError("not a number, or does not fit in an unsigned int"); + return Error::success(); } -/// Convert bits into bytes. Assert if not a byte width multiple. -static unsigned inBytes(unsigned Bits) { - if (Bits % 8) - report_fatal_error("number of bits must be a byte width multiple"); - return Bits / 8; +/// Get an unsigned integer representing the number of bits and convert it into +/// bytes. Error out of not a byte width multiple. +template <typename IntTy> +static Error getIntInBytes(StringRef R, IntTy &Result) { + if (Error Err = getInt<IntTy>(R, Result)) + return Err; + if (Result % 8) + return reportError("number of bits must be a byte width multiple"); + Result /= 8; + return Error::success(); } -static unsigned getAddrSpace(StringRef R) { - unsigned AddrSpace = getInt(R); +static Error getAddrSpace(StringRef R, unsigned &AddrSpace) { + if (Error Err = getInt(R, AddrSpace)) + return Err; if (!isUInt<24>(AddrSpace)) - report_fatal_error("Invalid address space, must be a 24-bit integer"); - return AddrSpace; + return reportError("Invalid address space, must be a 24-bit integer"); + return Error::success(); } -void DataLayout::parseSpecifier(StringRef Desc) { +Error DataLayout::parseSpecifier(StringRef Desc) { StringRepresentation = std::string(Desc); while (!Desc.empty()) { // Split at '-'. - std::pair<StringRef, StringRef> Split = split(Desc, '-'); + std::pair<StringRef, StringRef> Split; + if (Error Err = split(Desc, '-', Split)) + return Err; Desc = Split.second; // Split at ':'. - Split = split(Split.first, ':'); + if (Error Err = split(Split.first, ':', Split)) + return Err; // Aliases used below. StringRef &Tok = Split.first; // Current token. @@ -246,11 +272,14 @@ void DataLayout::parseSpecifier(StringRef Desc) { if (Tok == "ni") { do { - Split = split(Rest, ':'); + if (Error Err = split(Rest, ':', Split)) + return Err; Rest = Split.second; - unsigned AS = getInt(Split.first); + unsigned AS; + if (Error Err = getInt(Split.first, AS)) + return Err; if (AS == 0) - report_fatal_error("Address space 0 can never be non-integral"); + return reportError("Address space 0 can never be non-integral"); NonIntegralAddressSpaces.push_back(AS); } while (!Rest.empty()); @@ -273,28 +302,36 @@ void DataLayout::parseSpecifier(StringRef Desc) { break; case 'p': { // Address space. - unsigned AddrSpace = Tok.empty() ? 0 : getInt(Tok); + unsigned AddrSpace = 0; + if (!Tok.empty()) + if (Error Err = getInt(Tok, AddrSpace)) + return Err; if (!isUInt<24>(AddrSpace)) - report_fatal_error("Invalid address space, must be a 24bit integer"); + return reportError("Invalid address space, must be a 24bit integer"); // Size. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing size specification for pointer in datalayout string"); - Split = split(Rest, ':'); - unsigned PointerMemSize = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + unsigned PointerMemSize; + if (Error Err = getIntInBytes(Tok, PointerMemSize)) + return Err; if (!PointerMemSize) - report_fatal_error("Invalid pointer size of 0 bytes"); + return reportError("Invalid pointer size of 0 bytes"); // ABI alignment. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing alignment specification for pointer in datalayout string"); - Split = split(Rest, ':'); - unsigned PointerABIAlign = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + unsigned PointerABIAlign; + if (Error Err = getIntInBytes(Tok, PointerABIAlign)) + return Err; if (!isPowerOf2_64(PointerABIAlign)) - report_fatal_error( - "Pointer ABI alignment must be a power of 2"); + return reportError("Pointer ABI alignment must be a power of 2"); // Size of index used in GEP for address calculation. // The parameter is optional. By default it is equal to size of pointer. @@ -303,23 +340,28 @@ void DataLayout::parseSpecifier(StringRef Desc) { // Preferred alignment. unsigned PointerPrefAlign = PointerABIAlign; if (!Rest.empty()) { - Split = split(Rest, ':'); - PointerPrefAlign = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + if (Error Err = getIntInBytes(Tok, PointerPrefAlign)) + return Err; if (!isPowerOf2_64(PointerPrefAlign)) - report_fatal_error( - "Pointer preferred alignment must be a power of 2"); + return reportError( + "Pointer preferred alignment must be a power of 2"); // Now read the index. It is the second optional parameter here. if (!Rest.empty()) { - Split = split(Rest, ':'); - IndexSize = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + if (Error Err = getIntInBytes(Tok, IndexSize)) + return Err; if (!IndexSize) - report_fatal_error("Invalid index size of 0 bytes"); + return reportError("Invalid index size of 0 bytes"); } } - setPointerAlignment(AddrSpace, assumeAligned(PointerABIAlign), - assumeAligned(PointerPrefAlign), PointerMemSize, - IndexSize); + if (Error Err = setPointerAlignment( + AddrSpace, assumeAligned(PointerABIAlign), + assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize)) + return Err; break; } case 'i': @@ -336,61 +378,75 @@ void DataLayout::parseSpecifier(StringRef Desc) { } // Bit size. - unsigned Size = Tok.empty() ? 0 : getInt(Tok); + unsigned Size = 0; + if (!Tok.empty()) + if (Error Err = getInt(Tok, Size)) + return Err; if (AlignType == AGGREGATE_ALIGN && Size != 0) - report_fatal_error( + return reportError( "Sized aggregate specification in datalayout string"); // ABI alignment. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing alignment specification in datalayout string"); - Split = split(Rest, ':'); - const unsigned ABIAlign = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + unsigned ABIAlign; + if (Error Err = getIntInBytes(Tok, ABIAlign)) + return Err; if (AlignType != AGGREGATE_ALIGN && !ABIAlign) - report_fatal_error( + return reportError( "ABI alignment specification must be >0 for non-aggregate types"); if (!isUInt<16>(ABIAlign)) - report_fatal_error("Invalid ABI alignment, must be a 16bit integer"); + return reportError("Invalid ABI alignment, must be a 16bit integer"); if (ABIAlign != 0 && !isPowerOf2_64(ABIAlign)) - report_fatal_error("Invalid ABI alignment, must be a power of 2"); + return reportError("Invalid ABI alignment, must be a power of 2"); // Preferred alignment. unsigned PrefAlign = ABIAlign; if (!Rest.empty()) { - Split = split(Rest, ':'); - PrefAlign = inBytes(getInt(Tok)); + if (Error Err = split(Rest, ':', Split)) + return Err; + if (Error Err = getIntInBytes(Tok, PrefAlign)) + return Err; } if (!isUInt<16>(PrefAlign)) - report_fatal_error( + return reportError( "Invalid preferred alignment, must be a 16bit integer"); if (PrefAlign != 0 && !isPowerOf2_64(PrefAlign)) - report_fatal_error("Invalid preferred alignment, must be a power of 2"); + return reportError("Invalid preferred alignment, must be a power of 2"); - setAlignment(AlignType, assumeAligned(ABIAlign), assumeAligned(PrefAlign), - Size); + if (Error Err = setAlignment(AlignType, assumeAligned(ABIAlign), + assumeAligned(PrefAlign), Size)) + return Err; break; } case 'n': // Native integer types. while (true) { - unsigned Width = getInt(Tok); + unsigned Width; + if (Error Err = getInt(Tok, Width)) + return Err; if (Width == 0) - report_fatal_error( + return reportError( "Zero width native integer type in datalayout string"); LegalIntWidths.push_back(Width); if (Rest.empty()) break; - Split = split(Rest, ':'); + if (Error Err = split(Rest, ':', Split)) + return Err; } break; case 'S': { // Stack natural alignment. - uint64_t Alignment = inBytes(getInt(Tok)); + uint64_t Alignment; + if (Error Err = getIntInBytes(Tok, Alignment)) + return Err; if (Alignment != 0 && !llvm::isPowerOf2_64(Alignment)) - report_fatal_error("Alignment is neither 0 nor a power of 2"); + return reportError("Alignment is neither 0 nor a power of 2"); StackNaturalAlign = MaybeAlign(Alignment); break; } @@ -403,34 +459,44 @@ void DataLayout::parseSpecifier(StringRef Desc) { TheFunctionPtrAlignType = FunctionPtrAlignType::MultipleOfFunctionAlign; break; default: - report_fatal_error("Unknown function pointer alignment type in " + return reportError("Unknown function pointer alignment type in " "datalayout string"); } Tok = Tok.substr(1); - uint64_t Alignment = inBytes(getInt(Tok)); + uint64_t Alignment; + if (Error Err = getIntInBytes(Tok, Alignment)) + return Err; if (Alignment != 0 && !llvm::isPowerOf2_64(Alignment)) - report_fatal_error("Alignment is neither 0 nor a power of 2"); + return reportError("Alignment is neither 0 nor a power of 2"); FunctionPtrAlign = MaybeAlign(Alignment); break; } case 'P': { // Function address space. - ProgramAddrSpace = getAddrSpace(Tok); + if (Error Err = getAddrSpace(Tok, ProgramAddrSpace)) + return Err; break; } case 'A': { // Default stack/alloca address space. - AllocaAddrSpace = getAddrSpace(Tok); + if (Error Err = getAddrSpace(Tok, AllocaAddrSpace)) + return Err; + break; + } + case 'G': { // Default address space for global variables. + if (Error Err = getAddrSpace(Tok, DefaultGlobalsAddrSpace)) + return Err; break; } case 'm': if (!Tok.empty()) - report_fatal_error("Unexpected trailing characters after mangling specifier in datalayout string"); + return reportError("Unexpected trailing characters after mangling " + "specifier in datalayout string"); if (Rest.empty()) - report_fatal_error("Expected mangling specifier in datalayout string"); + return reportError("Expected mangling specifier in datalayout string"); if (Rest.size() > 1) - report_fatal_error("Unknown mangling specifier in datalayout string"); + return reportError("Unknown mangling specifier in datalayout string"); switch(Rest[0]) { default: - report_fatal_error("Unknown mangling in datalayout string"); + return reportError("Unknown mangling in datalayout string"); case 'e': ManglingMode = MM_ELF; break; @@ -452,10 +518,12 @@ void DataLayout::parseSpecifier(StringRef Desc) { } break; default: - report_fatal_error("Unknown specifier in datalayout string"); + return reportError("Unknown specifier in datalayout string"); break; } } + + return Error::success(); } DataLayout::DataLayout(const Module *M) { @@ -469,6 +537,7 @@ bool DataLayout::operator==(const DataLayout &Other) const { AllocaAddrSpace == Other.AllocaAddrSpace && StackNaturalAlign == Other.StackNaturalAlign && ProgramAddrSpace == Other.ProgramAddrSpace && + DefaultGlobalsAddrSpace == Other.DefaultGlobalsAddrSpace && FunctionPtrAlign == Other.FunctionPtrAlign && TheFunctionPtrAlignType == Other.TheFunctionPtrAlignType && ManglingMode == Other.ManglingMode && @@ -487,17 +556,17 @@ DataLayout::findAlignmentLowerBound(AlignTypeEnum AlignType, }); } -void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align, - Align pref_align, uint32_t bit_width) { +Error DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align, + Align pref_align, uint32_t bit_width) { // AlignmentsTy::ABIAlign and AlignmentsTy::PrefAlign were once stored as // uint16_t, it is unclear if there are requirements for alignment to be less // than 2^16 other than storage. In the meantime we leave the restriction as // an assert. See D67400 for context. assert(Log2(abi_align) < 16 && Log2(pref_align) < 16 && "Alignment too big"); if (!isUInt<24>(bit_width)) - report_fatal_error("Invalid bit width, must be a 24bit integer"); + return reportError("Invalid bit width, must be a 24bit integer"); if (pref_align < abi_align) - report_fatal_error( + return reportError( "Preferred alignment cannot be less than the ABI alignment"); AlignmentsTy::iterator I = findAlignmentLowerBound(align_type, bit_width); @@ -511,24 +580,35 @@ void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align, Alignments.insert(I, LayoutAlignElem::get(align_type, abi_align, pref_align, bit_width)); } -} + return Error::success(); +} + +const PointerAlignElem & +DataLayout::getPointerAlignElem(uint32_t AddressSpace) const { + if (AddressSpace != 0) { + auto I = lower_bound(Pointers, AddressSpace, + [](const PointerAlignElem &A, uint32_t AddressSpace) { + return A.AddressSpace < AddressSpace; + }); + if (I != Pointers.end() && I->AddressSpace == AddressSpace) + return *I; + } -DataLayout::PointersTy::iterator -DataLayout::findPointerLowerBound(uint32_t AddressSpace) { - return std::lower_bound(Pointers.begin(), Pointers.end(), AddressSpace, - [](const PointerAlignElem &A, uint32_t AddressSpace) { - return A.AddressSpace < AddressSpace; - }); + assert(Pointers[0].AddressSpace == 0); + return Pointers[0]; } -void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, - Align PrefAlign, uint32_t TypeByteWidth, - uint32_t IndexWidth) { +Error DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, + Align PrefAlign, uint32_t TypeByteWidth, + uint32_t IndexWidth) { if (PrefAlign < ABIAlign) - report_fatal_error( + return reportError( "Preferred alignment cannot be less than the ABI alignment"); - PointersTy::iterator I = findPointerLowerBound(AddrSpace); + auto I = lower_bound(Pointers, AddrSpace, + [](const PointerAlignElem &A, uint32_t AddressSpace) { + return A.AddressSpace < AddressSpace; + }); if (I == Pointers.end() || I->AddressSpace != AddrSpace) { Pointers.insert(I, PointerAlignElem::get(AddrSpace, ABIAlign, PrefAlign, TypeByteWidth, IndexWidth)); @@ -538,49 +618,19 @@ void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, I->TypeByteWidth = TypeByteWidth; I->IndexWidth = IndexWidth; } + return Error::success(); } -/// getAlignmentInfo - Return the alignment (either ABI if ABIInfo = true or -/// preferred if ABIInfo = false) the layout wants for the specified datatype. -Align DataLayout::getAlignmentInfo(AlignTypeEnum AlignType, uint32_t BitWidth, - bool ABIInfo, Type *Ty) const { - AlignmentsTy::const_iterator I = findAlignmentLowerBound(AlignType, BitWidth); - // See if we found an exact match. Of if we are looking for an integer type, - // but don't have an exact match take the next largest integer. This is where - // the lower_bound will point to when it fails an exact match. - if (I != Alignments.end() && I->AlignType == (unsigned)AlignType && - (I->TypeBitWidth == BitWidth || AlignType == INTEGER_ALIGN)) - return ABIInfo ? I->ABIAlign : I->PrefAlign; - - if (AlignType == INTEGER_ALIGN) { - // If we didn't have a larger value try the largest value we have. - if (I != Alignments.begin()) { - --I; // Go to the previous entry and see if its an integer. - if (I->AlignType == INTEGER_ALIGN) - return ABIInfo ? I->ABIAlign : I->PrefAlign; - } - } else if (AlignType == VECTOR_ALIGN) { - // By default, use natural alignment for vector types. This is consistent - // with what clang and llvm-gcc do. - unsigned Alignment = - getTypeAllocSize(cast<VectorType>(Ty)->getElementType()); - // We're only calculating a natural alignment, so it doesn't have to be - // based on the full size for scalable vectors. Using the minimum element - // count should be enough here. - Alignment *= cast<VectorType>(Ty)->getElementCount().Min; - Alignment = PowerOf2Ceil(Alignment); - return Align(Alignment); - } - - // If we still couldn't find a reasonable default alignment, fall back - // to a simple heuristic that the alignment is the first power of two - // greater-or-equal to the store size of the type. This is a reasonable - // approximation of reality, and if the user wanted something less - // less conservative, they should have specified it explicitly in the data - // layout. - unsigned Alignment = getTypeStoreSize(Ty); - Alignment = PowerOf2Ceil(Alignment); - return Align(Alignment); +Align DataLayout::getIntegerAlignment(uint32_t BitWidth, + bool abi_or_pref) const { + auto I = findAlignmentLowerBound(INTEGER_ALIGN, BitWidth); + // If we don't have an exact match, use alignment of next larger integer + // type. If there is none, use alignment of largest integer type by going + // back one element. + if (I == Alignments.end() || I->AlignType != INTEGER_ALIGN) + --I; + assert(I->AlignType == INTEGER_ALIGN && "Must be integer alignment"); + return abi_or_pref ? I->ABIAlign : I->PrefAlign; } namespace { @@ -642,30 +692,15 @@ const StructLayout *DataLayout::getStructLayout(StructType *Ty) const { } Align DataLayout::getPointerABIAlignment(unsigned AS) const { - PointersTy::const_iterator I = findPointerLowerBound(AS); - if (I == Pointers.end() || I->AddressSpace != AS) { - I = findPointerLowerBound(0); - assert(I->AddressSpace == 0); - } - return I->ABIAlign; + return getPointerAlignElem(AS).ABIAlign; } Align DataLayout::getPointerPrefAlignment(unsigned AS) const { - PointersTy::const_iterator I = findPointerLowerBound(AS); - if (I == Pointers.end() || I->AddressSpace != AS) { - I = findPointerLowerBound(0); - assert(I->AddressSpace == 0); - } - return I->PrefAlign; + return getPointerAlignElem(AS).PrefAlign; } unsigned DataLayout::getPointerSize(unsigned AS) const { - PointersTy::const_iterator I = findPointerLowerBound(AS); - if (I == Pointers.end() || I->AddressSpace != AS) { - I = findPointerLowerBound(0); - assert(I->AddressSpace == 0); - } - return I->TypeByteWidth; + return getPointerAlignElem(AS).TypeByteWidth; } unsigned DataLayout::getMaxPointerSize() const { @@ -684,12 +719,7 @@ unsigned DataLayout::getPointerTypeSizeInBits(Type *Ty) const { } unsigned DataLayout::getIndexSize(unsigned AS) const { - PointersTy::const_iterator I = findPointerLowerBound(AS); - if (I == Pointers.end() || I->AddressSpace != AS) { - I = findPointerLowerBound(0); - assert(I->AddressSpace == 0); - } - return I->IndexWidth; + return getPointerAlignElem(AS).IndexWidth; } unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const { @@ -708,8 +738,6 @@ unsigned DataLayout::getIndexTypeSizeInBits(Type *Ty) const { == false) for the requested type \a Ty. */ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const { - AlignTypeEnum AlignType; - assert(Ty->isSized() && "Cannot getTypeInfo() on a type that is unsized!"); switch (Ty->getTypeID()) { // Early escape for the non-numeric types. @@ -730,12 +758,15 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const { // Get the layout annotation... which is lazily created on demand. const StructLayout *Layout = getStructLayout(cast<StructType>(Ty)); - const Align Align = getAlignmentInfo(AGGREGATE_ALIGN, 0, abi_or_pref, Ty); + const LayoutAlignElem &AggregateAlign = Alignments[0]; + assert(AggregateAlign.AlignType == AGGREGATE_ALIGN && + "Aggregate alignment must be first alignment entry"); + const Align Align = + abi_or_pref ? AggregateAlign.ABIAlign : AggregateAlign.PrefAlign; return std::max(Align, Layout->getAlignment()); } case Type::IntegerTyID: - AlignType = INTEGER_ALIGN; - break; + return getIntegerAlignment(Ty->getIntegerBitWidth(), abi_or_pref); case Type::HalfTyID: case Type::BFloatTyID: case Type::FloatTyID: @@ -744,22 +775,47 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const { // same size and alignment, so they look the same here. case Type::PPC_FP128TyID: case Type::FP128TyID: - case Type::X86_FP80TyID: - AlignType = FLOAT_ALIGN; - break; + case Type::X86_FP80TyID: { + unsigned BitWidth = getTypeSizeInBits(Ty).getFixedSize(); + auto I = findAlignmentLowerBound(FLOAT_ALIGN, BitWidth); + if (I != Alignments.end() && I->AlignType == FLOAT_ALIGN && + I->TypeBitWidth == BitWidth) + return abi_or_pref ? I->ABIAlign : I->PrefAlign; + + // If we still couldn't find a reasonable default alignment, fall back + // to a simple heuristic that the alignment is the first power of two + // greater-or-equal to the store size of the type. This is a reasonable + // approximation of reality, and if the user wanted something less + // less conservative, they should have specified it explicitly in the data + // layout. + return Align(PowerOf2Ceil(BitWidth / 8)); + } case Type::X86_MMXTyID: case Type::FixedVectorTyID: - case Type::ScalableVectorTyID: - AlignType = VECTOR_ALIGN; - break; + case Type::ScalableVectorTyID: { + unsigned BitWidth = getTypeSizeInBits(Ty).getKnownMinSize(); + auto I = findAlignmentLowerBound(VECTOR_ALIGN, BitWidth); + if (I != Alignments.end() && I->AlignType == VECTOR_ALIGN && + I->TypeBitWidth == BitWidth) + return abi_or_pref ? I->ABIAlign : I->PrefAlign; + + // By default, use natural alignment for vector types. This is consistent + // with what clang and llvm-gcc do. + // TODO: This should probably not be using the alloc size. + unsigned Alignment = + getTypeAllocSize(cast<VectorType>(Ty)->getElementType()); + // We're only calculating a natural alignment, so it doesn't have to be + // based on the full size for scalable vectors. Using the minimum element + // count should be enough here. + Alignment *= cast<VectorType>(Ty)->getElementCount().getKnownMinValue(); + Alignment = PowerOf2Ceil(Alignment); + return Align(Alignment); + } + case Type::X86_AMXTyID: + return Align(64); default: llvm_unreachable("Bad type for getAlignment!!!"); } - - // If we're dealing with a scalable vector, we just need the known minimum - // size for determining alignment. If not, we'll get the exact size. - return getAlignmentInfo(AlignType, getTypeSizeInBits(Ty).getKnownMinSize(), - abi_or_pref, Ty); } /// TODO: Remove this function once the transition to Align is over. @@ -771,12 +827,6 @@ Align DataLayout::getABITypeAlign(Type *Ty) const { return getAlignment(Ty, true); } -/// getABIIntegerTypeAlignment - Return the minimum ABI-required alignment for -/// an integer type of the specified bitwidth. -Align DataLayout::getABIIntegerTypeAlignment(unsigned BitWidth) const { - return getAlignmentInfo(INTEGER_ALIGN, BitWidth, true, nullptr); -} - /// TODO: Remove this function once the transition to Align is over. unsigned DataLayout::getPrefTypeAlignment(Type *Ty) const { return getPrefTypeAlign(Ty).value(); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 190b220dc9aa..d7656b9dd1f8 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -652,7 +652,8 @@ bool llvm::stripNonLineTableDebugInfo(Module &M) { MDNode *InlinedAt = DL.getInlinedAt(); Scope = remap(Scope); InlinedAt = remap(InlinedAt); - return DebugLoc::get(DL.getLine(), DL.getCol(), Scope, InlinedAt); + return DILocation::get(M.getContext(), DL.getLine(), DL.getCol(), + Scope, InlinedAt); }; if (I.getDebugLoc() != DebugLoc()) @@ -696,6 +697,38 @@ void Instruction::applyMergedLocation(const DILocation *LocA, setDebugLoc(DILocation::getMergedLocation(LocA, LocB)); } +void Instruction::updateLocationAfterHoist() { dropLocation(); } + +void Instruction::dropLocation() { + const DebugLoc &DL = getDebugLoc(); + if (!DL) + return; + + // If this isn't a call, drop the location to allow a location from a + // preceding instruction to propagate. + if (!isa<CallBase>(this)) { + setDebugLoc(DebugLoc()); + return; + } + + // Set a line 0 location for calls to preserve scope information in case + // inlining occurs. + DISubprogram *SP = getFunction()->getSubprogram(); + if (SP) + // If a function scope is available, set it on the line 0 location. When + // hoisting a call to a predecessor block, using the function scope avoids + // making it look like the callee was reached earlier than it should be. + setDebugLoc(DILocation::get(getContext(), 0, 0, SP)); + else + // The parent function has no scope. Go ahead and drop the location. If + // the parent function is inlined, and the callee has a subprogram, the + // inliner will attach a location to the call. + // + // One alternative is to set a line 0 location with the existing scope and + // inlinedAt info. The location might be sensitive to when inlining occurs. + setDebugLoc(DebugLoc()); +} + //===----------------------------------------------------------------------===// // LLVM C API implementations. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 110d94116f10..77bba9f7ed0e 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -133,7 +133,7 @@ const DILocation *DILocation::getMergedLocation(const DILocation *LocA, } Optional<unsigned> DILocation::encodeDiscriminator(unsigned BD, unsigned DF, unsigned CI) { - SmallVector<unsigned, 3> Components = {BD, DF, CI}; + std::array<unsigned, 3> Components = {BD, DF, CI}; uint64_t RemainingWork = 0U; // We use RemainingWork to figure out if we have no remaining components to // encode. For example: if BD != 0 but DF == 0 && CI == 0, we don't need to @@ -435,6 +435,84 @@ DISubrange::BoundType DISubrange::getStride() const { return BoundType(); } +DIGenericSubrange *DIGenericSubrange::getImpl(LLVMContext &Context, + Metadata *CountNode, Metadata *LB, + Metadata *UB, Metadata *Stride, + StorageType Storage, + bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DIGenericSubrange, (CountNode, LB, UB, Stride)); + Metadata *Ops[] = {CountNode, LB, UB, Stride}; + DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIGenericSubrange, Ops); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getCount() const { + Metadata *CB = getRawCountNode(); + if (!CB) + return BoundType(); + + assert((isa<DIVariable>(CB) || isa<DIExpression>(CB)) && + "Count must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast<DIVariable>(CB)) + return BoundType(MD); + + if (auto *MD = dyn_cast<DIExpression>(CB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getLowerBound() const { + Metadata *LB = getRawLowerBound(); + if (!LB) + return BoundType(); + + assert((isa<DIVariable>(LB) || isa<DIExpression>(LB)) && + "LowerBound must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast<DIVariable>(LB)) + return BoundType(MD); + + if (auto *MD = dyn_cast<DIExpression>(LB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getUpperBound() const { + Metadata *UB = getRawUpperBound(); + if (!UB) + return BoundType(); + + assert((isa<DIVariable>(UB) || isa<DIExpression>(UB)) && + "UpperBound must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast<DIVariable>(UB)) + return BoundType(MD); + + if (auto *MD = dyn_cast<DIExpression>(UB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getStride() const { + Metadata *ST = getRawStride(); + if (!ST) + return BoundType(); + + assert((isa<DIVariable>(ST) || isa<DIExpression>(ST)) && + "Stride must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast<DIVariable>(ST)) + return BoundType(MD); + + if (auto *MD = dyn_cast<DIExpression>(ST)) + return BoundType(MD); + + return BoundType(); +} + DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, bool IsUnsigned, MDString *Name, StorageType Storage, bool ShouldCreate) { @@ -470,6 +548,20 @@ Optional<DIBasicType::Signedness> DIBasicType::getSignedness() const { } } +DIStringType *DIStringType::getImpl(LLVMContext &Context, unsigned Tag, + MDString *Name, Metadata *StringLength, + Metadata *StringLengthExp, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, StorageType Storage, + bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIStringType, (Tag, Name, StringLength, StringLengthExp, + SizeInBits, AlignInBits, Encoding)); + Metadata *Ops[] = {nullptr, nullptr, Name, StringLength, StringLengthExp}; + DEFINE_GETIMPL_STORE(DIStringType, (Tag, SizeInBits, AlignInBits, Encoding), + Ops); +} + DIDerivedType *DIDerivedType::getImpl( LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, @@ -493,18 +585,20 @@ DICompositeType *DICompositeType::getImpl( uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator, - Metadata *DataLocation, StorageType Storage, bool ShouldCreate) { + Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, + Metadata *Rank, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); // Keep this in sync with buildODRType. - DEFINE_GETIMPL_LOOKUP(DICompositeType, - (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, Elements, - RuntimeLang, VTableHolder, TemplateParams, Identifier, - Discriminator, DataLocation)); + DEFINE_GETIMPL_LOOKUP( + DICompositeType, + (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, + Identifier, Discriminator, DataLocation, Associated, Allocated, Rank)); Metadata *Ops[] = {File, Scope, Name, BaseType, Elements, VTableHolder, TemplateParams, Identifier, - Discriminator, DataLocation}; + Discriminator, DataLocation, Associated, Allocated, + Rank}; DEFINE_GETIMPL_STORE(DICompositeType, (Tag, Line, RuntimeLang, SizeInBits, AlignInBits, OffsetInBits, Flags), Ops); @@ -516,7 +610,8 @@ DICompositeType *DICompositeType::buildODRType( uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, Metadata *Discriminator, - Metadata *DataLocation) { + Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, + Metadata *Rank) { assert(!Identifier.getString().empty() && "Expected valid identifier"); if (!Context.isODRUniquingDebugTypes()) return nullptr; @@ -526,7 +621,7 @@ DICompositeType *DICompositeType::buildODRType( Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, &Identifier, Discriminator, - DataLocation); + DataLocation, Associated, Allocated, Rank); // Only mutate CT if it's a forward declaration and the new operands aren't. assert(CT->getRawIdentifier() == &Identifier && "Wrong ODR identifier?"); @@ -538,7 +633,8 @@ DICompositeType *DICompositeType::buildODRType( Flags); Metadata *Ops[] = {File, Scope, Name, BaseType, Elements, VTableHolder, TemplateParams, &Identifier, - Discriminator, DataLocation}; + Discriminator, DataLocation, Associated, Allocated, + Rank}; assert((std::end(Ops) - std::begin(Ops)) == (int)CT->getNumOperands() && "Mismatched number of operands"); for (unsigned I = 0, E = CT->getNumOperands(); I != E; ++I) @@ -553,7 +649,8 @@ DICompositeType *DICompositeType::getODRType( uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, Metadata *Discriminator, - Metadata *DataLocation) { + Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, + Metadata *Rank) { assert(!Identifier.getString().empty() && "Expected valid identifier"); if (!Context.isODRUniquingDebugTypes()) return nullptr; @@ -562,7 +659,8 @@ DICompositeType *DICompositeType::getODRType( CT = DICompositeType::getDistinct( Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, - TemplateParams, &Identifier, Discriminator, DataLocation); + TemplateParams, &Identifier, Discriminator, DataLocation, Associated, + Allocated, Rank); return CT; } @@ -828,14 +926,14 @@ DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *File, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *APINotesFile, - unsigned LineNo, StorageType Storage, + unsigned LineNo, bool IsDecl, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIModule, (File, Scope, Name, ConfigurationMacros, - IncludePath, APINotesFile, LineNo)); + IncludePath, APINotesFile, LineNo, IsDecl)); Metadata *Ops[] = {File, Scope, Name, ConfigurationMacros, IncludePath, APINotesFile}; - DEFINE_GETIMPL_STORE(DIModule, (LineNo), Ops); + DEFINE_GETIMPL_STORE(DIModule, (LineNo, IsDecl), Ops); } DITemplateTypeParameter * @@ -1016,6 +1114,7 @@ bool DIExpression::isValid() const { return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && getNumElements() == 2; } + case dwarf::DW_OP_LLVM_implicit_pointer: case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_constu: @@ -1040,6 +1139,8 @@ bool DIExpression::isValid() const { case dwarf::DW_OP_regx: case dwarf::DW_OP_bregx: case dwarf::DW_OP_push_object_address: + case dwarf::DW_OP_over: + case dwarf::DW_OP_consts: break; } } @@ -1313,6 +1414,15 @@ bool DIExpression::isConstant() const { return true; } +bool DIExpression::isSignedConstant() const { + // Recognize DW_OP_consts C + if (getNumElements() != 2) + return false; + if (getElement(0) != dwarf::DW_OP_consts) + return false; + return true; +} + DIExpression::ExtOps DIExpression::getExtOps(unsigned FromSize, unsigned ToSize, bool Signed) { dwarf::TypeKind TK = Signed ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned; diff --git a/llvm/lib/IR/DebugLoc.cpp b/llvm/lib/IR/DebugLoc.cpp index e945cbcba782..993f3a39e6ff 100644 --- a/llvm/lib/IR/DebugLoc.cpp +++ b/llvm/lib/IR/DebugLoc.cpp @@ -50,7 +50,7 @@ DebugLoc DebugLoc::getFnDebugLoc() const { // FIXME: Add a method on \a DILocation that does this work. const MDNode *Scope = getInlinedAtScope(); if (auto *SP = getDISubprogram(Scope)) - return DebugLoc::get(SP->getScopeLine(), 0, SP); + return DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); return DebugLoc(); } @@ -68,21 +68,9 @@ void DebugLoc::setImplicitCode(bool ImplicitCode) { } } -DebugLoc DebugLoc::get(unsigned Line, unsigned Col, const MDNode *Scope, - const MDNode *InlinedAt, bool ImplicitCode) { - // If no scope is available, this is an unknown location. - if (!Scope) - return DebugLoc(); - - return DILocation::get(Scope->getContext(), Line, Col, - const_cast<MDNode *>(Scope), - const_cast<MDNode *>(InlinedAt), ImplicitCode); -} - DebugLoc DebugLoc::appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt, LLVMContext &Ctx, - DenseMap<const MDNode *, MDNode *> &Cache, - bool ReplaceLast) { + DenseMap<const MDNode *, MDNode *> &Cache) { SmallVector<DILocation *, 3> InlinedAtLocations; DILocation *Last = InlinedAt; DILocation *CurInlinedAt = DL; @@ -95,8 +83,6 @@ DebugLoc DebugLoc::appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt, break; } - if (ReplaceLast && !IA->getInlinedAt()) - break; InlinedAtLocations.push_back(IA); CurInlinedAt = IA; } diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index 6528c723fbfa..8820a79421c3 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -32,6 +32,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/InstructionCost.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include "llvm/Support/ScopedPrinter.h" @@ -213,6 +214,20 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, unsigned long long N) : Key(std::string(Key)), Val(utostr(N)) {} +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, + ElementCount EC) + : Key(std::string(Key)) { + raw_string_ostream OS(Val); + EC.print(OS); +} + +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, + InstructionCost C) + : Key(std::string(Key)) { + raw_string_ostream OS(Val); + C.print(OS); +} + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc) : Key(std::string(Key)), Loc(Loc) { if (Loc) { @@ -368,16 +383,5 @@ std::string DiagnosticInfoOptimizationBase::getMsg() const { return OS.str(); } -DiagnosticInfoMisExpect::DiagnosticInfoMisExpect(const Instruction *Inst, - Twine &Msg) - : DiagnosticInfoWithLocationBase(DK_MisExpect, DS_Warning, - *Inst->getParent()->getParent(), - Inst->getDebugLoc()), - Msg(Msg) {} - -void DiagnosticInfoMisExpect::print(DiagnosticPrinter &DP) const { - DP << getLocationStr() << ": " << getMsg(); -} - void OptimizationRemarkAnalysisFPCommute::anchor() {} void OptimizationRemarkAnalysisAliasing::anchor() {} diff --git a/llvm/lib/IR/Dominators.cpp b/llvm/lib/IR/Dominators.cpp index bb1cc347dcb1..fbc28c202aec 100644 --- a/llvm/lib/IR/Dominators.cpp +++ b/llvm/lib/IR/Dominators.cpp @@ -90,9 +90,11 @@ template void llvm::DomTreeBuilder::DeleteEdge<DomTreeBuilder::BBPostDomTree>( DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To); template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBDomTree>( - DomTreeBuilder::BBDomTree &DT, DomTreeBuilder::BBUpdates); + DomTreeBuilder::BBDomTree &DT, DomTreeBuilder::BBDomTreeGraphDiff &, + DomTreeBuilder::BBDomTreeGraphDiff *); template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBPostDomTree>( - DomTreeBuilder::BBPostDomTree &DT, DomTreeBuilder::BBUpdates); + DomTreeBuilder::BBPostDomTree &DT, DomTreeBuilder::BBPostDomTreeGraphDiff &, + DomTreeBuilder::BBPostDomTreeGraphDiff *); template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>( const DomTreeBuilder::BBDomTree &DT, @@ -113,8 +115,15 @@ bool DominatorTree::invalidate(Function &F, const PreservedAnalyses &PA, // dominates - Return true if Def dominates a use in User. This performs // the special checks necessary if Def and User are in the same basic block. // Note that Def doesn't dominate a use in Def itself! -bool DominatorTree::dominates(const Instruction *Def, +bool DominatorTree::dominates(const Value *DefV, const Instruction *User) const { + const Instruction *Def = dyn_cast<Instruction>(DefV); + if (!Def) { + assert((isa<Argument>(DefV) || isa<Constant>(DefV)) && + "Should be called with an instruction, argument or constant"); + return true; // Arguments and constants dominate everything. + } + const BasicBlock *UseBB = User->getParent(); const BasicBlock *DefBB = Def->getParent(); @@ -248,7 +257,14 @@ bool DominatorTree::dominates(const BasicBlockEdge &BBE, const Use &U) const { return dominates(BBE, UseBB); } -bool DominatorTree::dominates(const Instruction *Def, const Use &U) const { +bool DominatorTree::dominates(const Value *DefV, const Use &U) const { + const Instruction *Def = dyn_cast<Instruction>(DefV); + if (!Def) { + assert((isa<Argument>(DefV) || isa<Constant>(DefV)) && + "Should be called with an instruction, argument or constant"); + return true; // Arguments and constants dominate everything. + } + Instruction *UserInst = cast<Instruction>(U.getUser()); const BasicBlock *DefBB = Def->getParent(); diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 10d535e3ab11..17247123f87f 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/IntrinsicsR600.h" #include "llvm/IR/IntrinsicsRISCV.h" #include "llvm/IR/IntrinsicsS390.h" +#include "llvm/IR/IntrinsicsVE.h" #include "llvm/IR/IntrinsicsWebAssembly.h" #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/IntrinsicsXCore.h" @@ -86,9 +87,11 @@ void Argument::setParent(Function *parent) { Parent = parent; } -bool Argument::hasNonNullAttr() const { +bool Argument::hasNonNullAttr(bool AllowUndefOrPoison) const { if (!getType()->isPointerTy()) return false; - if (getParent()->hasParamAttribute(getArgNo(), Attribute::NonNull)) + if (getParent()->hasParamAttribute(getArgNo(), Attribute::NonNull) && + (AllowUndefOrPoison || + getParent()->hasParamAttribute(getArgNo(), Attribute::NoUndef))) return true; else if (getDereferenceableBytes() > 0 && !NullPointerIsDefined(getParent(), @@ -102,6 +105,12 @@ bool Argument::hasByValAttr() const { return hasAttribute(Attribute::ByVal); } +bool Argument::hasByRefAttr() const { + if (!getType()->isPointerTy()) + return false; + return hasAttribute(Attribute::ByRef); +} + bool Argument::hasSwiftSelfAttr() const { return getParent()->hasParamAttribute(getArgNo(), Attribute::SwiftSelf); } @@ -121,7 +130,7 @@ bool Argument::hasPreallocatedAttr() const { return hasAttribute(Attribute::Preallocated); } -bool Argument::hasPassPointeeByValueAttr() const { +bool Argument::hasPassPointeeByValueCopyAttr() const { if (!getType()->isPointerTy()) return false; AttributeList Attrs = getParent()->getAttributes(); return Attrs.hasParamAttribute(getArgNo(), Attribute::ByVal) || @@ -129,27 +138,54 @@ bool Argument::hasPassPointeeByValueAttr() const { Attrs.hasParamAttribute(getArgNo(), Attribute::Preallocated); } -uint64_t Argument::getPassPointeeByValueCopySize(const DataLayout &DL) const { - AttributeSet ParamAttrs - = getParent()->getAttributes().getParamAttributes(getArgNo()); +bool Argument::hasPointeeInMemoryValueAttr() const { + if (!getType()->isPointerTy()) + return false; + AttributeList Attrs = getParent()->getAttributes(); + return Attrs.hasParamAttribute(getArgNo(), Attribute::ByVal) || + Attrs.hasParamAttribute(getArgNo(), Attribute::StructRet) || + Attrs.hasParamAttribute(getArgNo(), Attribute::InAlloca) || + Attrs.hasParamAttribute(getArgNo(), Attribute::Preallocated) || + Attrs.hasParamAttribute(getArgNo(), Attribute::ByRef); +} +/// For a byval, sret, inalloca, or preallocated parameter, get the in-memory +/// parameter type. +static Type *getMemoryParamAllocType(AttributeSet ParamAttrs, Type *ArgTy) { // FIXME: All the type carrying attributes are mutually exclusive, so there // should be a single query to get the stored type that handles any of them. if (Type *ByValTy = ParamAttrs.getByValType()) - return DL.getTypeAllocSize(ByValTy); + return ByValTy; + if (Type *ByRefTy = ParamAttrs.getByRefType()) + return ByRefTy; if (Type *PreAllocTy = ParamAttrs.getPreallocatedType()) - return DL.getTypeAllocSize(PreAllocTy); + return PreAllocTy; - // FIXME: inalloca always depends on pointee element type. It's also possible - // for byval to miss it. + // FIXME: sret and inalloca always depends on pointee element type. It's also + // possible for byval to miss it. if (ParamAttrs.hasAttribute(Attribute::InAlloca) || ParamAttrs.hasAttribute(Attribute::ByVal) || + ParamAttrs.hasAttribute(Attribute::StructRet) || ParamAttrs.hasAttribute(Attribute::Preallocated)) - return DL.getTypeAllocSize(cast<PointerType>(getType())->getElementType()); + return cast<PointerType>(ArgTy)->getElementType(); + return nullptr; +} + +uint64_t Argument::getPassPointeeByValueCopySize(const DataLayout &DL) const { + AttributeSet ParamAttrs = + getParent()->getAttributes().getParamAttributes(getArgNo()); + if (Type *MemTy = getMemoryParamAllocType(ParamAttrs, getType())) + return DL.getTypeAllocSize(MemTy); return 0; } +Type *Argument::getPointeeInMemoryValueType() const { + AttributeSet ParamAttrs = + getParent()->getAttributes().getParamAttributes(getArgNo()); + return getMemoryParamAllocType(ParamAttrs, getType()); +} + unsigned Argument::getParamAlignment() const { assert(getType()->isPointerTy() && "Only pointers have alignments"); return getParent()->getParamAlignment(getArgNo()); @@ -165,6 +201,16 @@ Type *Argument::getParamByValType() const { return getParent()->getParamByValType(getArgNo()); } +Type *Argument::getParamStructRetType() const { + assert(getType()->isPointerTy() && "Only pointers have sret types"); + return getParent()->getParamStructRetType(getArgNo()); +} + +Type *Argument::getParamByRefType() const { + assert(getType()->isPointerTy() && "Only pointers have byval types"); + return getParent()->getParamByRefType(getArgNo()); +} + uint64_t Argument::getDereferenceableBytes() const { assert(getType()->isPointerTy() && "Only pointers have dereferenceable bytes"); @@ -534,6 +580,21 @@ void Function::addDereferenceableOrNullParamAttr(unsigned ArgNo, setAttributes(PAL); } +DenormalMode Function::getDenormalMode(const fltSemantics &FPType) const { + if (&FPType == &APFloat::IEEEsingle()) { + Attribute Attr = getFnAttribute("denormal-fp-math-f32"); + StringRef Val = Attr.getValueAsString(); + if (!Val.empty()) + return parseDenormalFPAttribute(Val); + + // If the f32 variant of the attribute isn't specified, try to use the + // generic one. + } + + Attribute Attr = getFnAttribute("denormal-fp-math"); + return parseDenormalFPAttribute(Attr.getValueAsString()); +} + const std::string &Function::getGC() const { assert(hasGC() && "Function has no collector"); return getContext().getGC(*this); @@ -551,6 +612,12 @@ void Function::clearGC() { setValueSubclassDataBit(14, false); } +bool Function::hasStackProtectorFnAttr() const { + return hasFnAttribute(Attribute::StackProtect) || + hasFnAttribute(Attribute::StackProtectStrong) || + hasFnAttribute(Attribute::StackProtectReq); +} + /// Copy all additional attributes (those not needed to create a Function) from /// the Function Src to this one. void Function::copyAttributesFrom(const Function *Src) { @@ -582,6 +649,14 @@ static const char * const IntrinsicNameTable[] = { #include "llvm/IR/IntrinsicImpl.inc" #undef GET_INTRINSIC_TARGET_DATA +bool Function::isTargetIntrinsic(Intrinsic::ID IID) { + return IID > TargetInfos[0].Count; +} + +bool Function::isTargetIntrinsic() const { + return isTargetIntrinsic(IntID); +} + /// Find the segment of \c IntrinsicNameTable for intrinsics with the same /// target as \c Name, or the generic table if \c Name is not target specific. /// @@ -674,9 +749,10 @@ static std::string getMangledTypeStr(Type* Ty) { Result += "f"; } else if (VectorType* VTy = dyn_cast<VectorType>(Ty)) { ElementCount EC = VTy->getElementCount(); - if (EC.Scalable) + if (EC.isScalable()) Result += "nx"; - Result += "v" + utostr(EC.Min) + getMangledTypeStr(VTy->getElementType()); + Result += "v" + utostr(EC.getKnownMinValue()) + + getMangledTypeStr(VTy->getElementType()); } else if (Ty) { switch (Ty->getTypeID()) { default: llvm_unreachable("Unhandled type"); @@ -690,6 +766,7 @@ static std::string getMangledTypeStr(Type* Ty) { case Type::FP128TyID: Result += "f128"; break; case Type::PPC_FP128TyID: Result += "ppcf128"; break; case Type::X86_MMXTyID: Result += "x86mmx"; break; + case Type::X86_AMXTyID: Result += "x86amx"; break; case Type::IntegerTyID: Result += "i" + utostr(cast<IntegerType>(Ty)->getBitWidth()); break; @@ -707,6 +784,8 @@ StringRef Intrinsic::getName(ID id) { std::string Intrinsic::getName(ID id, ArrayRef<Type*> Tys) { assert(id < num_intrinsics && "Invalid intrinsic ID!"); + assert((Tys.empty() || Intrinsic::isOverloaded(id)) && + "This version of getName is for overloaded intrinsics only"); std::string Result(IntrinsicNameTable[id]); for (Type *Ty : Tys) { Result += "." + getMangledTypeStr(Ty); @@ -770,7 +849,10 @@ enum IIT_Info { IIT_SUBDIVIDE4_ARG = 45, IIT_VEC_OF_BITCASTS_TO_INT = 46, IIT_V128 = 47, - IIT_BF16 = 48 + IIT_BF16 = 48, + IIT_STRUCT9 = 49, + IIT_V256 = 50, + IIT_AMX = 51 }; static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, @@ -793,6 +875,9 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, case IIT_MMX: OutputTable.push_back(IITDescriptor::get(IITDescriptor::MMX, 0)); return; + case IIT_AMX: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::AMX, 0)); + return; case IIT_TOKEN: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Token, 0)); return; @@ -864,6 +949,10 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, OutputTable.push_back(IITDescriptor::getVector(128, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); return; + case IIT_V256: + OutputTable.push_back(IITDescriptor::getVector(256, IsScalableVector)); + DecodeIITType(NextElt, Infos, Info, OutputTable); + return; case IIT_V512: OutputTable.push_back(IITDescriptor::getVector(512, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); @@ -932,6 +1021,7 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos, case IIT_EMPTYSTRUCT: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct, 0)); return; + case IIT_STRUCT9: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT8: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT7: ++StructElts; LLVM_FALLTHROUGH; case IIT_STRUCT6: ++StructElts; LLVM_FALLTHROUGH; @@ -1025,6 +1115,7 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos, case IITDescriptor::Void: return Type::getVoidTy(Context); case IITDescriptor::VarArg: return Type::getVoidTy(Context); case IITDescriptor::MMX: return Type::getX86_MMXTy(Context); + case IITDescriptor::AMX: return Type::getX86_AMXTy(Context); case IITDescriptor::Token: return Type::getTokenTy(Context); case IITDescriptor::Metadata: return Type::getMetadataTy(Context); case IITDescriptor::Half: return Type::getHalfTy(Context); @@ -1162,7 +1253,7 @@ Function *Intrinsic::getDeclaration(Module *M, ID id, ArrayRef<Type*> Tys) { // There can never be multiple globals with the same name of different types, // because intrinsics must be a specific type. return cast<Function>( - M->getOrInsertFunction(getName(id, Tys), + M->getOrInsertFunction(Tys.empty() ? getName(id) : getName(id, Tys), getType(M->getContext(), id, Tys)) .getCallee()); } @@ -1204,6 +1295,7 @@ static bool matchIntrinsicType( case IITDescriptor::Void: return !Ty->isVoidTy(); case IITDescriptor::VarArg: return true; case IITDescriptor::MMX: return !Ty->isX86_MMXTy(); + case IITDescriptor::AMX: return !Ty->isX86_AMXTy(); case IITDescriptor::Token: return !Ty->isTokenTy(); case IITDescriptor::Metadata: return !Ty->isMetadataTy(); case IITDescriptor::Half: return !Ty->isHalfTy(); @@ -1356,10 +1448,10 @@ static bool matchIntrinsicType( // Verify the overloaded type "matches" the Ref type. // i.e. Ty is a vector with the same width as Ref. // Composed of pointers to the same element type as Ref. - VectorType *ReferenceType = dyn_cast<VectorType>(ArgTys[RefArgNumber]); - VectorType *ThisArgVecTy = dyn_cast<VectorType>(Ty); + auto *ReferenceType = dyn_cast<VectorType>(ArgTys[RefArgNumber]); + auto *ThisArgVecTy = dyn_cast<VectorType>(Ty); if (!ThisArgVecTy || !ReferenceType || - (ReferenceType->getNumElements() != ThisArgVecTy->getNumElements())) + (ReferenceType->getElementCount() != ThisArgVecTy->getElementCount())) return true; PointerType *ThisArgEltTy = dyn_cast<PointerType>(ThisArgVecTy->getElementType()); diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp index dd8e62164de1..c2cbe7ddddf8 100644 --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -104,7 +104,8 @@ bool GlobalValue::isInterposable() const { bool GlobalValue::canBenefitFromLocalAlias() const { // See AsmPrinter::getSymbolPreferLocal(). - return GlobalObject::isExternalLinkage(getLinkage()) && !isDeclaration() && + return hasDefaultVisibility() && + GlobalObject::isExternalLinkage(getLinkage()) && !isDeclaration() && !isa<GlobalIFunc>(this) && !hasComdat(); } @@ -351,11 +352,15 @@ GlobalVariable::GlobalVariable(Type *Ty, bool constant, LinkageTypes Link, GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant, LinkageTypes Link, Constant *InitVal, const Twine &Name, GlobalVariable *Before, - ThreadLocalMode TLMode, unsigned AddressSpace, + ThreadLocalMode TLMode, + Optional<unsigned> AddressSpace, bool isExternallyInitialized) : GlobalObject(Ty, Value::GlobalVariableVal, OperandTraits<GlobalVariable>::op_begin(this), - InitVal != nullptr, Link, Name, AddressSpace), + InitVal != nullptr, Link, Name, + AddressSpace + ? *AddressSpace + : M.getDataLayout().getDefaultGlobalsAddressSpace()), isConstantGlobal(constant), isExternallyInitializedConstant(isExternallyInitialized) { assert(!Ty->isFunctionTy() && PointerType::isValidElementType(Ty) && diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp index b87dfe1c8df6..91ca984b755c 100644 --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -42,13 +42,14 @@ using namespace llvm; /// created. GlobalVariable *IRBuilderBase::CreateGlobalString(StringRef Str, const Twine &Name, - unsigned AddressSpace) { + unsigned AddressSpace, + Module *M) { Constant *StrConstant = ConstantDataArray::getString(Context, Str); - Module &M = *BB->getParent()->getParent(); - auto *GV = new GlobalVariable(M, StrConstant->getType(), true, - GlobalValue::PrivateLinkage, StrConstant, Name, - nullptr, GlobalVariable::NotThreadLocal, - AddressSpace); + if (!M) + M = BB->getParent()->getParent(); + auto *GV = new GlobalVariable( + *M, StrConstant->getType(), true, GlobalValue::PrivateLinkage, + StrConstant, Name, nullptr, GlobalVariable::NotThreadLocal, AddressSpace); GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); GV->setAlignment(Align(1)); return GV; @@ -79,6 +80,17 @@ static CallInst *createCallHelper(Function *Callee, ArrayRef<Value *> Ops, return CI; } +Value *IRBuilderBase::CreateVScale(Constant *Scaling, const Twine &Name) { + Module *M = GetInsertBlock()->getParent()->getParent(); + assert(isa<ConstantInt>(Scaling) && "Expected constant integer"); + Function *TheFn = + Intrinsic::getDeclaration(M, Intrinsic::vscale, {Scaling->getType()}); + CallInst *CI = createCallHelper(TheFn, {}, this, Name); + return cast<ConstantInt>(Scaling)->getSExtValue() == 1 + ? CI + : CreateMul(CI, Scaling); +} + CallInst *IRBuilderBase::CreateMemSet(Value *Ptr, Value *Val, Value *Size, MaybeAlign Align, bool isVolatile, MDNode *TBAATag, MDNode *ScopeTag, @@ -135,22 +147,21 @@ CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemSet( return CI; } -CallInst *IRBuilderBase::CreateMemCpy(Value *Dst, MaybeAlign DstAlign, - Value *Src, MaybeAlign SrcAlign, - Value *Size, bool isVolatile, - MDNode *TBAATag, MDNode *TBAAStructTag, - MDNode *ScopeTag, MDNode *NoAliasTag) { +CallInst *IRBuilderBase::CreateMemTransferInst( + Intrinsic::ID IntrID, Value *Dst, MaybeAlign DstAlign, Value *Src, + MaybeAlign SrcAlign, Value *Size, bool isVolatile, MDNode *TBAATag, + MDNode *TBAAStructTag, MDNode *ScopeTag, MDNode *NoAliasTag) { Dst = getCastedInt8PtrValue(Dst); Src = getCastedInt8PtrValue(Src); Value *Ops[] = {Dst, Src, Size, getInt1(isVolatile)}; Type *Tys[] = { Dst->getType(), Src->getType(), Size->getType() }; Module *M = BB->getParent()->getParent(); - Function *TheFn = Intrinsic::getDeclaration(M, Intrinsic::memcpy, Tys); + Function *TheFn = Intrinsic::getDeclaration(M, IntrID, Tys); CallInst *CI = createCallHelper(TheFn, Ops, this); - auto* MCI = cast<MemCpyInst>(CI); + auto* MCI = cast<MemTransferInst>(CI); if (DstAlign) MCI->setDestAlignment(*DstAlign); if (SrcAlign) @@ -324,78 +335,57 @@ static CallInst *getReductionIntrinsic(IRBuilderBase *Builder, Intrinsic::ID ID, CallInst *IRBuilderBase::CreateFAddReduce(Value *Acc, Value *Src) { Module *M = GetInsertBlock()->getParent()->getParent(); Value *Ops[] = {Acc, Src}; - Type *Tys[] = {Acc->getType(), Src->getType()}; - auto Decl = Intrinsic::getDeclaration( - M, Intrinsic::experimental_vector_reduce_v2_fadd, Tys); + auto Decl = Intrinsic::getDeclaration(M, Intrinsic::vector_reduce_fadd, + {Src->getType()}); return createCallHelper(Decl, Ops, this); } CallInst *IRBuilderBase::CreateFMulReduce(Value *Acc, Value *Src) { Module *M = GetInsertBlock()->getParent()->getParent(); Value *Ops[] = {Acc, Src}; - Type *Tys[] = {Acc->getType(), Src->getType()}; - auto Decl = Intrinsic::getDeclaration( - M, Intrinsic::experimental_vector_reduce_v2_fmul, Tys); + auto Decl = Intrinsic::getDeclaration(M, Intrinsic::vector_reduce_fmul, + {Src->getType()}); return createCallHelper(Decl, Ops, this); } CallInst *IRBuilderBase::CreateAddReduce(Value *Src) { - return getReductionIntrinsic(this, Intrinsic::experimental_vector_reduce_add, - Src); + return getReductionIntrinsic(this, Intrinsic::vector_reduce_add, Src); } CallInst *IRBuilderBase::CreateMulReduce(Value *Src) { - return getReductionIntrinsic(this, Intrinsic::experimental_vector_reduce_mul, - Src); + return getReductionIntrinsic(this, Intrinsic::vector_reduce_mul, Src); } CallInst *IRBuilderBase::CreateAndReduce(Value *Src) { - return getReductionIntrinsic(this, Intrinsic::experimental_vector_reduce_and, - Src); + return getReductionIntrinsic(this, Intrinsic::vector_reduce_and, Src); } CallInst *IRBuilderBase::CreateOrReduce(Value *Src) { - return getReductionIntrinsic(this, Intrinsic::experimental_vector_reduce_or, - Src); + return getReductionIntrinsic(this, Intrinsic::vector_reduce_or, Src); } CallInst *IRBuilderBase::CreateXorReduce(Value *Src) { - return getReductionIntrinsic(this, Intrinsic::experimental_vector_reduce_xor, - Src); + return getReductionIntrinsic(this, Intrinsic::vector_reduce_xor, Src); } CallInst *IRBuilderBase::CreateIntMaxReduce(Value *Src, bool IsSigned) { - auto ID = IsSigned ? Intrinsic::experimental_vector_reduce_smax - : Intrinsic::experimental_vector_reduce_umax; + auto ID = + IsSigned ? Intrinsic::vector_reduce_smax : Intrinsic::vector_reduce_umax; return getReductionIntrinsic(this, ID, Src); } CallInst *IRBuilderBase::CreateIntMinReduce(Value *Src, bool IsSigned) { - auto ID = IsSigned ? Intrinsic::experimental_vector_reduce_smin - : Intrinsic::experimental_vector_reduce_umin; + auto ID = + IsSigned ? Intrinsic::vector_reduce_smin : Intrinsic::vector_reduce_umin; return getReductionIntrinsic(this, ID, Src); } -CallInst *IRBuilderBase::CreateFPMaxReduce(Value *Src, bool NoNaN) { - auto Rdx = getReductionIntrinsic( - this, Intrinsic::experimental_vector_reduce_fmax, Src); - if (NoNaN) { - FastMathFlags FMF; - FMF.setNoNaNs(); - Rdx->setFastMathFlags(FMF); - } - return Rdx; +CallInst *IRBuilderBase::CreateFPMaxReduce(Value *Src) { + return getReductionIntrinsic(this, Intrinsic::vector_reduce_fmax, Src); } -CallInst *IRBuilderBase::CreateFPMinReduce(Value *Src, bool NoNaN) { - auto Rdx = getReductionIntrinsic( - this, Intrinsic::experimental_vector_reduce_fmin, Src); - if (NoNaN) { - FastMathFlags FMF; - FMF.setNoNaNs(); - Rdx->setFastMathFlags(FMF); - } - return Rdx; +CallInst *IRBuilderBase::CreateFPMinReduce(Value *Src) { + return getReductionIntrinsic(this, Intrinsic::vector_reduce_fmin, Src); } CallInst *IRBuilderBase::CreateLifetimeStart(Value *Ptr, ConstantInt *Size) { @@ -462,6 +452,13 @@ IRBuilderBase::CreateAssumption(Value *Cond, return createCallHelper(FnAssume, Ops, this, "", nullptr, OpBundles); } +Instruction *IRBuilderBase::CreateNoAliasScopeDeclaration(Value *Scope) { + Module *M = BB->getModule(); + auto *FnIntrinsic = Intrinsic::getDeclaration( + M, Intrinsic::experimental_noalias_scope_decl, {}); + return createCallHelper(FnIntrinsic, {Scope}, this); +} + /// Create a call to a Masked Load intrinsic. /// \p Ptr - base pointer for the load /// \p Alignment - alignment of the source location @@ -525,8 +522,8 @@ CallInst *IRBuilderBase::CreateMaskedIntrinsic(Intrinsic::ID Id, CallInst *IRBuilderBase::CreateMaskedGather(Value *Ptrs, Align Alignment, Value *Mask, Value *PassThru, const Twine &Name) { - auto PtrsTy = cast<VectorType>(Ptrs->getType()); - auto PtrTy = cast<PointerType>(PtrsTy->getElementType()); + auto *PtrsTy = cast<FixedVectorType>(Ptrs->getType()); + auto *PtrTy = cast<PointerType>(PtrsTy->getElementType()); unsigned NumElts = PtrsTy->getNumElements(); auto *DataTy = FixedVectorType::get(PtrTy->getElementType(), NumElts); @@ -555,8 +552,8 @@ CallInst *IRBuilderBase::CreateMaskedGather(Value *Ptrs, Align Alignment, /// be accessed in memory CallInst *IRBuilderBase::CreateMaskedScatter(Value *Data, Value *Ptrs, Align Alignment, Value *Mask) { - auto PtrsTy = cast<VectorType>(Ptrs->getType()); - auto DataTy = cast<VectorType>(Data->getType()); + auto *PtrsTy = cast<FixedVectorType>(Ptrs->getType()); + auto *DataTy = cast<FixedVectorType>(Data->getType()); unsigned NumElts = PtrsTy->getNumElements(); #ifndef NDEBUG @@ -588,7 +585,7 @@ getStatepointArgs(IRBuilderBase &B, uint64_t ID, uint32_t NumPatchBytes, Args.push_back(ActualCallee); Args.push_back(B.getInt32(CallArgs.size())); Args.push_back(B.getInt32(Flags)); - Args.insert(Args.end(), CallArgs.begin(), CallArgs.end()); + llvm::append_range(Args, CallArgs); // GC Transition and Deopt args are now always handled via operand bundle. // They will be removed from the signature of gc.statepoint shortly. Args.push_back(B.getInt32(0)); @@ -605,18 +602,17 @@ getStatepointBundles(Optional<ArrayRef<T1>> TransitionArgs, std::vector<OperandBundleDef> Rval; if (DeoptArgs) { SmallVector<Value*, 16> DeoptValues; - DeoptValues.insert(DeoptValues.end(), DeoptArgs->begin(), DeoptArgs->end()); + llvm::append_range(DeoptValues, *DeoptArgs); Rval.emplace_back("deopt", DeoptValues); } if (TransitionArgs) { SmallVector<Value*, 16> TransitionValues; - TransitionValues.insert(TransitionValues.end(), - TransitionArgs->begin(), TransitionArgs->end()); + llvm::append_range(TransitionValues, *TransitionArgs); Rval.emplace_back("gc-transition", TransitionValues); } if (GCArgs.size()) { SmallVector<Value*, 16> LiveValues; - LiveValues.insert(LiveValues.end(), GCArgs.begin(), GCArgs.end()); + llvm::append_range(LiveValues, GCArgs); Rval.emplace_back("gc-live", LiveValues); } return Rval; @@ -662,10 +658,10 @@ CallInst *IRBuilderBase::CreateGCStatepointCall( CallInst *IRBuilderBase::CreateGCStatepointCall( uint64_t ID, uint32_t NumPatchBytes, Value *ActualCallee, uint32_t Flags, - ArrayRef<Use> CallArgs, Optional<ArrayRef<Use>> TransitionArgs, + ArrayRef<Value *> CallArgs, Optional<ArrayRef<Use>> TransitionArgs, Optional<ArrayRef<Use>> DeoptArgs, ArrayRef<Value *> GCArgs, const Twine &Name) { - return CreateGCStatepointCallCommon<Use, Use, Use, Value *>( + return CreateGCStatepointCallCommon<Value *, Use, Use, Value *>( this, ID, NumPatchBytes, ActualCallee, Flags, CallArgs, TransitionArgs, DeoptArgs, GCArgs, Name); } @@ -720,9 +716,9 @@ InvokeInst *IRBuilderBase::CreateGCStatepointInvoke( InvokeInst *IRBuilderBase::CreateGCStatepointInvoke( uint64_t ID, uint32_t NumPatchBytes, Value *ActualInvokee, BasicBlock *NormalDest, BasicBlock *UnwindDest, uint32_t Flags, - ArrayRef<Use> InvokeArgs, Optional<ArrayRef<Use>> TransitionArgs, + ArrayRef<Value *> InvokeArgs, Optional<ArrayRef<Use>> TransitionArgs, Optional<ArrayRef<Use>> DeoptArgs, ArrayRef<Value *> GCArgs, const Twine &Name) { - return CreateGCStatepointInvokeCommon<Use, Use, Use, Value *>( + return CreateGCStatepointInvokeCommon<Value *, Use, Use, Value *>( this, ID, NumPatchBytes, ActualInvokee, NormalDest, UnwindDest, Flags, InvokeArgs, TransitionArgs, DeoptArgs, GCArgs, Name); } @@ -999,18 +995,24 @@ Value *IRBuilderBase::CreateStripInvariantGroup(Value *Ptr) { Value *IRBuilderBase::CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name) { - assert(NumElts > 0 && "Cannot splat to an empty vector!"); + auto EC = ElementCount::getFixed(NumElts); + return CreateVectorSplat(EC, V, Name); +} + +Value *IRBuilderBase::CreateVectorSplat(ElementCount EC, Value *V, + const Twine &Name) { + assert(EC.isNonZero() && "Cannot splat to an empty vector!"); - // First insert it into an undef vector so we can shuffle it. + // First insert it into a poison vector so we can shuffle it. Type *I32Ty = getInt32Ty(); - Value *Undef = UndefValue::get(FixedVectorType::get(V->getType(), NumElts)); - V = CreateInsertElement(Undef, V, ConstantInt::get(I32Ty, 0), + Value *Poison = PoisonValue::get(VectorType::get(V->getType(), EC)); + V = CreateInsertElement(Poison, V, ConstantInt::get(I32Ty, 0), Name + ".splatinsert"); // Shuffle the value across the desired number of elements. - Value *Zeros = - ConstantAggregateZero::get(FixedVectorType::get(I32Ty, NumElts)); - return CreateShuffleVector(V, Undef, Zeros, Name + ".splat"); + SmallVector<int, 16> Zeros; + Zeros.resize(EC.getKnownMinValue()); + return CreateShuffleVector(V, Zeros, Name + ".splat"); } Value *IRBuilderBase::CreateExtractInteger( @@ -1045,9 +1047,7 @@ Value *IRBuilderBase::CreatePreserveArrayAccessIndex( Value *LastIndexV = getInt32(LastIndex); Constant *Zero = ConstantInt::get(Type::getInt32Ty(Context), 0); - SmallVector<Value *, 4> IdxList; - for (unsigned I = 0; I < Dimension; ++I) - IdxList.push_back(Zero); + SmallVector<Value *, 4> IdxList(Dimension, Zero); IdxList.push_back(LastIndexV); Type *ResultType = diff --git a/llvm/lib/IR/IRPrintingPasses.cpp b/llvm/lib/IR/IRPrintingPasses.cpp index 03657ff8d9d4..8d6fe1eb6134 100644 --- a/llvm/lib/IR/IRPrintingPasses.cpp +++ b/llvm/lib/IR/IRPrintingPasses.cpp @@ -11,13 +11,15 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/IRPrintingPasses.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" +#include "llvm/IR/PrintPasses.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; PrintModulePass::PrintModulePass() : OS(dbgs()) {} diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index bfbd801cb7a7..1e3fcd672a43 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -55,9 +55,6 @@ Instruction::~Instruction() { // instructions in a BasicBlock are deleted). if (isUsedByMetadata()) ValueAsMetadata::handleRAUW(this, UndefValue::get(getType())); - - if (hasMetadataHashEntry()) - clearMetadataHashEntries(); } @@ -488,6 +485,7 @@ bool Instruction::isIdenticalToWhenDefined(const Instruction *I) const { if (!std::equal(op_begin(), op_end(), I->op_begin())) return false; + // WARNING: this logic must be kept in sync with EliminateDuplicatePHINodes()! if (const PHINode *thisPHI = dyn_cast<PHINode>(this)) { const PHINode *otherPHI = cast<PHINode>(I); return std::equal(thisPHI->block_begin(), thisPHI->block_end(), @@ -643,16 +641,18 @@ bool Instruction::isLifetimeStartOrEnd() const { return ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end; } -const Instruction *Instruction::getNextNonDebugInstruction() const { +const Instruction * +Instruction::getNextNonDebugInstruction(bool SkipPseudoOp) const { for (const Instruction *I = getNextNode(); I; I = I->getNextNode()) - if (!isa<DbgInfoIntrinsic>(I)) + if (!isa<DbgInfoIntrinsic>(I) && !(SkipPseudoOp && isa<PseudoProbeInst>(I))) return I; return nullptr; } -const Instruction *Instruction::getPrevNonDebugInstruction() const { +const Instruction * +Instruction::getPrevNonDebugInstruction(bool SkipPseudoOp) const { for (const Instruction *I = getPrevNode(); I; I = I->getPrevNode()) - if (!isa<DbgInfoIntrinsic>(I)) + if (!isa<DbgInfoIntrinsic>(I) && !(SkipPseudoOp && isa<PseudoProbeInst>(I))) return I; return nullptr; } @@ -672,6 +672,13 @@ bool Instruction::isAssociative() const { } } +bool Instruction::isCommutative() const { + if (auto *II = dyn_cast<IntrinsicInst>(this)) + return II->isCommutative(); + // TODO: Should allow icmp/fcmp? + return isCommutative(getOpcode()); +} + unsigned Instruction::getNumSuccessors() const { switch (getOpcode()) { #define HANDLE_TERM_INST(N, OPC, CLASS) \ diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index 2f17a0d73af4..d6b4a4f5030f 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -49,13 +49,14 @@ using namespace llvm; // AllocaInst Class //===----------------------------------------------------------------------===// -Optional<uint64_t> +Optional<TypeSize> AllocaInst::getAllocationSizeInBits(const DataLayout &DL) const { - uint64_t Size = DL.getTypeAllocSizeInBits(getAllocatedType()); + TypeSize Size = DL.getTypeAllocSizeInBits(getAllocatedType()); if (isArrayAllocation()) { auto *C = dyn_cast<ConstantInt>(getArraySize()); if (!C) return None; + assert(!Size.isScalable() && "Array elements cannot have a scalable size"); Size *= C->getZExtValue(); } return Size; @@ -321,16 +322,6 @@ Value *CallBase::getReturnedArgOperand() const { return nullptr; } -bool CallBase::hasRetAttr(Attribute::AttrKind Kind) const { - if (Attrs.hasAttribute(AttributeList::ReturnIndex, Kind)) - return true; - - // Look at the callee, if available. - if (const Function *F = getCalledFunction()) - return F->getAttributes().hasAttribute(AttributeList::ReturnIndex, Kind); - return false; -} - /// Determine whether the argument or parameter has the given attribute. bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const { assert(ArgNo < getNumArgOperands() && "Param index out of bounds!"); @@ -409,7 +400,7 @@ CallBase::BundleOpInfo &CallBase::getBundleOpInfoForOperand(unsigned OpIdx) { bundle_op_iterator Begin = bundle_op_info_begin(); bundle_op_iterator End = bundle_op_info_end(); - bundle_op_iterator Current; + bundle_op_iterator Current = Begin; while (Begin != End) { unsigned ScaledOperandPerBundle = @@ -515,6 +506,18 @@ CallInst *CallInst::Create(CallInst *CI, ArrayRef<OperandBundleDef> OpB, return NewCI; } +CallInst *CallInst::CreateWithReplacedBundle(CallInst *CI, OperandBundleDef OpB, + Instruction *InsertPt) { + SmallVector<OperandBundleDef, 2> OpDefs; + for (unsigned i = 0, e = CI->getNumOperandBundles(); i < e; ++i) { + auto ChildOB = CI->getOperandBundleAt(i); + if (ChildOB.getTagName() != OpB.getTag()) + OpDefs.emplace_back(ChildOB); + } + OpDefs.emplace_back(OpB); + return CallInst::Create(CI, OpDefs, InsertPt); +} + // Update profile weight for call instruction by scaling it using the ratio // of S/T. The meaning of "branch_weights" meta data for call instruction is // transfered to represent call count. @@ -548,8 +551,9 @@ void CallInst::updateProfWeight(uint64_t S, uint64_t T) { ->getValue() .getZExtValue()); Val *= APS; - Vals.push_back(MDB.createConstant(ConstantInt::get( - Type::getInt64Ty(getContext()), Val.udiv(APT).getLimitedValue()))); + Vals.push_back(MDB.createConstant( + ConstantInt::get(Type::getInt32Ty(getContext()), + Val.udiv(APT).getLimitedValue(UINT32_MAX)))); } else if (ProfDataName->getString().equals("VP")) for (unsigned i = 1; i < ProfileData->getNumOperands(); i += 2) { // The first value is the key of the value profile, which will not change. @@ -826,6 +830,18 @@ InvokeInst *InvokeInst::Create(InvokeInst *II, ArrayRef<OperandBundleDef> OpB, return NewII; } +InvokeInst *InvokeInst::CreateWithReplacedBundle(InvokeInst *II, + OperandBundleDef OpB, + Instruction *InsertPt) { + SmallVector<OperandBundleDef, 2> OpDefs; + for (unsigned i = 0, e = II->getNumOperandBundles(); i < e; ++i) { + auto ChildOB = II->getOperandBundleAt(i); + if (ChildOB.getTagName() != OpB.getTag()) + OpDefs.emplace_back(ChildOB); + } + OpDefs.emplace_back(OpB); + return InvokeInst::Create(II, OpDefs, InsertPt); +} LandingPadInst *InvokeInst::getLandingPadInst() const { return cast<LandingPadInst>(getUnwindDest()->getFirstNonPHI()); @@ -1919,7 +1935,7 @@ ShuffleVectorInst::ShuffleVectorInst(Value *V1, Value *V2, ArrayRef<int> Mask, } void ShuffleVectorInst::commute() { - int NumOpElts = cast<VectorType>(Op<0>()->getType())->getNumElements(); + int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements(); int NumMaskElts = ShuffleMask.size(); SmallVector<int, 16> NewMask(NumMaskElts); for (int i = 0; i != NumMaskElts; ++i) { @@ -1943,7 +1959,8 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2, return false; // Make sure the mask elements make sense. - int V1Size = cast<VectorType>(V1->getType())->getElementCount().Min; + int V1Size = + cast<VectorType>(V1->getType())->getElementCount().getKnownMinValue(); for (int Elem : Mask) if (Elem != UndefMaskElem && Elem >= V1Size * 2) return false; @@ -1973,7 +1990,7 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2, return true; if (const auto *MV = dyn_cast<ConstantVector>(Mask)) { - unsigned V1Size = cast<VectorType>(V1->getType())->getNumElements(); + unsigned V1Size = cast<FixedVectorType>(V1->getType())->getNumElements(); for (Value *Op : MV->operands()) { if (auto *CI = dyn_cast<ConstantInt>(Op)) { if (CI->uge(V1Size*2)) @@ -1986,8 +2003,9 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2, } if (const auto *CDS = dyn_cast<ConstantDataSequential>(Mask)) { - unsigned V1Size = cast<VectorType>(V1->getType())->getNumElements(); - for (unsigned i = 0, e = MaskTy->getNumElements(); i != e; ++i) + unsigned V1Size = cast<FixedVectorType>(V1->getType())->getNumElements(); + for (unsigned i = 0, e = cast<FixedVectorType>(MaskTy)->getNumElements(); + i != e; ++i) if (CDS->getElementAsInteger(i) >= V1Size*2) return false; return true; @@ -1998,12 +2016,26 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2, void ShuffleVectorInst::getShuffleMask(const Constant *Mask, SmallVectorImpl<int> &Result) { - unsigned NumElts = cast<VectorType>(Mask->getType())->getElementCount().Min; + ElementCount EC = cast<VectorType>(Mask->getType())->getElementCount(); + if (isa<ConstantAggregateZero>(Mask)) { - Result.resize(NumElts, 0); + Result.resize(EC.getKnownMinValue(), 0); return; } - Result.reserve(NumElts); + + Result.reserve(EC.getKnownMinValue()); + + if (EC.isScalable()) { + assert((isa<ConstantAggregateZero>(Mask) || isa<UndefValue>(Mask)) && + "Scalable vector shuffle mask must be undef or zeroinitializer"); + int MaskVal = isa<UndefValue>(Mask) ? -1 : 0; + for (unsigned I = 0; I < EC.getKnownMinValue(); ++I) + Result.emplace_back(MaskVal); + return; + } + + unsigned NumElts = EC.getKnownMinValue(); + if (auto *CDS = dyn_cast<ConstantDataSequential>(Mask)) { for (unsigned i = 0; i != NumElts; ++i) Result.push_back(CDS->getElementAsInteger(i)); @@ -2185,8 +2217,14 @@ bool ShuffleVectorInst::isExtractSubvectorMask(ArrayRef<int> Mask, bool ShuffleVectorInst::isIdentityWithPadding() const { if (isa<UndefValue>(Op<2>())) return false; - int NumOpElts = cast<VectorType>(Op<0>()->getType())->getNumElements(); - int NumMaskElts = cast<VectorType>(getType())->getNumElements(); + + // FIXME: Not currently possible to express a shuffle mask for a scalable + // vector for this case. + if (isa<ScalableVectorType>(getType())) + return false; + + int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements(); + int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements(); if (NumMaskElts <= NumOpElts) return false; @@ -2208,7 +2246,7 @@ bool ShuffleVectorInst::isIdentityWithExtract() const { return false; // FIXME: Not currently possible to express a shuffle mask for a scalable - // vector for this case + // vector for this case. if (isa<ScalableVectorType>(getType())) return false; @@ -2226,8 +2264,13 @@ bool ShuffleVectorInst::isConcat() const { isa<UndefValue>(Op<2>())) return false; - int NumOpElts = cast<VectorType>(Op<0>()->getType())->getNumElements(); - int NumMaskElts = getType()->getNumElements(); + // FIXME: Not currently possible to express a shuffle mask for a scalable + // vector for this case. + if (isa<ScalableVectorType>(getType())) + return false; + + int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements(); + int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements(); if (NumMaskElts != NumOpElts * 2) return false; @@ -2614,6 +2657,7 @@ bool CastInst::isNoopCast(Instruction::CastOps Opcode, Type *SrcTy, Type *DestTy, const DataLayout &DL) { + assert(castIsValid(Opcode, SrcTy, DestTy) && "method precondition"); switch (Opcode) { default: llvm_unreachable("Invalid CastOp"); case Instruction::Trunc: @@ -2968,8 +3012,8 @@ CastInst *CastInst::CreatePointerCast(Value *S, Type *Ty, "Invalid cast"); assert(Ty->isVectorTy() == S->getType()->isVectorTy() && "Invalid cast"); assert((!Ty->isVectorTy() || - cast<VectorType>(Ty)->getNumElements() == - cast<VectorType>(S->getType())->getNumElements()) && + cast<VectorType>(Ty)->getElementCount() == + cast<VectorType>(S->getType())->getElementCount()) && "Invalid cast"); if (Ty->isIntOrIntVectorTy()) @@ -2987,8 +3031,8 @@ CastInst *CastInst::CreatePointerCast(Value *S, Type *Ty, "Invalid cast"); assert(Ty->isVectorTy() == S->getType()->isVectorTy() && "Invalid cast"); assert((!Ty->isVectorTy() || - cast<VectorType>(Ty)->getNumElements() == - cast<VectorType>(S->getType())->getNumElements()) && + cast<VectorType>(Ty)->getElementCount() == + cast<VectorType>(S->getType())->getElementCount()) && "Invalid cast"); if (Ty->isIntOrIntVectorTy()) @@ -3088,63 +3132,6 @@ CastInst *CastInst::CreateFPCast(Value *C, Type *Ty, return Create(opcode, C, Ty, Name, InsertAtEnd); } -// Check whether it is valid to call getCastOpcode for these types. -// This routine must be kept in sync with getCastOpcode. -bool CastInst::isCastable(Type *SrcTy, Type *DestTy) { - if (!SrcTy->isFirstClassType() || !DestTy->isFirstClassType()) - return false; - - if (SrcTy == DestTy) - return true; - - if (VectorType *SrcVecTy = dyn_cast<VectorType>(SrcTy)) - if (VectorType *DestVecTy = dyn_cast<VectorType>(DestTy)) - if (SrcVecTy->getNumElements() == DestVecTy->getNumElements()) { - // An element by element cast. Valid if casting the elements is valid. - SrcTy = SrcVecTy->getElementType(); - DestTy = DestVecTy->getElementType(); - } - - // Get the bit sizes, we'll need these - TypeSize SrcBits = SrcTy->getPrimitiveSizeInBits(); // 0 for ptr - TypeSize DestBits = DestTy->getPrimitiveSizeInBits(); // 0 for ptr - - // Run through the possibilities ... - if (DestTy->isIntegerTy()) { // Casting to integral - if (SrcTy->isIntegerTy()) // Casting from integral - return true; - if (SrcTy->isFloatingPointTy()) // Casting from floating pt - return true; - if (SrcTy->isVectorTy()) // Casting from vector - return DestBits == SrcBits; - // Casting from something else - return SrcTy->isPointerTy(); - } - if (DestTy->isFloatingPointTy()) { // Casting to floating pt - if (SrcTy->isIntegerTy()) // Casting from integral - return true; - if (SrcTy->isFloatingPointTy()) // Casting from floating pt - return true; - if (SrcTy->isVectorTy()) // Casting from vector - return DestBits == SrcBits; - // Casting from something else - return false; - } - if (DestTy->isVectorTy()) // Casting to vector - return DestBits == SrcBits; - if (DestTy->isPointerTy()) { // Casting to pointer - if (SrcTy->isPointerTy()) // Casting from pointer - return true; - return SrcTy->isIntegerTy(); // Casting from integral - } - if (DestTy->isX86_MMXTy()) { - if (SrcTy->isVectorTy()) - return DestBits == SrcBits; // 64-bit vector to MMX - return false; - } // Casting to something else - return false; -} - bool CastInst::isBitCastable(Type *SrcTy, Type *DestTy) { if (!SrcTy->isFirstClassType() || !DestTy->isFirstClassType()) return false; @@ -3206,7 +3193,6 @@ bool CastInst::isBitOrNoopPointerCastable(Type *SrcTy, Type *DestTy, // castIsValid( getCastOpcode(Val, Ty), Val, Ty) // should not assert in castIsValid. In other words, this produces a "correct" // casting opcode for the arguments passed to it. -// This routine must be kept in sync with isCastable. Instruction::CastOps CastInst::getCastOpcode( const Value *Src, bool SrcIsSigned, Type *DestTy, bool DestIsSigned) { @@ -3221,7 +3207,7 @@ CastInst::getCastOpcode( // FIXME: Check address space sizes here if (VectorType *SrcVecTy = dyn_cast<VectorType>(SrcTy)) if (VectorType *DestVecTy = dyn_cast<VectorType>(DestTy)) - if (SrcVecTy->getNumElements() == DestVecTy->getNumElements()) { + if (SrcVecTy->getElementCount() == DestVecTy->getElementCount()) { // An element by element cast. Find the appropriate opcode based on the // element types. SrcTy = SrcVecTy->getElementType(); @@ -3311,10 +3297,7 @@ CastInst::getCastOpcode( /// it in one place and to eliminate the redundant code for getting the sizes /// of the types involved. bool -CastInst::castIsValid(Instruction::CastOps op, Value *S, Type *DstTy) { - // Check for type sanity on the arguments - Type *SrcTy = S->getType(); - +CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) { if (!SrcTy->isFirstClassType() || !DstTy->isFirstClassType() || SrcTy->isAggregateType() || DstTy->isAggregateType()) return false; @@ -3330,9 +3313,9 @@ CastInst::castIsValid(Instruction::CastOps op, Value *S, Type *DstTy) { // scalar types means that checking that vector lengths match also checks that // scalars are not being converted to vectors or vectors to scalars). ElementCount SrcEC = SrcIsVec ? cast<VectorType>(SrcTy)->getElementCount() - : ElementCount(0, false); + : ElementCount::getFixed(0); ElementCount DstEC = DstIsVec ? cast<VectorType>(DstTy)->getElementCount() - : ElementCount(0, false); + : ElementCount::getFixed(0); // Switch on the opcode provided switch (op) { @@ -3390,9 +3373,9 @@ CastInst::castIsValid(Instruction::CastOps op, Value *S, Type *DstTy) { if (SrcIsVec && DstIsVec) return SrcEC == DstEC; if (SrcIsVec) - return SrcEC == ElementCount(1, false); + return SrcEC == ElementCount::getFixed(1); if (DstIsVec) - return DstEC == ElementCount(1, false); + return DstEC == ElementCount::getFixed(1); return true; } @@ -3643,10 +3626,12 @@ bool CmpInst::isCommutative() const { return cast<FCmpInst>(this)->isCommutative(); } -bool CmpInst::isEquality() const { - if (const ICmpInst *IC = dyn_cast<ICmpInst>(this)) - return IC->isEquality(); - return cast<FCmpInst>(this)->isEquality(); +bool CmpInst::isEquality(Predicate P) { + if (ICmpInst::isIntPredicate(P)) + return ICmpInst::isEquality(P); + if (FCmpInst::isFPPredicate(P)) + return FCmpInst::isEquality(P); + llvm_unreachable("Unsupported predicate kind"); } CmpInst::Predicate CmpInst::getInversePredicate(Predicate pred) { @@ -3740,29 +3725,6 @@ ICmpInst::Predicate ICmpInst::getUnsignedPredicate(Predicate pred) { } } -CmpInst::Predicate CmpInst::getFlippedStrictnessPredicate(Predicate pred) { - switch (pred) { - default: llvm_unreachable("Unknown or unsupported cmp predicate!"); - case ICMP_SGT: return ICMP_SGE; - case ICMP_SLT: return ICMP_SLE; - case ICMP_SGE: return ICMP_SGT; - case ICMP_SLE: return ICMP_SLT; - case ICMP_UGT: return ICMP_UGE; - case ICMP_ULT: return ICMP_ULE; - case ICMP_UGE: return ICMP_UGT; - case ICMP_ULE: return ICMP_ULT; - - case FCMP_OGT: return FCMP_OGE; - case FCMP_OLT: return FCMP_OLE; - case FCMP_OGE: return FCMP_OGT; - case FCMP_OLE: return FCMP_OLT; - case FCMP_UGT: return FCMP_UGE; - case FCMP_ULT: return FCMP_ULE; - case FCMP_UGE: return FCMP_UGT; - case FCMP_ULE: return FCMP_ULT; - } -} - CmpInst::Predicate CmpInst::getSwappedPredicate(Predicate pred) { switch (pred) { default: llvm_unreachable("Unknown cmp predicate!"); @@ -3793,22 +3755,97 @@ CmpInst::Predicate CmpInst::getSwappedPredicate(Predicate pred) { } } +bool CmpInst::isNonStrictPredicate(Predicate pred) { + switch (pred) { + case ICMP_SGE: + case ICMP_SLE: + case ICMP_UGE: + case ICMP_ULE: + case FCMP_OGE: + case FCMP_OLE: + case FCMP_UGE: + case FCMP_ULE: + return true; + default: + return false; + } +} + +bool CmpInst::isStrictPredicate(Predicate pred) { + switch (pred) { + case ICMP_SGT: + case ICMP_SLT: + case ICMP_UGT: + case ICMP_ULT: + case FCMP_OGT: + case FCMP_OLT: + case FCMP_UGT: + case FCMP_ULT: + return true; + default: + return false; + } +} + +CmpInst::Predicate CmpInst::getStrictPredicate(Predicate pred) { + switch (pred) { + case ICMP_SGE: + return ICMP_SGT; + case ICMP_SLE: + return ICMP_SLT; + case ICMP_UGE: + return ICMP_UGT; + case ICMP_ULE: + return ICMP_ULT; + case FCMP_OGE: + return FCMP_OGT; + case FCMP_OLE: + return FCMP_OLT; + case FCMP_UGE: + return FCMP_UGT; + case FCMP_ULE: + return FCMP_ULT; + default: + return pred; + } +} + CmpInst::Predicate CmpInst::getNonStrictPredicate(Predicate pred) { switch (pred) { - case ICMP_SGT: return ICMP_SGE; - case ICMP_SLT: return ICMP_SLE; - case ICMP_UGT: return ICMP_UGE; - case ICMP_ULT: return ICMP_ULE; - case FCMP_OGT: return FCMP_OGE; - case FCMP_OLT: return FCMP_OLE; - case FCMP_UGT: return FCMP_UGE; - case FCMP_ULT: return FCMP_ULE; - default: return pred; + case ICMP_SGT: + return ICMP_SGE; + case ICMP_SLT: + return ICMP_SLE; + case ICMP_UGT: + return ICMP_UGE; + case ICMP_ULT: + return ICMP_ULE; + case FCMP_OGT: + return FCMP_OGE; + case FCMP_OLT: + return FCMP_OLE; + case FCMP_UGT: + return FCMP_UGE; + case FCMP_ULT: + return FCMP_ULE; + default: + return pred; } } +CmpInst::Predicate CmpInst::getFlippedStrictnessPredicate(Predicate pred) { + assert(CmpInst::isRelational(pred) && "Call only with relational predicate!"); + + if (isStrictPredicate(pred)) + return getNonStrictPredicate(pred); + if (isNonStrictPredicate(pred)) + return getStrictPredicate(pred); + + llvm_unreachable("Unknown predicate!"); +} + CmpInst::Predicate CmpInst::getSignedPredicate(Predicate pred) { - assert(CmpInst::isUnsigned(pred) && "Call only with signed predicates!"); + assert(CmpInst::isUnsigned(pred) && "Call only with unsigned predicates!"); switch (pred) { default: @@ -3824,6 +3861,23 @@ CmpInst::Predicate CmpInst::getSignedPredicate(Predicate pred) { } } +CmpInst::Predicate CmpInst::getUnsignedPredicate(Predicate pred) { + assert(CmpInst::isSigned(pred) && "Call only with signed predicates!"); + + switch (pred) { + default: + llvm_unreachable("Unknown predicate!"); + case CmpInst::ICMP_SLT: + return CmpInst::ICMP_ULT; + case CmpInst::ICMP_SLE: + return CmpInst::ICMP_ULE; + case CmpInst::ICMP_SGT: + return CmpInst::ICMP_UGT; + case CmpInst::ICMP_SGE: + return CmpInst::ICMP_UGE; + } +} + bool CmpInst::isUnsigned(Predicate predicate) { switch (predicate) { default: return false; @@ -3840,6 +3894,18 @@ bool CmpInst::isSigned(Predicate predicate) { } } +CmpInst::Predicate CmpInst::getFlippedSignednessPredicate(Predicate pred) { + assert(CmpInst::isRelational(pred) && + "Call only with non-equality predicates!"); + + if (isSigned(pred)) + return getUnsignedPredicate(pred); + if (isUnsigned(pred)) + return getSignedPredicate(pred); + + llvm_unreachable("Unknown predicate!"); +} + bool CmpInst::isOrdered(Predicate predicate) { switch (predicate) { default: return false; diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp index c4e06cd979ed..3d1ea2853591 100644 --- a/llvm/lib/IR/IntrinsicInst.cpp +++ b/llvm/lib/IR/IntrinsicInst.cpp @@ -208,7 +208,7 @@ Optional<int> VPIntrinsic::GetMaskParamPos(Intrinsic::ID IntrinsicID) { default: return None; -#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ case Intrinsic::VPID: \ return MASKPOS; #include "llvm/IR/VPIntrinsics.def" @@ -220,7 +220,7 @@ Optional<int> VPIntrinsic::GetVectorLengthParamPos(Intrinsic::ID IntrinsicID) { default: return None; -#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ case Intrinsic::VPID: \ return VLENPOS; #include "llvm/IR/VPIntrinsics.def" @@ -232,7 +232,7 @@ bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) { default: return false; -#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ case Intrinsic::VPID: \ break; #include "llvm/IR/VPIntrinsics.def" @@ -242,25 +242,26 @@ bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) { // Equivalent non-predicated opcode unsigned VPIntrinsic::GetFunctionalOpcodeForVP(Intrinsic::ID ID) { + unsigned FunctionalOC = Instruction::Call; switch (ID) { default: - return Instruction::Call; - -#define HANDLE_VP_TO_OC(VPID, OC) \ - case Intrinsic::VPID: \ - return Instruction::OC; + break; +#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID: +#define HANDLE_VP_TO_OPC(OPC) FunctionalOC = Instruction::OPC; +#define END_REGISTER_VP_INTRINSIC(...) break; #include "llvm/IR/VPIntrinsics.def" } + + return FunctionalOC; } -Intrinsic::ID VPIntrinsic::GetForOpcode(unsigned OC) { - switch (OC) { +Intrinsic::ID VPIntrinsic::GetForOpcode(unsigned IROPC) { + switch (IROPC) { default: return Intrinsic::not_intrinsic; -#define HANDLE_VP_TO_OC(VPID, OC) \ - case Instruction::OC: \ - return Intrinsic::VPID; +#define HANDLE_VP_TO_OPC(OPC) case Instruction::OPC: +#define END_REGISTER_VP_INTRINSIC(VPID) return Intrinsic::VPID; #include "llvm/IR/VPIntrinsics.def" } } @@ -280,8 +281,8 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const { // the operation. This function returns true when this is detected statically // in the IR. - // Check whether "W == vscale * EC.Min" - if (EC.Scalable) { + // Check whether "W == vscale * EC.getKnownMinValue()" + if (EC.isScalable()) { // Undig the DL auto ParMod = this->getModule(); if (!ParMod) @@ -291,8 +292,8 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const { // Compare vscale patterns uint64_t VScaleFactor; if (match(VLParam, m_c_Mul(m_ConstantInt(VScaleFactor), m_VScale(DL)))) - return VScaleFactor >= EC.Min; - return (EC.Min == 1) && match(VLParam, m_VScale(DL)); + return VScaleFactor >= EC.getKnownMinValue(); + return (EC.getKnownMinValue() == 1) && match(VLParam, m_VScale(DL)); } // standard SIMD operation @@ -301,7 +302,7 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const { return false; uint64_t VLNum = VLConst->getZExtValue(); - if (VLNum >= EC.Min) + if (VLNum >= EC.getKnownMinValue()) return true; return false; diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 7ebca5274369..4f292101256d 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -146,11 +146,16 @@ bool LLVMContext::getDiagnosticsHotnessRequested() const { return pImpl->DiagnosticsHotnessRequested; } -void LLVMContext::setDiagnosticsHotnessThreshold(uint64_t Threshold) { +void LLVMContext::setDiagnosticsHotnessThreshold(Optional<uint64_t> Threshold) { pImpl->DiagnosticsHotnessThreshold = Threshold; } + uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const { - return pImpl->DiagnosticsHotnessThreshold; + return pImpl->DiagnosticsHotnessThreshold.getValueOr(UINT64_MAX); +} + +bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { + return !pImpl->DiagnosticsHotnessThreshold.hasValue(); } remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() { diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp index f197b3e67d30..e998138ec3cb 100644 --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -35,6 +35,7 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C) FP128Ty(C, Type::FP128TyID), PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID), + X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8), Int16Ty(C, 16), @@ -50,11 +51,10 @@ LLVMContextImpl::~LLVMContextImpl() { delete *OwnedModules.begin(); #ifndef NDEBUG - // Check for metadata references from leaked Instructions. - for (auto &Pair : InstructionMetadata) + // Check for metadata references from leaked Values. + for (auto &Pair : ValueMetadata) Pair.first->dump(); - assert(InstructionMetadata.empty() && - "Instructions with metadata have been leaked"); + assert(ValueMetadata.empty() && "Values with metadata have been leaked"); #endif // Drop references for MDNodes. Do this before Values get deleted to avoid @@ -98,11 +98,9 @@ LLVMContextImpl::~LLVMContextImpl() { CAZConstants.clear(); CPNConstants.clear(); UVConstants.clear(); + PVConstants.clear(); IntConstants.clear(); FPConstants.clear(); - - for (auto &CDSConstant : CDSConstants) - delete CDSConstant.second; CDSConstants.clear(); // Destroy attribute node lists. @@ -129,8 +127,15 @@ LLVMContextImpl::~LLVMContextImpl() { } void LLVMContextImpl::dropTriviallyDeadConstantArrays() { - SmallSetVector<ConstantArray *, 4> WorkList(ArrayConstants.begin(), - ArrayConstants.end()); + SmallSetVector<ConstantArray *, 4> WorkList; + + // When ArrayConstants are of substantial size and only a few in them are + // dead, starting WorkList with all elements of ArrayConstants can be + // wasteful. Instead, starting WorkList with only elements that have empty + // uses. + for (ConstantArray *C : ArrayConstants) + if (C->use_empty()) + WorkList.insert(C); while (!WorkList.empty()) { ConstantArray *C = WorkList.pop_back_val(); @@ -171,7 +176,7 @@ unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) { unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end()); #ifndef NDEBUG { - SmallVector<Metadata *, 8> MDs(N->op_begin() + Offset, N->op_end()); + SmallVector<Metadata *, 8> MDs(drop_begin(N->operands(), Offset)); unsigned RawHash = calculateHash(MDs); assert(Hash == RawHash && "Expected hash of MDOperand to equal hash of Metadata*"); @@ -215,19 +220,8 @@ void LLVMContextImpl::getSyncScopeNames( SSNs[SSE.second] = SSE.first(); } -/// Singleton instance of the OptBisect class. -/// -/// This singleton is accessed via the LLVMContext::getOptPassGate() function. -/// It provides a mechanism to disable passes and individual optimizations at -/// compile time based on a command line option (-opt-bisect-limit) in order to -/// perform a bisecting search for optimization-related problems. -/// -/// Even if multiple LLVMContext objects are created, they will all return the -/// same instance of OptBisect in order to provide a single bisect count. Any -/// code that uses the OptBisect object should be serialized when bisection is -/// enabled in order to enable a consistent bisect count. -static ManagedStatic<OptBisect> OptBisector; - +/// Gets the OptPassGate for this LLVMContextImpl, which defaults to the +/// singleton OptBisect if not explicitly set. OptPassGate &LLVMContextImpl::getOptPassGate() const { if (!OPG) OPG = &(*OptBisector); diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 1c7d8746d242..05fd1814e2dc 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -57,27 +57,7 @@ class Type; class Value; class ValueHandleBase; -struct DenseMapAPIntKeyInfo { - static inline APInt getEmptyKey() { - APInt V(nullptr, 0); - V.U.VAL = 0; - return V; - } - - static inline APInt getTombstoneKey() { - APInt V(nullptr, 0); - V.U.VAL = 1; - return V; - } - - static unsigned getHashValue(const APInt &Key) { - return static_cast<unsigned>(hash_value(Key)); - } - - static bool isEqual(const APInt &LHS, const APInt &RHS) { - return LHS.getBitWidth() == RHS.getBitWidth() && LHS == RHS; - } -}; +using DenseMapAPIntKeyInfo = DenseMapInfo<APInt>; struct DenseMapAPFloatKeyInfo { static inline APFloat getEmptyKey() { return APFloat(APFloat::Bogus(), 1); } @@ -366,6 +346,36 @@ template <> struct MDNodeKeyImpl<DISubrange> { } }; +template <> struct MDNodeKeyImpl<DIGenericSubrange> { + Metadata *CountNode; + Metadata *LowerBound; + Metadata *UpperBound; + Metadata *Stride; + + MDNodeKeyImpl(Metadata *CountNode, Metadata *LowerBound, Metadata *UpperBound, + Metadata *Stride) + : CountNode(CountNode), LowerBound(LowerBound), UpperBound(UpperBound), + Stride(Stride) {} + MDNodeKeyImpl(const DIGenericSubrange *N) + : CountNode(N->getRawCountNode()), LowerBound(N->getRawLowerBound()), + UpperBound(N->getRawUpperBound()), Stride(N->getRawStride()) {} + + bool isKeyOf(const DIGenericSubrange *RHS) const { + return (CountNode == RHS->getRawCountNode()) && + (LowerBound == RHS->getRawLowerBound()) && + (UpperBound == RHS->getRawUpperBound()) && + (Stride == RHS->getRawStride()); + } + + unsigned getHashValue() const { + auto *MD = dyn_cast_or_null<ConstantAsMetadata>(CountNode); + if (CountNode && MD) + return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(), + LowerBound, UpperBound, Stride); + return hash_combine(CountNode, LowerBound, UpperBound, Stride); + } +}; + template <> struct MDNodeKeyImpl<DIEnumerator> { APInt Value; MDString *Name; @@ -417,6 +427,37 @@ template <> struct MDNodeKeyImpl<DIBasicType> { } }; +template <> struct MDNodeKeyImpl<DIStringType> { + unsigned Tag; + MDString *Name; + Metadata *StringLength; + Metadata *StringLengthExp; + uint64_t SizeInBits; + uint32_t AlignInBits; + unsigned Encoding; + + MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *StringLength, + Metadata *StringLengthExp, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding) + : Tag(Tag), Name(Name), StringLength(StringLength), + StringLengthExp(StringLengthExp), SizeInBits(SizeInBits), + AlignInBits(AlignInBits), Encoding(Encoding) {} + MDNodeKeyImpl(const DIStringType *N) + : Tag(N->getTag()), Name(N->getRawName()), + StringLength(N->getRawStringLength()), + StringLengthExp(N->getRawStringLengthExp()), + SizeInBits(N->getSizeInBits()), AlignInBits(N->getAlignInBits()), + Encoding(N->getEncoding()) {} + + bool isKeyOf(const DIStringType *RHS) const { + return Tag == RHS->getTag() && Name == RHS->getRawName() && + SizeInBits == RHS->getSizeInBits() && + AlignInBits == RHS->getAlignInBits() && + Encoding == RHS->getEncoding(); + } + unsigned getHashValue() const { return hash_combine(Tag, Name, Encoding); } +}; + template <> struct MDNodeKeyImpl<DIDerivedType> { unsigned Tag; MDString *Name; @@ -525,6 +566,9 @@ template <> struct MDNodeKeyImpl<DICompositeType> { MDString *Identifier; Metadata *Discriminator; Metadata *DataLocation; + Metadata *Associated; + Metadata *Allocated; + Metadata *Rank; MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, @@ -532,13 +576,15 @@ template <> struct MDNodeKeyImpl<DICompositeType> { Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator, - Metadata *DataLocation) + Metadata *DataLocation, Metadata *Associated, + Metadata *Allocated, Metadata *Rank) : Tag(Tag), Name(Name), File(File), Line(Line), Scope(Scope), BaseType(BaseType), SizeInBits(SizeInBits), OffsetInBits(OffsetInBits), AlignInBits(AlignInBits), Flags(Flags), Elements(Elements), RuntimeLang(RuntimeLang), VTableHolder(VTableHolder), TemplateParams(TemplateParams), Identifier(Identifier), - Discriminator(Discriminator), DataLocation(DataLocation) {} + Discriminator(Discriminator), DataLocation(DataLocation), + Associated(Associated), Allocated(Allocated), Rank(Rank) {} MDNodeKeyImpl(const DICompositeType *N) : Tag(N->getTag()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Scope(N->getRawScope()), @@ -549,7 +595,9 @@ template <> struct MDNodeKeyImpl<DICompositeType> { TemplateParams(N->getRawTemplateParams()), Identifier(N->getRawIdentifier()), Discriminator(N->getRawDiscriminator()), - DataLocation(N->getRawDataLocation()) {} + DataLocation(N->getRawDataLocation()), + Associated(N->getRawAssociated()), Allocated(N->getRawAllocated()), + Rank(N->getRawRank()) {} bool isKeyOf(const DICompositeType *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && @@ -564,7 +612,9 @@ template <> struct MDNodeKeyImpl<DICompositeType> { TemplateParams == RHS->getRawTemplateParams() && Identifier == RHS->getRawIdentifier() && Discriminator == RHS->getRawDiscriminator() && - DataLocation == RHS->getRawDataLocation(); + DataLocation == RHS->getRawDataLocation() && + Associated == RHS->getRawAssociated() && + Allocated == RHS->getRawAllocated() && Rank == RHS->getRawRank(); } unsigned getHashValue() const { @@ -841,25 +891,28 @@ template <> struct MDNodeKeyImpl<DIModule> { MDString *IncludePath; MDString *APINotesFile; unsigned LineNo; + bool IsDecl; MDNodeKeyImpl(Metadata *File, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, - MDString *APINotesFile, unsigned LineNo) + MDString *APINotesFile, unsigned LineNo, bool IsDecl) : File(File), Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), IncludePath(IncludePath), - APINotesFile(APINotesFile), LineNo(LineNo) {} + APINotesFile(APINotesFile), LineNo(LineNo), IsDecl(IsDecl) {} MDNodeKeyImpl(const DIModule *N) : File(N->getRawFile()), Scope(N->getRawScope()), Name(N->getRawName()), ConfigurationMacros(N->getRawConfigurationMacros()), IncludePath(N->getRawIncludePath()), - APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()) {} + APINotesFile(N->getRawAPINotesFile()), LineNo(N->getLineNo()), + IsDecl(N->getIsDecl()) {} bool isKeyOf(const DIModule *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && ConfigurationMacros == RHS->getRawConfigurationMacros() && IncludePath == RHS->getRawIncludePath() && APINotesFile == RHS->getRawAPINotesFile() && - File == RHS->getRawFile() && LineNo == RHS->getLineNo(); + File == RHS->getRawFile() && LineNo == RHS->getLineNo() && + IsDecl == RHS->getIsDecl(); } unsigned getHashValue() const { @@ -1204,72 +1257,55 @@ template <class NodeTy> struct MDNodeInfo { #define HANDLE_MDNODE_LEAF(CLASS) using CLASS##Info = MDNodeInfo<CLASS>; #include "llvm/IR/Metadata.def" -/// Map-like storage for metadata attachments. -class MDAttachmentMap { - SmallVector<std::pair<unsigned, TrackingMDNodeRef>, 2> Attachments; - +/// Multimap-like storage for metadata attachments. +class MDAttachments { public: - bool empty() const { return Attachments.empty(); } - size_t size() const { return Attachments.size(); } - - /// Get a particular attachment (if any). - MDNode *lookup(unsigned ID) const; - - /// Set an attachment to a particular node. - /// - /// Set the \c ID attachment to \c MD, replacing the current attachment at \c - /// ID (if anyway). - void set(unsigned ID, MDNode &MD); - - /// Remove an attachment. - /// - /// Remove the attachment at \c ID, if any. - bool erase(unsigned ID); - - /// Copy out all the attachments. - /// - /// Copies all the current attachments into \c Result, sorting by attachment - /// ID. This function does \em not clear \c Result. - void getAll(SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const; - - /// Erase matching attachments. - /// - /// Erases all attachments matching the \c shouldRemove predicate. - template <class PredTy> void remove_if(PredTy shouldRemove) { - Attachments.erase(llvm::remove_if(Attachments, shouldRemove), - Attachments.end()); - } -}; - -/// Multimap-like storage for metadata attachments for globals. This differs -/// from MDAttachmentMap in that it allows multiple attachments per metadata -/// kind. -class MDGlobalAttachmentMap { struct Attachment { unsigned MDKind; TrackingMDNodeRef Node; }; + +private: SmallVector<Attachment, 1> Attachments; public: bool empty() const { return Attachments.empty(); } - - /// Appends all attachments with the given ID to \c Result in insertion order. - /// If the global has no attachments with the given ID, or if ID is invalid, - /// leaves Result unchanged. - void get(unsigned ID, SmallVectorImpl<MDNode *> &Result) const; + size_t size() const { return Attachments.size(); } /// Returns the first attachment with the given ID or nullptr if no such /// attachment exists. MDNode *lookup(unsigned ID) const; - void insert(unsigned ID, MDNode &MD); - bool erase(unsigned ID); + /// Appends all attachments with the given ID to \c Result in insertion order. + /// If the global has no attachments with the given ID, or if ID is invalid, + /// leaves Result unchanged. + void get(unsigned ID, SmallVectorImpl<MDNode *> &Result) const; /// Appends all attachments for the global to \c Result, sorting by attachment /// ID. Attachments with the same ID appear in insertion order. This function /// does \em not clear \c Result. void getAll(SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const; + + /// Set an attachment to a particular node. + /// + /// Set the \c ID attachment to \c MD, replacing the current attachments at \c + /// ID (if anyway). + void set(unsigned ID, MDNode *MD); + + /// Adds an attachment to a particular node. + void insert(unsigned ID, MDNode &MD); + + /// Remove attachments with the given ID. + /// + /// Remove the attachments at \c ID, if any. + bool erase(unsigned ID); + + /// Erase matching attachments. + /// + /// Erases all attachments matching the \c shouldRemove predicate. + template <class PredTy> void remove_if(PredTy shouldRemove) { + llvm::erase_if(Attachments, shouldRemove); + } }; class LLVMContextImpl { @@ -1289,7 +1325,26 @@ public: std::unique_ptr<DiagnosticHandler> DiagHandler; bool RespectDiagnosticFilters = false; bool DiagnosticsHotnessRequested = false; - uint64_t DiagnosticsHotnessThreshold = 0; + /// The minimum hotness value a diagnostic needs in order to be included in + /// optimization diagnostics. + /// + /// The threshold is an Optional value, which maps to one of the 3 states: + /// 1). 0 => threshold disabled. All emarks will be printed. + /// 2). positive int => manual threshold by user. Remarks with hotness exceed + /// threshold will be printed. + /// 3). None => 'auto' threshold by user. The actual value is not + /// available at command line, but will be synced with + /// hotness threhold from profile summary during + /// compilation. + /// + /// State 1 and 2 are considered as terminal states. State transition is + /// only allowed from 3 to 2, when the threshold is first synced with profile + /// summary. This ensures that the threshold is set only once and stays + /// constant. + /// + /// If threshold option is not specified, it is disabled (0) by default. + Optional<uint64_t> DiagnosticsHotnessThreshold = 0; + /// The specialized remark streamer used by LLVM's OptimizationRemarkEmitter. std::unique_ptr<LLVMRemarkStreamer> LLVMRS; @@ -1342,10 +1397,15 @@ public: DenseMap<Type *, std::unique_ptr<UndefValue>> UVConstants; - StringMap<ConstantDataSequential*> CDSConstants; + DenseMap<Type *, std::unique_ptr<PoisonValue>> PVConstants; + + StringMap<std::unique_ptr<ConstantDataSequential>> CDSConstants; DenseMap<std::pair<const Function *, const BasicBlock *>, BlockAddress *> BlockAddresses; + + DenseMap<const GlobalValue *, DSOLocalEquivalent *> DSOLocalEquivalents; + ConstantUniqueMap<ConstantExpr> ExprConstants; ConstantUniqueMap<InlineAsm> InlineAsms; @@ -1358,7 +1418,7 @@ public: // Basic type instances. Type VoidTy, LabelTy, HalfTy, BFloatTy, FloatTy, DoubleTy, MetadataTy, TokenTy; - Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy; + Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy, X86_AMXTy; IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty; BumpPtrAllocator Alloc; @@ -1387,11 +1447,8 @@ public: /// CustomMDKindNames - Map to hold the metadata string to ID mapping. StringMap<unsigned> CustomMDKindNames; - /// Collection of per-instruction metadata used in this context. - DenseMap<const Instruction *, MDAttachmentMap> InstructionMetadata; - - /// Collection of per-GlobalObject metadata used in this context. - DenseMap<const GlobalObject *, MDGlobalAttachmentMap> GlobalObjectMetadata; + /// Collection of metadata used in this context. + DenseMap<const Value *, MDAttachments> ValueMetadata; /// Collection of per-GlobalObject sections used in this context. DenseMap<const GlobalObject *, StringRef> GlobalObjectSections; diff --git a/llvm/lib/IR/LLVMRemarkStreamer.cpp b/llvm/lib/IR/LLVMRemarkStreamer.cpp index 96001ab42c38..18b47611c97c 100644 --- a/llvm/lib/IR/LLVMRemarkStreamer.cpp +++ b/llvm/lib/IR/LLVMRemarkStreamer.cpp @@ -92,12 +92,11 @@ char LLVMRemarkSetupFormatError::ID = 0; Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks( LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, - unsigned RemarksHotnessThreshold) { + Optional<uint64_t> RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); - if (RemarksHotnessThreshold) - Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); + Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); if (RemarksFilename.empty()) return nullptr; @@ -137,16 +136,14 @@ Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks( return std::move(RemarksFile); } -Error llvm::setupLLVMOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, - StringRef RemarksPasses, - StringRef RemarksFormat, - bool RemarksWithHotness, - unsigned RemarksHotnessThreshold) { +Error llvm::setupLLVMOptimizationRemarks( + LLVMContext &Context, raw_ostream &OS, StringRef RemarksPasses, + StringRef RemarksFormat, bool RemarksWithHotness, + Optional<uint64_t> RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); - if (RemarksHotnessThreshold) - Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); + Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp index 74869fa62c66..4547c3a01239 100644 --- a/llvm/lib/IR/LegacyPassManager.cpp +++ b/llvm/lib/IR/LegacyPassManager.cpp @@ -20,6 +20,8 @@ #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/PrintPasses.h" +#include "llvm/IR/StructuralHash.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -48,7 +50,7 @@ namespace { enum PassDebugLevel { Disabled, Arguments, Structure, Executions, Details }; -} +} // namespace static cl::opt<enum PassDebugLevel> PassDebugging("debug-pass", cl::Hidden, @@ -60,80 +62,6 @@ PassDebugging("debug-pass", cl::Hidden, clEnumVal(Executions, "print pass name before it is executed"), clEnumVal(Details , "print pass details when it is executed"))); -namespace { -typedef llvm::cl::list<const llvm::PassInfo *, bool, PassNameParser> -PassOptionList; -} - -// Print IR out before/after specified passes. -static PassOptionList -PrintBefore("print-before", - llvm::cl::desc("Print IR before specified passes"), - cl::Hidden); - -static PassOptionList -PrintAfter("print-after", - llvm::cl::desc("Print IR after specified passes"), - cl::Hidden); - -static cl::opt<bool> PrintBeforeAll("print-before-all", - llvm::cl::desc("Print IR before each pass"), - cl::init(false), cl::Hidden); -static cl::opt<bool> PrintAfterAll("print-after-all", - llvm::cl::desc("Print IR after each pass"), - cl::init(false), cl::Hidden); - -static cl::opt<bool> - PrintModuleScope("print-module-scope", - cl::desc("When printing IR for print-[before|after]{-all} " - "always print a module IR"), - cl::init(false), cl::Hidden); - -static cl::list<std::string> - PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), - cl::desc("Only print IR for functions whose name " - "match this for all print-[before|after][-all] " - "options"), - cl::CommaSeparated, cl::Hidden); - -/// This is a helper to determine whether to print IR before or -/// after a pass. - -bool llvm::shouldPrintBeforePass() { - return PrintBeforeAll || !PrintBefore.empty(); -} - -bool llvm::shouldPrintAfterPass() { - return PrintAfterAll || !PrintAfter.empty(); -} - -static bool ShouldPrintBeforeOrAfterPass(StringRef PassID, - PassOptionList &PassesToPrint) { - for (auto *PassInf : PassesToPrint) { - if (PassInf) - if (PassInf->getPassArgument() == PassID) { - return true; - } - } - return false; -} - -bool llvm::shouldPrintBeforePass(StringRef PassID) { - return PrintBeforeAll || ShouldPrintBeforeOrAfterPass(PassID, PrintBefore); -} - -bool llvm::shouldPrintAfterPass(StringRef PassID) { - return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PassID, PrintAfter); -} - -bool llvm::forcePrintModuleIR() { return PrintModuleScope; } - -bool llvm::isFunctionInPrintList(StringRef FunctionName) { - static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(), - PrintFuncsList.end()); - return PrintFuncNames.empty() || - PrintFuncNames.count(std::string(FunctionName)); -} /// isPassDebuggingExecutionsOrMore - Return true if -debug-pass=Executions /// or higher is specified. bool PMDataManager::isPassDebuggingExecutionsOrMore() const { @@ -209,8 +137,7 @@ void PMDataManager::emitInstrCountChangedRemark( // remarks. Since it's possible that the first function in the module // doesn't actually contain a basic block, we have to go and find one that's // suitable for emitting remarks. - auto It = std::find_if(M.begin(), M.end(), - [](const Function &Fn) { return !Fn.empty(); }); + auto It = llvm::find_if(M, [](const Function &Fn) { return !Fn.empty(); }); // Didn't find a function. Quit. if (It == M.end()) @@ -641,7 +568,12 @@ PMTopLevelManager::setLastUser(ArrayRef<Pass*> AnalysisPasses, Pass *P) { PDepth = P->getResolver()->getPMDataManager().getDepth(); for (Pass *AP : AnalysisPasses) { - LastUser[AP] = P; + // Record P as the new last user of AP. + auto &LastUserOfAP = LastUser[AP]; + if (LastUserOfAP) + InversedLastUser[LastUserOfAP].erase(AP); + LastUserOfAP = P; + InversedLastUser[P].insert(AP); if (P == AP) continue; @@ -671,31 +603,25 @@ PMTopLevelManager::setLastUser(ArrayRef<Pass*> AnalysisPasses, Pass *P) { if (P->getResolver()) setLastUser(LastPMUses, P->getResolver()->getPMDataManager().getAsPass()); - // If AP is the last user of other passes then make P last user of // such passes. - for (auto LU : LastUser) { - if (LU.second == AP) - // DenseMap iterator is not invalidated here because - // this is just updating existing entries. - LastUser[LU.first] = P; - } + auto &LastUsedByAP = InversedLastUser[AP]; + for (Pass *L : LastUsedByAP) + LastUser[L] = P; + InversedLastUser[P].insert(LastUsedByAP.begin(), LastUsedByAP.end()); + LastUsedByAP.clear(); } } /// Collect passes whose last user is P void PMTopLevelManager::collectLastUses(SmallVectorImpl<Pass *> &LastUses, Pass *P) { - DenseMap<Pass *, SmallPtrSet<Pass *, 8> >::iterator DMI = - InversedLastUser.find(P); + auto DMI = InversedLastUser.find(P); if (DMI == InversedLastUser.end()) return; - SmallPtrSet<Pass *, 8> &LU = DMI->second; - for (Pass *LUP : LU) { - LastUses.push_back(LUP); - } - + auto &LU = DMI->second; + LastUses.append(LU.begin(), LU.end()); } AnalysisUsage *PMTopLevelManager::findAnalysisUsage(Pass *P) { @@ -929,11 +855,6 @@ void PMTopLevelManager::initializeAllAnalysisInfo() { // Initailize other pass managers for (PMDataManager *IPM : IndirectPassManagers) IPM->initializeAnalysisInfo(); - - for (auto LU : LastUser) { - SmallPtrSet<Pass *, 8> &L = InversedLastUser[LU.second]; - L.insert(LU.first); - } } /// Destructor @@ -1189,12 +1110,6 @@ void PMDataManager::collectRequiredAndUsedAnalyses( UP.push_back(AnalysisPass); else RP_NotAvail.push_back(RequiredID); - - for (const auto &RequiredID : AnUsage->getRequiredTransitiveSet()) - if (Pass *AnalysisPass = findAnalysisPass(RequiredID, true)) - UP.push_back(AnalysisPass); - else - RP_NotAvail.push_back(RequiredID); } // All Required analyses should be available to the pass as it runs! Here @@ -1236,6 +1151,8 @@ Pass *PMDataManager::findAnalysisPass(AnalysisID AID, bool SearchParent) { // Print list of passes that are last used by P. void PMDataManager::dumpLastUses(Pass *P, unsigned Offset) const{ + if (PassDebugging < Details) + return; SmallVector<Pass *, 12> LUses; @@ -1391,8 +1308,8 @@ PMDataManager::~PMDataManager() { //===----------------------------------------------------------------------===// // NOTE: Is this the right place to define this method ? // getAnalysisIfAvailable - Return analysis result or null if it doesn't exist. -Pass *AnalysisResolver::getAnalysisIfAvailable(AnalysisID ID, bool dir) const { - return PM.findAnalysisPass(ID, dir); +Pass *AnalysisResolver::getAnalysisIfAvailable(AnalysisID ID) const { + return PM.findAnalysisPass(ID, true); } std::tuple<Pass *, bool> @@ -1475,75 +1392,6 @@ void FPPassManager::dumpPassStructure(unsigned Offset) { } } -#ifdef EXPENSIVE_CHECKS -namespace { -namespace details { - -// Basic hashing mechanism to detect structural change to the IR, used to verify -// pass return status consistency with actual change. Loosely copied from -// llvm/lib/Transforms/Utils/FunctionComparator.cpp - -class StructuralHash { - uint64_t Hash = 0x6acaa36bef8325c5ULL; - - void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } - -public: - StructuralHash() = default; - - void update(Function &F) { - if (F.empty()) - return; - - update(F.isVarArg()); - update(F.arg_size()); - - SmallVector<const BasicBlock *, 8> BBs; - SmallPtrSet<const BasicBlock *, 16> VisitedBBs; - - BBs.push_back(&F.getEntryBlock()); - VisitedBBs.insert(BBs[0]); - while (!BBs.empty()) { - const BasicBlock *BB = BBs.pop_back_val(); - update(45798); // Block header - for (auto &Inst : *BB) - update(Inst.getOpcode()); - - const Instruction *Term = BB->getTerminator(); - for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) { - if (!VisitedBBs.insert(Term->getSuccessor(i)).second) - continue; - BBs.push_back(Term->getSuccessor(i)); - } - } - } - - void update(Module &M) { - for (Function &F : M) - update(F); - } - - uint64_t getHash() const { return Hash; } -}; - -} // namespace details - -uint64_t StructuralHash(Function &F) { - details::StructuralHash H; - H.update(F); - return H.getHash(); -} - -uint64_t StructuralHash(Module &M) { - details::StructuralHash H; - H.update(M); - return H.getHash(); -} - -} // end anonymous namespace - -#endif - /// Execute all of the passes scheduled for execution by invoking /// runOnFunction method. Keep track of whether any of the passes modifies /// the function, and if so, return true. @@ -1586,9 +1434,12 @@ bool FPPassManager::runOnFunction(Function &F) { #endif LocalChanged |= FP->runOnFunction(F); -#ifdef EXPENSIVE_CHECKS - assert((LocalChanged || (RefHash == StructuralHash(F))) && - "Pass modifies its input and doesn't report it."); +#if defined(EXPENSIVE_CHECKS) && !defined(NDEBUG) + if (!LocalChanged && (RefHash != StructuralHash(F))) { + llvm::errs() << "Pass modifies its input and doesn't report it: " + << FP->getPassName() << "\n"; + llvm_unreachable("Pass modifies its input and doesn't report it"); + } #endif if (EmitICRemark) { @@ -1614,7 +1465,8 @@ bool FPPassManager::runOnFunction(Function &F) { dumpUsedSet(FP); verifyPreservedAnalysis(FP); - removeNotPreservedAnalysis(FP); + if (LocalChanged) + removeNotPreservedAnalysis(FP); recordAvailableAnalysis(FP); removeDeadPasses(FP, F.getName(), ON_FUNCTION_MSG); } @@ -1723,7 +1575,8 @@ MPPassManager::runOnModule(Module &M) { dumpUsedSet(MP); verifyPreservedAnalysis(MP); - removeNotPreservedAnalysis(MP); + if (LocalChanged) + removeNotPreservedAnalysis(MP); recordAvailableAnalysis(MP); removeDeadPasses(MP, M.getModuleIdentifier(), ON_MODULE_MSG); } diff --git a/llvm/lib/IR/MDBuilder.cpp b/llvm/lib/IR/MDBuilder.cpp index 40d70f43132d..35af8490287b 100644 --- a/llvm/lib/IR/MDBuilder.cpp +++ b/llvm/lib/IR/MDBuilder.cpp @@ -151,24 +151,20 @@ MDNode *MDBuilder::mergeCallbackEncodings(MDNode *ExistingCallbacks, } MDNode *MDBuilder::createAnonymousAARoot(StringRef Name, MDNode *Extra) { - // To ensure uniqueness the root node is self-referential. - auto Dummy = MDNode::getTemporary(Context, None); - - SmallVector<Metadata *, 3> Args(1, Dummy.get()); + SmallVector<Metadata *, 3> Args(1, nullptr); if (Extra) Args.push_back(Extra); if (!Name.empty()) Args.push_back(createString(Name)); - MDNode *Root = MDNode::get(Context, Args); + MDNode *Root = MDNode::getDistinct(Context, Args); // At this point we have - // !0 = metadata !{} <- dummy - // !1 = metadata !{metadata !0} <- root - // Replace the dummy operand with the root node itself and delete the dummy. + // !0 = distinct !{null} <- root + // Replace the reserved operand with the root node itself. Root->replaceOperandWith(0, Root); // We now have - // !1 = metadata !{metadata !1} <- self-referential root + // !0 = distinct !{!0} <- root return Root; } @@ -310,14 +306,12 @@ MDNode *MDBuilder::createIrrLoopHeaderWeight(uint64_t Weight) { return MDNode::get(Context, Vals); } -MDNode *MDBuilder::createMisExpect(uint64_t Index, uint64_t LikleyWeight, - uint64_t UnlikleyWeight) { - auto *IntType = Type::getInt64Ty(Context); - Metadata *Vals[] = { - createString("misexpect"), - createConstant(ConstantInt::get(IntType, Index)), - createConstant(ConstantInt::get(IntType, LikleyWeight)), - createConstant(ConstantInt::get(IntType, UnlikleyWeight)), - }; - return MDNode::get(Context, Vals); +MDNode *MDBuilder::createPseudoProbeDesc(uint64_t GUID, uint64_t Hash, + Function *F) { + auto *Int64Ty = Type::getInt64Ty(Context); + SmallVector<Metadata *, 3> Ops(3); + Ops[0] = createConstant(ConstantInt::get(Int64Ty, GUID)); + Ops[1] = createConstant(ConstantInt::get(Int64Ty, Hash)); + Ops[2] = createString(F->getName()); + return MDNode::get(Context, Ops); } diff --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp index 0d66e321c396..674ba3cdaa24 100644 --- a/llvm/lib/IR/Mangler.cpp +++ b/llvm/lib/IR/Mangler.cpp @@ -12,6 +12,7 @@ #include "llvm/IR/Mangler.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" @@ -100,7 +101,7 @@ static void addByteCountSuffix(raw_ostream &OS, const Function *F, for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) { // 'Dereference' type in case of byval or inalloca parameter attribute. - uint64_t AllocSize = AI->hasPassPointeeByValueAttr() ? + uint64_t AllocSize = AI->hasPassPointeeByValueCopyAttr() ? AI->getPassPointeeByValueCopySize(DL) : DL.getTypeAllocSize(AI->getType()); @@ -184,6 +185,25 @@ void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName, getNameWithPrefix(OS, GV, CannotUsePrivateLabel); } +// Check if the name needs quotes to be safe for the linker to interpret. +static bool canBeUnquotedInDirective(char C) { + return isAlnum(C) || C == '_' || C == '$' || C == '.' || C == '@'; +} + +static bool canBeUnquotedInDirective(StringRef Name) { + if (Name.empty()) + return false; + + // If any of the characters in the string is an unacceptable character, force + // quotes. + for (char C : Name) { + if (!canBeUnquotedInDirective(C)) + return false; + } + + return true; +} + void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, const Triple &TT, Mangler &Mangler) { if (!GV->hasDLLExportStorageClass() || GV->isDeclaration()) @@ -194,6 +214,9 @@ void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, else OS << " -export:"; + bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName()); + if (NeedQuotes) + OS << "\""; if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) { std::string Flag; raw_string_ostream FlagOS(Flag); @@ -206,6 +229,8 @@ void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, } else { Mangler.getNameWithPrefix(OS, GV, false); } + if (NeedQuotes) + OS << "\""; if (!GV->getValueType()->isFunctionTy()) { if (TT.isWindowsMSVCEnvironment()) @@ -221,6 +246,11 @@ void llvm::emitLinkerFlagsForUsedCOFF(raw_ostream &OS, const GlobalValue *GV, return; OS << " /INCLUDE:"; + bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName()); + if (NeedQuotes) + OS << "\""; M.getNameWithPrefix(OS, GV, false); + if (NeedQuotes) + OS << "\""; } diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp index ce89009e86eb..7ca538995db2 100644 --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Metadata.h" #include "LLVMContextImpl.h" #include "MetadataImpl.h" #include "SymbolTableListTraitsImpl.h" @@ -38,7 +39,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Metadata.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/Type.h" @@ -640,10 +641,7 @@ void MDNode::resolveCycles() { } static bool hasSelfReference(MDNode *N) { - for (Metadata *MD : N->operands()) - if (MD == N) - return true; - return false; + return llvm::is_contained(N->operands(), N); } MDNode *MDNode::replaceWithPermanentImpl() { @@ -925,7 +923,32 @@ MDNode *MDNode::getMostGenericAliasScope(MDNode *A, MDNode *B) { if (!A || !B) return nullptr; - return concatenate(A, B); + // Take the intersection of domains then union the scopes + // within those domains + SmallPtrSet<const MDNode *, 16> ADomains; + SmallPtrSet<const MDNode *, 16> IntersectDomains; + SmallSetVector<Metadata *, 4> MDs; + for (const MDOperand &MDOp : A->operands()) + if (const MDNode *NAMD = dyn_cast<MDNode>(MDOp)) + if (const MDNode *Domain = AliasScopeNode(NAMD).getDomain()) + ADomains.insert(Domain); + + for (const MDOperand &MDOp : B->operands()) + if (const MDNode *NAMD = dyn_cast<MDNode>(MDOp)) + if (const MDNode *Domain = AliasScopeNode(NAMD).getDomain()) + if (ADomains.contains(Domain)) { + IntersectDomains.insert(Domain); + MDs.insert(MDOp); + } + + for (const MDOperand &MDOp : A->operands()) + if (const MDNode *NAMD = dyn_cast<MDNode>(MDOp)) + if (const MDNode *Domain = AliasScopeNode(NAMD).getDomain()) + if (IntersectDomains.contains(Domain)) + MDs.insert(MDOp); + + return MDs.empty() ? nullptr + : getOrSelfReference(A->getContext(), MDs.getArrayRef()); } MDNode *MDNode::getMostGenericFPMath(MDNode *A, MDNode *B) { @@ -1101,87 +1124,158 @@ StringRef NamedMDNode::getName() const { return StringRef(Name); } //===----------------------------------------------------------------------===// // Instruction Metadata method implementations. // -void MDAttachmentMap::set(unsigned ID, MDNode &MD) { - for (auto &I : Attachments) - if (I.first == ID) { - I.second.reset(&MD); - return; - } - Attachments.emplace_back(std::piecewise_construct, std::make_tuple(ID), - std::make_tuple(&MD)); + +MDNode *MDAttachments::lookup(unsigned ID) const { + for (const auto &A : Attachments) + if (A.MDKind == ID) + return A.Node; + return nullptr; +} + +void MDAttachments::get(unsigned ID, SmallVectorImpl<MDNode *> &Result) const { + for (const auto &A : Attachments) + if (A.MDKind == ID) + Result.push_back(A.Node); } -bool MDAttachmentMap::erase(unsigned ID) { +void MDAttachments::getAll( + SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const { + for (const auto &A : Attachments) + Result.emplace_back(A.MDKind, A.Node); + + // Sort the resulting array so it is stable with respect to metadata IDs. We + // need to preserve the original insertion order though. + if (Result.size() > 1) + llvm::stable_sort(Result, less_first()); +} + +void MDAttachments::set(unsigned ID, MDNode *MD) { + erase(ID); + if (MD) + insert(ID, *MD); +} + +void MDAttachments::insert(unsigned ID, MDNode &MD) { + Attachments.push_back({ID, TrackingMDNodeRef(&MD)}); +} + +bool MDAttachments::erase(unsigned ID) { if (empty()) return false; - // Common case is one/last value. - if (Attachments.back().first == ID) { + // Common case is one value. + if (Attachments.size() == 1 && Attachments.back().MDKind == ID) { Attachments.pop_back(); return true; } - for (auto I = Attachments.begin(), E = std::prev(Attachments.end()); I != E; - ++I) - if (I->first == ID) { - *I = std::move(Attachments.back()); - Attachments.pop_back(); - return true; - } + auto OldSize = Attachments.size(); + llvm::erase_if(Attachments, + [ID](const Attachment &A) { return A.MDKind == ID; }); + return OldSize != Attachments.size(); +} - return false; +MDNode *Value::getMetadata(unsigned KindID) const { + if (!hasMetadata()) + return nullptr; + const auto &Info = getContext().pImpl->ValueMetadata[this]; + assert(!Info.empty() && "bit out of sync with hash table"); + return Info.lookup(KindID); } -MDNode *MDAttachmentMap::lookup(unsigned ID) const { - for (const auto &I : Attachments) - if (I.first == ID) - return I.second; - return nullptr; +MDNode *Value::getMetadata(StringRef Kind) const { + if (!hasMetadata()) + return nullptr; + const auto &Info = getContext().pImpl->ValueMetadata[this]; + assert(!Info.empty() && "bit out of sync with hash table"); + return Info.lookup(getContext().getMDKindID(Kind)); } -void MDAttachmentMap::getAll( - SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const { - Result.append(Attachments.begin(), Attachments.end()); +void Value::getMetadata(unsigned KindID, SmallVectorImpl<MDNode *> &MDs) const { + if (hasMetadata()) + getContext().pImpl->ValueMetadata[this].get(KindID, MDs); +} - // Sort the resulting array so it is stable. - if (Result.size() > 1) - array_pod_sort(Result.begin(), Result.end()); +void Value::getMetadata(StringRef Kind, SmallVectorImpl<MDNode *> &MDs) const { + if (hasMetadata()) + getMetadata(getContext().getMDKindID(Kind), MDs); } -void MDGlobalAttachmentMap::insert(unsigned ID, MDNode &MD) { - Attachments.push_back({ID, TrackingMDNodeRef(&MD)}); +void Value::getAllMetadata( + SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const { + if (hasMetadata()) { + assert(getContext().pImpl->ValueMetadata.count(this) && + "bit out of sync with hash table"); + const auto &Info = getContext().pImpl->ValueMetadata.find(this)->second; + assert(!Info.empty() && "Shouldn't have called this"); + Info.getAll(MDs); + } } -MDNode *MDGlobalAttachmentMap::lookup(unsigned ID) const { - for (const auto &A : Attachments) - if (A.MDKind == ID) - return A.Node; - return nullptr; +void Value::setMetadata(unsigned KindID, MDNode *Node) { + assert(isa<Instruction>(this) || isa<GlobalObject>(this)); + + // Handle the case when we're adding/updating metadata on a value. + if (Node) { + auto &Info = getContext().pImpl->ValueMetadata[this]; + assert(!Info.empty() == HasMetadata && "bit out of sync with hash table"); + if (Info.empty()) + HasMetadata = true; + Info.set(KindID, Node); + return; + } + + // Otherwise, we're removing metadata from an instruction. + assert((HasMetadata == (getContext().pImpl->ValueMetadata.count(this) > 0)) && + "bit out of sync with hash table"); + if (!HasMetadata) + return; // Nothing to remove! + auto &Info = getContext().pImpl->ValueMetadata[this]; + + // Handle removal of an existing value. + Info.erase(KindID); + if (!Info.empty()) + return; + getContext().pImpl->ValueMetadata.erase(this); + HasMetadata = false; } -void MDGlobalAttachmentMap::get(unsigned ID, - SmallVectorImpl<MDNode *> &Result) const { - for (const auto &A : Attachments) - if (A.MDKind == ID) - Result.push_back(A.Node); +void Value::setMetadata(StringRef Kind, MDNode *Node) { + if (!Node && !HasMetadata) + return; + setMetadata(getContext().getMDKindID(Kind), Node); } -bool MDGlobalAttachmentMap::erase(unsigned ID) { - auto I = std::remove_if(Attachments.begin(), Attachments.end(), - [ID](const Attachment &A) { return A.MDKind == ID; }); - bool Changed = I != Attachments.end(); - Attachments.erase(I, Attachments.end()); - return Changed; +void Value::addMetadata(unsigned KindID, MDNode &MD) { + assert(isa<Instruction>(this) || isa<GlobalObject>(this)); + if (!HasMetadata) + HasMetadata = true; + getContext().pImpl->ValueMetadata[this].insert(KindID, MD); } -void MDGlobalAttachmentMap::getAll( - SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const { - for (const auto &A : Attachments) - Result.emplace_back(A.MDKind, A.Node); +void Value::addMetadata(StringRef Kind, MDNode &MD) { + addMetadata(getContext().getMDKindID(Kind), MD); +} - // Sort the resulting array so it is stable with respect to metadata IDs. We - // need to preserve the original insertion order though. - llvm::stable_sort(Result, less_first()); +bool Value::eraseMetadata(unsigned KindID) { + // Nothing to unset. + if (!HasMetadata) + return false; + + auto &Store = getContext().pImpl->ValueMetadata[this]; + bool Changed = Store.erase(KindID); + if (Store.empty()) + clearMetadata(); + return Changed; +} + +void Value::clearMetadata() { + if (!HasMetadata) + return; + assert(getContext().pImpl->ValueMetadata.count(this) && + "bit out of sync with hash table"); + getContext().pImpl->ValueMetadata.erase(this); + HasMetadata = false; } void Instruction::setMetadata(StringRef Kind, MDNode *Node) { @@ -1195,29 +1289,28 @@ MDNode *Instruction::getMetadataImpl(StringRef Kind) const { } void Instruction::dropUnknownNonDebugMetadata(ArrayRef<unsigned> KnownIDs) { - if (!hasMetadataHashEntry()) + if (!Value::hasMetadata()) return; // Nothing to remove! - auto &InstructionMetadata = getContext().pImpl->InstructionMetadata; - - SmallSet<unsigned, 4> KnownSet; - KnownSet.insert(KnownIDs.begin(), KnownIDs.end()); - if (KnownSet.empty()) { + if (KnownIDs.empty()) { // Just drop our entry at the store. - InstructionMetadata.erase(this); - setHasMetadataHashEntry(false); + clearMetadata(); return; } - auto &Info = InstructionMetadata[this]; - Info.remove_if([&KnownSet](const std::pair<unsigned, TrackingMDNodeRef> &I) { - return !KnownSet.count(I.first); + SmallSet<unsigned, 4> KnownSet; + KnownSet.insert(KnownIDs.begin(), KnownIDs.end()); + + auto &MetadataStore = getContext().pImpl->ValueMetadata; + auto &Info = MetadataStore[this]; + assert(!Info.empty() && "bit out of sync with hash table"); + Info.remove_if([&KnownSet](const MDAttachments::Attachment &I) { + return !KnownSet.count(I.MDKind); }); if (Info.empty()) { // Drop our entry at the store. - InstructionMetadata.erase(this); - setHasMetadataHashEntry(false); + clearMetadata(); } } @@ -1231,33 +1324,28 @@ void Instruction::setMetadata(unsigned KindID, MDNode *Node) { return; } - // Handle the case when we're adding/updating metadata on an instruction. - if (Node) { - auto &Info = getContext().pImpl->InstructionMetadata[this]; - assert(!Info.empty() == hasMetadataHashEntry() && - "HasMetadata bit is wonked"); - if (Info.empty()) - setHasMetadataHashEntry(true); - Info.set(KindID, *Node); - return; - } + Value::setMetadata(KindID, Node); +} - // Otherwise, we're removing metadata from an instruction. - assert((hasMetadataHashEntry() == - (getContext().pImpl->InstructionMetadata.count(this) > 0)) && - "HasMetadata bit out of date!"); - if (!hasMetadataHashEntry()) - return; // Nothing to remove! - auto &Info = getContext().pImpl->InstructionMetadata[this]; +void Instruction::addAnnotationMetadata(StringRef Name) { + MDBuilder MDB(getContext()); - // Handle removal of an existing value. - Info.erase(KindID); - - if (!Info.empty()) - return; + auto *Existing = getMetadata(LLVMContext::MD_annotation); + SmallVector<Metadata *, 4> Names; + bool AppendName = true; + if (Existing) { + auto *Tuple = cast<MDTuple>(Existing); + for (auto &N : Tuple->operands()) { + if (cast<MDString>(N.get())->getString() == Name) + AppendName = false; + Names.push_back(N.get()); + } + } + if (AppendName) + Names.push_back(MDB.createString(Name)); - getContext().pImpl->InstructionMetadata.erase(this); - setHasMetadataHashEntry(false); + MDNode *MD = MDTuple::get(getContext(), Names); + setMetadata(LLVMContext::MD_annotation, MD); } void Instruction::setAAMetadata(const AAMDNodes &N) { @@ -1271,13 +1359,7 @@ MDNode *Instruction::getMetadataImpl(unsigned KindID) const { // Handle 'dbg' as a special case since it is not stored in the hash table. if (KindID == LLVMContext::MD_dbg) return DbgLoc.getAsMDNode(); - - if (!hasMetadataHashEntry()) - return nullptr; - auto &Info = getContext().pImpl->InstructionMetadata[this]; - assert(!Info.empty() && "bit out of sync with hash table"); - - return Info.lookup(KindID); + return Value::getMetadata(KindID); } void Instruction::getAllMetadataImpl( @@ -1288,27 +1370,8 @@ void Instruction::getAllMetadataImpl( if (DbgLoc) { Result.push_back( std::make_pair((unsigned)LLVMContext::MD_dbg, DbgLoc.getAsMDNode())); - if (!hasMetadataHashEntry()) - return; } - - assert(hasMetadataHashEntry() && - getContext().pImpl->InstructionMetadata.count(this) && - "Shouldn't have called this"); - const auto &Info = getContext().pImpl->InstructionMetadata.find(this)->second; - assert(!Info.empty() && "Shouldn't have called this"); - Info.getAll(Result); -} - -void Instruction::getAllMetadataOtherThanDebugLocImpl( - SmallVectorImpl<std::pair<unsigned, MDNode *>> &Result) const { - Result.clear(); - assert(hasMetadataHashEntry() && - getContext().pImpl->InstructionMetadata.count(this) && - "Shouldn't have called this"); - const auto &Info = getContext().pImpl->InstructionMetadata.find(this)->second; - assert(!Info.empty() && "Shouldn't have called this"); - Info.getAll(Result); + Value::getAllMetadata(Result); } bool Instruction::extractProfMetadata(uint64_t &TrueVal, @@ -1372,84 +1435,6 @@ bool Instruction::extractProfTotalWeight(uint64_t &TotalVal) const { return false; } -void Instruction::clearMetadataHashEntries() { - assert(hasMetadataHashEntry() && "Caller should check"); - getContext().pImpl->InstructionMetadata.erase(this); - setHasMetadataHashEntry(false); -} - -void GlobalObject::getMetadata(unsigned KindID, - SmallVectorImpl<MDNode *> &MDs) const { - if (hasMetadata()) - getContext().pImpl->GlobalObjectMetadata[this].get(KindID, MDs); -} - -void GlobalObject::getMetadata(StringRef Kind, - SmallVectorImpl<MDNode *> &MDs) const { - if (hasMetadata()) - getMetadata(getContext().getMDKindID(Kind), MDs); -} - -void GlobalObject::addMetadata(unsigned KindID, MDNode &MD) { - if (!hasMetadata()) - setHasMetadataHashEntry(true); - - getContext().pImpl->GlobalObjectMetadata[this].insert(KindID, MD); -} - -void GlobalObject::addMetadata(StringRef Kind, MDNode &MD) { - addMetadata(getContext().getMDKindID(Kind), MD); -} - -bool GlobalObject::eraseMetadata(unsigned KindID) { - // Nothing to unset. - if (!hasMetadata()) - return false; - - auto &Store = getContext().pImpl->GlobalObjectMetadata[this]; - bool Changed = Store.erase(KindID); - if (Store.empty()) - clearMetadata(); - return Changed; -} - -void GlobalObject::getAllMetadata( - SmallVectorImpl<std::pair<unsigned, MDNode *>> &MDs) const { - MDs.clear(); - - if (!hasMetadata()) - return; - - getContext().pImpl->GlobalObjectMetadata[this].getAll(MDs); -} - -void GlobalObject::clearMetadata() { - if (!hasMetadata()) - return; - getContext().pImpl->GlobalObjectMetadata.erase(this); - setHasMetadataHashEntry(false); -} - -void GlobalObject::setMetadata(unsigned KindID, MDNode *N) { - eraseMetadata(KindID); - if (N) - addMetadata(KindID, *N); -} - -void GlobalObject::setMetadata(StringRef Kind, MDNode *N) { - setMetadata(getContext().getMDKindID(Kind), N); -} - -MDNode *GlobalObject::getMetadata(unsigned KindID) const { - if (hasMetadata()) - return getContext().pImpl->GlobalObjectMetadata[this].lookup(KindID); - return nullptr; -} - -MDNode *GlobalObject::getMetadata(StringRef Kind) const { - return getMetadata(getContext().getMDKindID(Kind)); -} - void GlobalObject::copyMetadata(const GlobalObject *Other, unsigned Offset) { SmallVector<std::pair<unsigned, MDNode *>, 8> MDs; Other->getAllMetadata(MDs); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 3ea181a9b48d..b4f10e2e2d23 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -582,7 +582,7 @@ void Module::setProfileSummary(Metadata *M, ProfileSummary::Kind Kind) { setModuleFlag(ModFlagBehavior::Error, "ProfileSummary", M); } -Metadata *Module::getProfileSummary(bool IsCS) { +Metadata *Module::getProfileSummary(bool IsCS) const { return (IsCS ? getModuleFlag("CSProfileSummary") : getModuleFlag("ProfileSummary")); } @@ -601,13 +601,6 @@ void Module::setSemanticInterposition(bool SI) { addModuleFlag(ModFlagBehavior::Error, "SemanticInterposition", SI); } -bool Module::noSemanticInterposition() const { - // Conservatively require an explicit zero value for now. - Metadata *MF = getModuleFlag("SemanticInterposition"); - auto *Val = cast_or_null<ConstantAsMetadata>(MF); - return Val && cast<ConstantInt>(Val->getValue())->getZExtValue() == 0; -} - void Module::setOwnedMemoryBuffer(std::unique_ptr<MemoryBuffer> MB) { OwnedMemoryBuffer = std::move(MB); } diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp index 91612eafada7..5d21ca759f35 100644 --- a/llvm/lib/IR/ModuleSummaryIndex.cpp +++ b/llvm/lib/IR/ModuleSummaryIndex.cpp @@ -163,7 +163,9 @@ bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { return false; } -static void propagateAttributesToRefs(GlobalValueSummary *S) { +static void +propagateAttributesToRefs(GlobalValueSummary *S, + DenseSet<ValueInfo> &MarkedNonReadWriteOnly) { // If reference is not readonly or writeonly then referenced summary is not // read/writeonly either. Note that: // - All references from GlobalVarSummary are conservatively considered as @@ -174,6 +176,11 @@ static void propagateAttributesToRefs(GlobalValueSummary *S) { // for them. for (auto &VI : S->refs()) { assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S)); + if (!VI.getAccessSpecifier()) { + if (!MarkedNonReadWriteOnly.insert(VI).second) + continue; + } else if (MarkedNonReadWriteOnly.contains(VI)) + continue; for (auto &Ref : VI.getSummaryList()) // If references to alias is not read/writeonly then aliasee // is not read/writeonly @@ -216,11 +223,24 @@ void ModuleSummaryIndex::propagateAttributes( const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { if (!PropagateAttrs) return; + DenseSet<ValueInfo> MarkedNonReadWriteOnly; for (auto &P : *this) for (auto &S : P.second.SummaryList) { - if (!isGlobalValueLive(S.get())) + if (!isGlobalValueLive(S.get())) { + // computeDeadSymbols should have marked all copies live. Note that + // it is possible that there is a GUID collision between internal + // symbols with the same name in different files of the same name but + // not enough distinguishing path. Because computeDeadSymbols should + // conservatively mark all copies live we can assert here that all are + // dead if any copy is dead. + assert(llvm::none_of( + P.second.SummaryList, + [&](const std::unique_ptr<GlobalValueSummary> &Summary) { + return isGlobalValueLive(Summary.get()); + })); // We don't examine references from dead objects - continue; + break; + } // Global variable can't be marked read/writeonly if it is not eligible // to import since we need to ensure that all external references get @@ -240,7 +260,7 @@ void ModuleSummaryIndex::propagateAttributes( GVS->setReadOnly(false); GVS->setWriteOnly(false); } - propagateAttributesToRefs(S.get()); + propagateAttributesToRefs(S.get(), MarkedNonReadWriteOnly); } setWithAttributePropagation(); if (llvm::AreStatisticsEnabled()) diff --git a/llvm/lib/IR/OptBisect.cpp b/llvm/lib/IR/OptBisect.cpp index 3104b90f3070..dc85e1316d48 100644 --- a/llvm/lib/IR/OptBisect.cpp +++ b/llvm/lib/IR/OptBisect.cpp @@ -54,3 +54,5 @@ bool OptBisect::checkPass(const StringRef PassName, printPassMessage(PassName, CurBisectNum, TargetDesc, ShouldRun); return ShouldRun; } + +ManagedStatic<OptBisect> llvm::OptBisector; diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp index a815da2bdc51..755ea57c63fd 100644 --- a/llvm/lib/IR/Pass.cpp +++ b/llvm/lib/IR/Pass.cpp @@ -62,7 +62,7 @@ bool ModulePass::skipModule(Module &M) const { } bool Pass::mustPreserveAnalysisID(char &AID) const { - return Resolver->getAnalysisIfAvailable(&AID, true) != nullptr; + return Resolver->getAnalysisIfAvailable(&AID) != nullptr; } // dumpPassStructure - Implement the -debug-pass=Structure option @@ -259,22 +259,23 @@ void AnalysisUsage::setPreservesCFG() { AnalysisUsage &AnalysisUsage::addPreserved(StringRef Arg) { const PassInfo *PI = Pass::lookupPassInfo(Arg); // If the pass exists, preserve it. Otherwise silently do nothing. - if (PI) Preserved.push_back(PI->getTypeInfo()); + if (PI) + pushUnique(Preserved, PI->getTypeInfo()); return *this; } AnalysisUsage &AnalysisUsage::addRequiredID(const void *ID) { - Required.push_back(ID); + pushUnique(Required, ID); return *this; } AnalysisUsage &AnalysisUsage::addRequiredID(char &ID) { - Required.push_back(&ID); + pushUnique(Required, &ID); return *this; } AnalysisUsage &AnalysisUsage::addRequiredTransitiveID(char &ID) { - Required.push_back(&ID); - RequiredTransitive.push_back(&ID); + pushUnique(Required, &ID); + pushUnique(RequiredTransitive, &ID); return *this; } diff --git a/llvm/lib/IR/PassInstrumentation.cpp b/llvm/lib/IR/PassInstrumentation.cpp index 49cc6ec04d90..56a36db21e28 100644 --- a/llvm/lib/IR/PassInstrumentation.cpp +++ b/llvm/lib/IR/PassInstrumentation.cpp @@ -12,10 +12,29 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/PassInstrumentation.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/PassManager.h" namespace llvm { +void PassInstrumentationCallbacks::addClassToPassName(StringRef ClassName, + StringRef PassName) { + ClassToPassName[ClassName] = PassName.str(); +} + +StringRef +PassInstrumentationCallbacks::getPassNameForClassName(StringRef ClassName) { + return ClassToPassName[ClassName]; +} + AnalysisKey PassInstrumentationAnalysis::Key; +bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials) { + size_t Pos = PassID.find('<'); + StringRef Prefix = PassID; + if (Pos != StringRef::npos) + Prefix = PassID.substr(0, Pos); + return any_of(Specials, [Prefix](StringRef S) { return Prefix.endswith(S); }); +} + } // namespace llvm diff --git a/llvm/lib/IR/PassManager.cpp b/llvm/lib/IR/PassManager.cpp index 624827ff8cd9..4cf7ab2a602b 100644 --- a/llvm/lib/IR/PassManager.cpp +++ b/llvm/lib/IR/PassManager.cpp @@ -91,6 +91,54 @@ bool FunctionAnalysisManagerModuleProxy::Result::invalidate( } } // namespace llvm +PreservedAnalyses ModuleToFunctionPassAdaptor::run(Module &M, + ModuleAnalysisManager &AM) { + FunctionAnalysisManager &FAM = + AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); + + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M); + + PreservedAnalyses PA = PreservedAnalyses::all(); + for (Function &F : M) { + if (F.isDeclaration()) + continue; + + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass<Function>(*Pass, F)) + continue; + + PreservedAnalyses PassPA; + { + TimeTraceScope TimeScope(Pass->name(), F.getName()); + PassPA = Pass->run(F, FAM); + } + + PI.runAfterPass(*Pass, F, PassPA); + + // We know that the function pass couldn't have invalidated any other + // function's analyses (that's the contract of a function pass), so + // directly handle the function analysis manager's invalidation here. + FAM.invalidate(F, PassPA); + + // Then intersect the preserved set so that invalidation of module + // analyses will eventually occur when the module pass completes. + PA.intersect(std::move(PassPA)); + } + + // The FunctionAnalysisManagerModuleProxy is preserved because (we assume) + // the function passes we ran didn't add or remove any functions. + // + // We also preserve all analyses on Functions, because we did all the + // invalidation we needed to do above. + PA.preserveSet<AllAnalysesOn<Function>>(); + PA.preserve<FunctionAnalysisManagerModuleProxy>(); + return PA; +} + AnalysisSetKey CFGAnalyses::SetKey; AnalysisSetKey PreservedAnalyses::AllAnalysesKey; diff --git a/llvm/lib/IR/PassRegistry.cpp b/llvm/lib/IR/PassRegistry.cpp index 0572c4fe5237..94f607afec47 100644 --- a/llvm/lib/IR/PassRegistry.cpp +++ b/llvm/lib/IR/PassRegistry.cpp @@ -40,14 +40,12 @@ PassRegistry::~PassRegistry() = default; const PassInfo *PassRegistry::getPassInfo(const void *TI) const { sys::SmartScopedReader<true> Guard(Lock); - MapType::const_iterator I = PassInfoMap.find(TI); - return I != PassInfoMap.end() ? I->second : nullptr; + return PassInfoMap.lookup(TI); } const PassInfo *PassRegistry::getPassInfo(StringRef Arg) const { sys::SmartScopedReader<true> Guard(Lock); - StringMapType::const_iterator I = PassInfoStringMap.find(Arg); - return I != PassInfoStringMap.end() ? I->second : nullptr; + return PassInfoStringMap.lookup(Arg); } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/PassTimingInfo.cpp b/llvm/lib/IR/PassTimingInfo.cpp index 25275e5733ac..d0c1517f480b 100644 --- a/llvm/lib/IR/PassTimingInfo.cpp +++ b/llvm/lib/IR/PassTimingInfo.cpp @@ -16,9 +16,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/PassTimingInfo.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/PassInstrumentation.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" @@ -26,9 +24,8 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" -#include "llvm/Support/Timer.h" +#include "llvm/Support/TypeName.h" #include "llvm/Support/raw_ostream.h" -#include <memory> #include <string> using namespace llvm; @@ -38,11 +35,17 @@ using namespace llvm; namespace llvm { bool TimePassesIsEnabled = false; +bool TimePassesPerRun = false; static cl::opt<bool, true> EnableTiming( "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden, cl::desc("Time each pass, printing elapsed time for each on exit")); +static cl::opt<bool, true> EnableTimingPerRun( + "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden, + cl::desc("Time each pass run, printing elapsed time for each run on exit"), + cl::callback([](const bool &) { TimePassesIsEnabled = true; })); + namespace { namespace legacy { @@ -168,6 +171,13 @@ void reportAndResetTimings(raw_ostream *OutStream) { /// Returns the timer for the specified pass invocation of \p PassID. /// Each time it creates a new timer. Timer &TimePassesHandler::getPassTimer(StringRef PassID) { + if (!PerRun) { + TimerVector &Timers = TimingData[PassID]; + if (Timers.size() == 0) + Timers.emplace_back(new Timer(PassID, PassID, TG)); + return *Timers.front(); + } + // Take a vector of Timers created for this \p PassID and append // one more timer to it. TimerVector &Timers = TimingData[PassID]; @@ -182,8 +192,12 @@ Timer &TimePassesHandler::getPassTimer(StringRef PassID) { return *T; } -TimePassesHandler::TimePassesHandler(bool Enabled) - : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {} +TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun) + : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled), + PerRun(PerRun) {} + +TimePassesHandler::TimePassesHandler() + : TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {} void TimePassesHandler::setOutStream(raw_ostream &Out) { OutStream = &Out; @@ -234,30 +248,20 @@ void TimePassesHandler::stopTimer(StringRef PassID) { MyTimer->stopTimer(); } -static bool matchPassManager(StringRef PassID) { - size_t prefix_pos = PassID.find('<'); - if (prefix_pos == StringRef::npos) - return false; - StringRef Prefix = PassID.substr(0, prefix_pos); - return Prefix.endswith("PassManager") || Prefix.endswith("PassAdaptor") || - Prefix.endswith("AnalysisManagerProxy"); -} - -bool TimePassesHandler::runBeforePass(StringRef PassID) { - if (matchPassManager(PassID)) - return true; +void TimePassesHandler::runBeforePass(StringRef PassID) { + if (isSpecialPass(PassID, + {"PassManager", "PassAdaptor", "AnalysisManagerProxy"})) + return; startTimer(PassID); LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID << ")\n"); LLVM_DEBUG(dump()); - - // we are not going to skip this pass, thus return true. - return true; } void TimePassesHandler::runAfterPass(StringRef PassID) { - if (matchPassManager(PassID)) + if (isSpecialPass(PassID, + {"PassManager", "PassAdaptor", "AnalysisManagerProxy"})) return; stopTimer(PassID); @@ -270,12 +274,16 @@ void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) { if (!Enabled) return; - PIC.registerBeforePassCallback( - [this](StringRef P, Any) { return this->runBeforePass(P); }); + PIC.registerBeforeNonSkippedPassCallback( + [this](StringRef P, Any) { this->runBeforePass(P); }); PIC.registerAfterPassCallback( - [this](StringRef P, Any) { this->runAfterPass(P); }); + [this](StringRef P, Any, const PreservedAnalyses &) { + this->runAfterPass(P); + }); PIC.registerAfterPassInvalidatedCallback( - [this](StringRef P) { this->runAfterPass(P); }); + [this](StringRef P, const PreservedAnalyses &) { + this->runAfterPass(P); + }); PIC.registerBeforeAnalysisCallback( [this](StringRef P, Any) { this->runBeforePass(P); }); PIC.registerAfterAnalysisCallback( diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp new file mode 100644 index 000000000000..83b8c93e766f --- /dev/null +++ b/llvm/lib/IR/PrintPasses.cpp @@ -0,0 +1,88 @@ +//===- PrintPasses.cpp ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/PrintPasses.h" +#include "llvm/Support/CommandLine.h" +#include <unordered_set> + +using namespace llvm; + +// Print IR out before/after specified passes. +static cl::list<std::string> + PrintBefore("print-before", + llvm::cl::desc("Print IR before specified passes"), + cl::CommaSeparated, cl::Hidden); + +static cl::list<std::string> + PrintAfter("print-after", llvm::cl::desc("Print IR after specified passes"), + cl::CommaSeparated, cl::Hidden); + +static cl::opt<bool> PrintBeforeAll("print-before-all", + llvm::cl::desc("Print IR before each pass"), + cl::init(false), cl::Hidden); +static cl::opt<bool> PrintAfterAll("print-after-all", + llvm::cl::desc("Print IR after each pass"), + cl::init(false), cl::Hidden); + +static cl::opt<bool> + PrintModuleScope("print-module-scope", + cl::desc("When printing IR for print-[before|after]{-all} " + "always print a module IR"), + cl::init(false), cl::Hidden); + +static cl::list<std::string> + PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), + cl::desc("Only print IR for functions whose name " + "match this for all print-[before|after][-all] " + "options"), + cl::CommaSeparated, cl::Hidden); + +/// This is a helper to determine whether to print IR before or +/// after a pass. + +bool llvm::shouldPrintBeforeSomePass() { + return PrintBeforeAll || !PrintBefore.empty(); +} + +bool llvm::shouldPrintAfterSomePass() { + return PrintAfterAll || !PrintAfter.empty(); +} + +static bool shouldPrintBeforeOrAfterPass(StringRef PassID, + ArrayRef<std::string> PassesToPrint) { + return llvm::is_contained(PassesToPrint, PassID); +} + +bool llvm::shouldPrintBeforeAll() { return PrintBeforeAll; } + +bool llvm::shouldPrintAfterAll() { return PrintAfterAll; } + +bool llvm::shouldPrintBeforePass(StringRef PassID) { + return PrintBeforeAll || shouldPrintBeforeOrAfterPass(PassID, PrintBefore); +} + +bool llvm::shouldPrintAfterPass(StringRef PassID) { + return PrintAfterAll || shouldPrintBeforeOrAfterPass(PassID, PrintAfter); +} + +std::vector<std::string> llvm::printBeforePasses() { + return std::vector<std::string>(PrintBefore); +} + +std::vector<std::string> llvm::printAfterPasses() { + return std::vector<std::string>(PrintAfter); +} + +bool llvm::forcePrintModuleIR() { return PrintModuleScope; } + +bool llvm::isFunctionInPrintList(StringRef FunctionName) { + static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(), + PrintFuncsList.end()); + return PrintFuncNames.empty() || + PrintFuncNames.count(std::string(FunctionName)); +} diff --git a/llvm/lib/IR/ProfileSummary.cpp b/llvm/lib/IR/ProfileSummary.cpp index ac6bcd9fe3af..453a278a7f3f 100644 --- a/llvm/lib/IR/ProfileSummary.cpp +++ b/llvm/lib/IR/ProfileSummary.cpp @@ -259,7 +259,7 @@ void ProfileSummary::printSummary(raw_ostream &OS) { void ProfileSummary::printDetailedSummary(raw_ostream &OS) { OS << "Detailed summary:\n"; - for (auto Entry : DetailedSummary) { + for (const auto &Entry : DetailedSummary) { OS << Entry.NumCounts << " blocks with count >= " << Entry.MinCount << " account for " << format("%0.6g", (float)Entry.Cutoff / Scale * 100) diff --git a/llvm/lib/IR/PseudoProbe.cpp b/llvm/lib/IR/PseudoProbe.cpp new file mode 100644 index 000000000000..804214f06e7a --- /dev/null +++ b/llvm/lib/IR/PseudoProbe.cpp @@ -0,0 +1,58 @@ +//===- PseudoProbe.cpp - Pseudo Probe Helpers -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the helpers to manipulate pseudo probe IR intrinsic +// calls. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/PseudoProbe.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" + +using namespace llvm; + +namespace llvm { + +Optional<PseudoProbe> extractProbeFromDiscriminator(const Instruction &Inst) { + assert(isa<CallBase>(&Inst) && !isa<IntrinsicInst>(&Inst) && + "Only call instructions should have pseudo probe encodes as their " + "Dwarf discriminators"); + if (const DebugLoc &DLoc = Inst.getDebugLoc()) { + const DILocation *DIL = DLoc; + auto Discriminator = DIL->getDiscriminator(); + if (DILocation::isPseudoProbeDiscriminator(Discriminator)) { + PseudoProbe Probe; + Probe.Id = + PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator); + Probe.Type = + PseudoProbeDwarfDiscriminator::extractProbeType(Discriminator); + Probe.Attr = + PseudoProbeDwarfDiscriminator::extractProbeAttributes(Discriminator); + return Probe; + } + } + return None; +} + +Optional<PseudoProbe> extractProbe(const Instruction &Inst) { + if (const auto *II = dyn_cast<PseudoProbeInst>(&Inst)) { + PseudoProbe Probe; + Probe.Id = II->getIndex()->getZExtValue(); + Probe.Type = (uint32_t)PseudoProbeType::Block; + Probe.Attr = II->getAttributes()->getZExtValue(); + return Probe; + } + + if (isa<CallBase>(&Inst) && !isa<IntrinsicInst>(&Inst)) + return extractProbeFromDiscriminator(Inst); + + return None; +} +} // namespace llvm diff --git a/llvm/lib/IR/ReplaceConstant.cpp b/llvm/lib/IR/ReplaceConstant.cpp new file mode 100644 index 000000000000..7efa525d427e --- /dev/null +++ b/llvm/lib/IR/ReplaceConstant.cpp @@ -0,0 +1,70 @@ +//===- ReplaceConstant.cpp - Replace LLVM constant expression--------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a utility function for replacing LLVM constant +// expressions by instructions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ReplaceConstant.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/NoFolder.h" + +namespace llvm { +// Replace a constant expression by instructions with equivalent operations at +// a specified location. +Instruction *createReplacementInstr(ConstantExpr *CE, Instruction *Instr) { + IRBuilder<NoFolder> Builder(Instr); + unsigned OpCode = CE->getOpcode(); + switch (OpCode) { + case Instruction::GetElementPtr: { + SmallVector<Value *, 4> CEOpVec(CE->operands()); + ArrayRef<Value *> CEOps(CEOpVec); + return dyn_cast<Instruction>( + Builder.CreateInBoundsGEP(cast<GEPOperator>(CE)->getSourceElementType(), + CEOps[0], CEOps.slice(1))); + } + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::FDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::FRem: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + return dyn_cast<Instruction>( + Builder.CreateBinOp((Instruction::BinaryOps)OpCode, CE->getOperand(0), + CE->getOperand(1), CE->getName())); + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::PtrToInt: + case Instruction::IntToPtr: + case Instruction::BitCast: + return dyn_cast<Instruction>( + Builder.CreateCast((Instruction::CastOps)OpCode, CE->getOperand(0), + CE->getType(), CE->getName())); + default: + llvm_unreachable("Unhandled constant expression!\n"); + } +} +} // namespace llvm diff --git a/llvm/lib/IR/SafepointIRVerifier.cpp b/llvm/lib/IR/SafepointIRVerifier.cpp index 6bf7caa50a12..8ed31b6668e0 100644 --- a/llvm/lib/IR/SafepointIRVerifier.cpp +++ b/llvm/lib/IR/SafepointIRVerifier.cpp @@ -561,8 +561,7 @@ GCPtrTracker::GCPtrTracker(const Function &F, const DominatorTree &DT, } BasicBlockState *GCPtrTracker::getBasicBlockState(const BasicBlock *BB) { - auto it = BlockMap.find(BB); - return it != BlockMap.end() ? it->second : nullptr; + return BlockMap.lookup(BB); } const BasicBlockState *GCPtrTracker::getBasicBlockState( diff --git a/llvm/lib/IR/StructuralHash.cpp b/llvm/lib/IR/StructuralHash.cpp new file mode 100644 index 000000000000..5a6e07451326 --- /dev/null +++ b/llvm/lib/IR/StructuralHash.cpp @@ -0,0 +1,84 @@ +//===-- StructuralHash.cpp - IR Hash for expensive checks -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// + +#ifdef EXPENSIVE_CHECKS + +#include "llvm/IR/StructuralHash.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +namespace { +namespace details { + +// Basic hashing mechanism to detect structural change to the IR, used to verify +// pass return status consistency with actual change. Loosely copied from +// llvm/lib/Transforms/Utils/FunctionComparator.cpp + +class StructuralHash { + uint64_t Hash = 0x6acaa36bef8325c5ULL; + + void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); } + +public: + StructuralHash() = default; + + void update(const Function &F) { + if (F.empty()) + return; + + update(F.isVarArg()); + update(F.arg_size()); + + SmallVector<const BasicBlock *, 8> BBs; + SmallPtrSet<const BasicBlock *, 16> VisitedBBs; + + BBs.push_back(&F.getEntryBlock()); + VisitedBBs.insert(BBs[0]); + while (!BBs.empty()) { + const BasicBlock *BB = BBs.pop_back_val(); + update(45798); // Block header + for (auto &Inst : *BB) + update(Inst.getOpcode()); + + const Instruction *Term = BB->getTerminator(); + for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) { + if (!VisitedBBs.insert(Term->getSuccessor(i)).second) + continue; + BBs.push_back(Term->getSuccessor(i)); + } + } + } + + void update(const Module &M) { + for (const Function &F : M) + update(F); + } + + uint64_t getHash() const { return Hash; } +}; + +} // namespace details + +} // namespace + +uint64_t llvm::StructuralHash(const Function &F) { + details::StructuralHash H; + H.update(F); + return H.getHash(); +} + +uint64_t llvm::StructuralHash(const Module &M) { + details::StructuralHash H; + H.update(M); + return H.getHash(); +} + +#endif diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index d869a6e07cca..bade7dc325f4 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -49,6 +49,7 @@ Type *Type::getPrimitiveType(LLVMContext &C, TypeID IDNumber) { case LabelTyID : return getLabelTy(C); case MetadataTyID : return getMetadataTy(C); case X86_MMXTyID : return getX86_MMXTy(C); + case X86_AMXTyID : return getX86_AMXTy(C); case TokenTyID : return getTokenTy(C); default: return nullptr; @@ -81,6 +82,14 @@ bool Type::canLosslesslyBitCastTo(Type *Ty) const { Ty->getPrimitiveSizeInBits().getFixedSize() == 64) return true; + // 8192-bit fixed width vector types can be losslessly converted to x86amx. + if (((isa<FixedVectorType>(this)) && Ty->isX86_AMXTy()) && + getPrimitiveSizeInBits().getFixedSize() == 8192) + return true; + if ((isX86_AMXTy() && isa<FixedVectorType>(Ty)) && + Ty->getPrimitiveSizeInBits().getFixedSize() == 8192) + return true; + // At this point we have only various mismatches of the first class types // remaining and ptr->ptr. Just select the lossless conversions. Everything // else is not lossless. Conservatively assume we can't losslessly convert @@ -120,6 +129,7 @@ TypeSize Type::getPrimitiveSizeInBits() const { case Type::FP128TyID: return TypeSize::Fixed(128); case Type::PPC_FP128TyID: return TypeSize::Fixed(128); case Type::X86_MMXTyID: return TypeSize::Fixed(64); + case Type::X86_AMXTyID: return TypeSize::Fixed(8192); case Type::IntegerTyID: return TypeSize::Fixed(cast<IntegerType>(this)->getBitWidth()); case Type::FixedVectorTyID: @@ -128,7 +138,7 @@ TypeSize Type::getPrimitiveSizeInBits() const { ElementCount EC = VTy->getElementCount(); TypeSize ETS = VTy->getElementType()->getPrimitiveSizeInBits(); assert(!ETS.isScalable() && "Vector type should have fixed-width elements"); - return {ETS.getFixedSize() * EC.Min, EC.Scalable}; + return {ETS.getFixedSize() * EC.getKnownMinValue(), EC.isScalable()}; } default: return TypeSize::Fixed(0); } @@ -179,6 +189,7 @@ Type *Type::getX86_FP80Ty(LLVMContext &C) { return &C.pImpl->X86_FP80Ty; } Type *Type::getFP128Ty(LLVMContext &C) { return &C.pImpl->FP128Ty; } Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; } Type *Type::getX86_MMXTy(LLVMContext &C) { return &C.pImpl->X86_MMXTy; } +Type *Type::getX86_AMXTy(LLVMContext &C) { return &C.pImpl->X86_AMXTy; } IntegerType *Type::getInt1Ty(LLVMContext &C) { return &C.pImpl->Int1Ty; } IntegerType *Type::getInt8Ty(LLVMContext &C) { return &C.pImpl->Int8Ty; } @@ -223,6 +234,10 @@ PointerType *Type::getX86_MMXPtrTy(LLVMContext &C, unsigned AS) { return getX86_MMXTy(C)->getPointerTo(AS); } +PointerType *Type::getX86_AMXPtrTy(LLVMContext &C, unsigned AS) { + return getX86_AMXTy(C)->getPointerTo(AS); +} + PointerType *Type::getIntNPtrTy(LLVMContext &C, unsigned N, unsigned AS) { return getIntNTy(C, N)->getPointerTo(AS); } @@ -275,11 +290,6 @@ IntegerType *IntegerType::get(LLVMContext &C, unsigned NumBits) { return Entry; } -bool IntegerType::isPowerOf2ByteWidth() const { - unsigned BitWidth = getBitWidth(); - return (BitWidth > 7) && isPowerOf2_32(BitWidth); -} - APInt IntegerType::getMask() const { return APInt::getAllOnesValue(getBitWidth()); } @@ -380,6 +390,18 @@ StructType *StructType::get(LLVMContext &Context, ArrayRef<Type*> ETypes, return ST; } +bool StructType::containsScalableVectorType() const { + for (Type *Ty : elements()) { + if (isa<ScalableVectorType>(Ty)) + return true; + if (auto *STy = dyn_cast<StructType>(Ty)) + if (STy->containsScalableVectorType()) + return true; + } + + return false; +} + void StructType::setBody(ArrayRef<Type*> Elements, bool isPacked) { assert(isOpaque() && "Struct body already set!"); @@ -499,9 +521,14 @@ bool StructType::isSized(SmallPtrSetImpl<Type*> *Visited) const { // Okay, our struct is sized if all of the elements are, but if one of the // elements is opaque, the struct isn't sized *yet*, but may become sized in // the future, so just bail out without caching. - for (element_iterator I = element_begin(), E = element_end(); I != E; ++I) - if (!(*I)->isSized(Visited)) + for (Type *Ty : elements()) { + // If the struct contains a scalable vector type, don't consider it sized. + // This prevents it from being used in loads/stores/allocas/GEPs. + if (isa<ScalableVectorType>(Ty)) + return false; + if (!Ty->isSized(Visited)) return false; + } // Here we cheat a bit and cast away const-ness. The goal is to memoize when // we find a sized type, as types can only move from opaque to sized, not the @@ -521,7 +548,7 @@ StringRef StructType::getName() const { bool StructType::isValidElementType(Type *ElemTy) { return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy() && - !ElemTy->isTokenTy() && !isa<ScalableVectorType>(ElemTy); + !ElemTy->isTokenTy(); } bool StructType::isLayoutIdentical(StructType *Other) const { @@ -533,10 +560,6 @@ bool StructType::isLayoutIdentical(StructType *Other) const { return elements() == Other->elements(); } -StructType *Module::getTypeByName(StringRef Name) const { - return getContext().pImpl->NamedStructTypes.lookup(Name); -} - Type *StructType::getTypeAtIndex(const Value *V) const { unsigned Idx = (unsigned)cast<Constant>(V)->getUniqueInteger().getZExtValue(); assert(indexValid(Idx) && "Invalid structure index!"); @@ -557,6 +580,10 @@ bool StructType::indexValid(const Value *V) const { return CU && CU->getZExtValue() < getNumElements(); } +StructType *StructType::getTypeByName(LLVMContext &C, StringRef Name) { + return C.pImpl->NamedStructTypes.lookup(Name); +} + //===----------------------------------------------------------------------===// // ArrayType Implementation //===----------------------------------------------------------------------===// @@ -598,10 +625,10 @@ VectorType::VectorType(Type *ElType, unsigned EQ, Type::TypeID TID) } VectorType *VectorType::get(Type *ElementType, ElementCount EC) { - if (EC.Scalable) - return ScalableVectorType::get(ElementType, EC.Min); + if (EC.isScalable()) + return ScalableVectorType::get(ElementType, EC.getKnownMinValue()); else - return FixedVectorType::get(ElementType, EC.Min); + return FixedVectorType::get(ElementType, EC.getKnownMinValue()); } bool VectorType::isValidElementType(Type *ElemTy) { @@ -619,7 +646,7 @@ FixedVectorType *FixedVectorType::get(Type *ElementType, unsigned NumElts) { "be an integer, floating point, or " "pointer type."); - ElementCount EC(NumElts, false); + auto EC = ElementCount::getFixed(NumElts); LLVMContextImpl *pImpl = ElementType->getContext().pImpl; VectorType *&Entry = ElementType->getContext() @@ -641,7 +668,7 @@ ScalableVectorType *ScalableVectorType::get(Type *ElementType, "be an integer, floating point, or " "pointer type."); - ElementCount EC(MinNumElts, true); + auto EC = ElementCount::getScalable(MinNumElts); LLVMContextImpl *pImpl = ElementType->getContext().pImpl; VectorType *&Entry = ElementType->getContext() diff --git a/llvm/lib/IR/Use.cpp b/llvm/lib/IR/Use.cpp index dc0716b85372..99049c0232aa 100644 --- a/llvm/lib/IR/Use.cpp +++ b/llvm/lib/IR/Use.cpp @@ -17,24 +17,17 @@ void Use::swap(Use &RHS) { if (Val == RHS.Val) return; - if (Val) - removeFromList(); - - Value *OldVal = Val; - if (RHS.Val) { - RHS.removeFromList(); - Val = RHS.Val; - Val->addUse(*this); - } else { - Val = nullptr; - } - - if (OldVal) { - RHS.Val = OldVal; - RHS.Val->addUse(RHS); - } else { - RHS.Val = nullptr; - } + std::swap(Val, RHS.Val); + std::swap(Next, RHS.Next); + std::swap(Prev, RHS.Prev); + + *Prev = this; + if (Next) + Next->Prev = &Next; + + *RHS.Prev = &RHS; + if (RHS.Next) + RHS.Next->Prev = &RHS.Next; } unsigned Use::getOperandNo() const { diff --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp index 7da592f40127..9105c6fbd230 100644 --- a/llvm/lib/IR/User.cpp +++ b/llvm/lib/IR/User.cpp @@ -29,7 +29,7 @@ void User::replaceUsesOfWith(Value *From, Value *To) { // The side effects of this setOperand call include linking to // "To", adding "this" to the uses list of To, and // most importantly, removing "this" from the use list of "From". - setOperand(i, To); // Fix it now... + setOperand(i, To); } } diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index efb8d53e8964..572f37a32410 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -51,9 +51,9 @@ static inline Type *checkType(Type *Ty) { } Value::Value(Type *ty, unsigned scid) - : VTy(checkType(ty)), UseList(nullptr), SubclassID(scid), - HasValueHandle(0), SubclassOptionalData(0), SubclassData(0), - NumUserOperands(0), IsUsedByMD(false), HasName(false) { + : VTy(checkType(ty)), UseList(nullptr), SubclassID(scid), HasValueHandle(0), + SubclassOptionalData(0), SubclassData(0), NumUserOperands(0), + IsUsedByMD(false), HasName(false), HasMetadata(false) { static_assert(ConstantFirstVal == 0, "!(SubclassID < ConstantFirstVal)"); // FIXME: Why isn't this in the subclass gunk?? // Note, we cannot call isa<CallInst> before the CallInst has been @@ -77,6 +77,10 @@ Value::~Value() { if (isUsedByMetadata()) ValueAsMetadata::handleDeletion(this); + // Remove associated metadata from context. + if (HasMetadata) + clearMetadata(); + #ifndef NDEBUG // Only in -g mode... // Check to make sure that there are no uses of this value that are still // around when the value is destroyed. If there are, then we have a dangling @@ -147,6 +151,14 @@ bool Value::hasNUsesOrMore(unsigned N) const { return hasNItemsOrMore(use_begin(), use_end(), N); } +bool Value::hasOneUser() const { + if (use_empty()) + return false; + if (hasOneUse()) + return true; + return std::equal(++user_begin(), user_end(), user_begin()); +} + static bool isUnDroppableUser(const User *U) { return !U->isDroppable(); } Use *Value::getSingleUndroppableUse() { @@ -175,21 +187,34 @@ void Value::dropDroppableUses( for (Use &U : uses()) if (U.getUser()->isDroppable() && ShouldDrop(&U)) ToBeEdited.push_back(&U); - for (Use *U : ToBeEdited) { - U->removeFromList(); - if (auto *Assume = dyn_cast<IntrinsicInst>(U->getUser())) { - assert(Assume->getIntrinsicID() == Intrinsic::assume); - unsigned OpNo = U->getOperandNo(); - if (OpNo == 0) - Assume->setOperand(0, ConstantInt::getTrue(Assume->getContext())); - else { - Assume->setOperand(OpNo, UndefValue::get(U->get()->getType())); - CallInst::BundleOpInfo &BOI = Assume->getBundleOpInfoForOperand(OpNo); - BOI.Tag = getContext().pImpl->getOrInsertBundleTag("ignore"); - } - } else - llvm_unreachable("unkown droppable use"); + for (Use *U : ToBeEdited) + dropDroppableUse(*U); +} + +void Value::dropDroppableUsesIn(User &Usr) { + assert(Usr.isDroppable() && "Expected a droppable user!"); + for (Use &UsrOp : Usr.operands()) { + if (UsrOp.get() == this) + dropDroppableUse(UsrOp); + } +} + +void Value::dropDroppableUse(Use &U) { + U.removeFromList(); + if (auto *Assume = dyn_cast<IntrinsicInst>(U.getUser())) { + assert(Assume->getIntrinsicID() == Intrinsic::assume); + unsigned OpNo = U.getOperandNo(); + if (OpNo == 0) + U.set(ConstantInt::getTrue(Assume->getContext())); + else { + U.set(UndefValue::get(U.get()->getType())); + CallInst::BundleOpInfo &BOI = Assume->getBundleOpInfoForOperand(OpNo); + BOI.Tag = Assume->getContext().pImpl->getOrInsertBundleTag("ignore"); + } + return; } + + llvm_unreachable("unkown droppable use"); } bool Value::isUsedInBasicBlock(const BasicBlock *BB) const { @@ -405,6 +430,18 @@ void Value::takeName(Value *V) { ST->reinsertValue(this); } +#ifndef NDEBUG +std::string Value::getNameOrAsOperand() const { + if (!getName().empty()) + return std::string(getName()); + + std::string BBName; + raw_string_ostream OS(BBName); + printAsOperand(OS, false); + return OS.str(); +} +#endif + void Value::assertModuleIsMaterializedImpl() const { #ifndef NDEBUG const GlobalValue *GV = dyn_cast<GlobalValue>(this); @@ -691,11 +728,16 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, CanBeNull = false; if (const Argument *A = dyn_cast<Argument>(this)) { DerefBytes = A->getDereferenceableBytes(); - if (DerefBytes == 0 && (A->hasByValAttr() || A->hasStructRetAttr())) { - Type *PT = cast<PointerType>(A->getType())->getElementType(); - if (PT->isSized()) - DerefBytes = DL.getTypeStoreSize(PT).getKnownMinSize(); + if (DerefBytes == 0) { + // Handle byval/byref/inalloca/preallocated arguments + if (Type *ArgMemTy = A->getPointeeInMemoryValueType()) { + if (ArgMemTy->isSized()) { + // FIXME: Why isn't this the type alloc size? + DerefBytes = DL.getTypeStoreSize(ArgMemTy).getKnownMinSize(); + } + } } + if (DerefBytes == 0) { DerefBytes = A->getDereferenceableOrNullBytes(); CanBeNull = true; @@ -783,7 +825,7 @@ Align Value::getPointerAlignment(const DataLayout &DL) const { const MaybeAlign Alignment = A->getParamAlign(); if (!Alignment && A->hasStructRetAttr()) { // An sret parameter has at least the ABI alignment of the return type. - Type *EltTy = cast<PointerType>(A->getType())->getElementType(); + Type *EltTy = A->getParamStructRetType(); if (EltTy->isSized()) return DL.getABITypeAlign(EltTy); } diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 6df1072925f9..100e881c8fa8 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -115,6 +115,11 @@ using namespace llvm; +static cl::opt<bool> VerifyNoAliasScopeDomination( + "verify-noalias-scope-decl-dom", cl::Hidden, cl::init(false), + cl::desc("Ensure that llvm.experimental.noalias.scope.decl for identical " + "scopes are not dominating")); + namespace llvm { struct VerifierSupport { @@ -282,6 +287,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// Whether the current function has a DISubprogram attached to it. bool HasDebugInfo = false; + /// The current source language. + dwarf::SourceLanguage CurrentSourceLang = dwarf::DW_LANG_lo_user; + /// Whether source was present on the first DIFile encountered in each CU. DenseMap<const DICompileUnit *, bool> HasSourceDebugInfo; @@ -310,6 +318,8 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { TBAAVerifier TBAAVerifyHelper; + SmallVector<IntrinsicInst *, 4> NoAliasScopeDecls; + void checkAtomicMemAccessSize(Type *Ty, const Instruction *I); public: @@ -357,6 +367,8 @@ public: LandingPadResultTy = nullptr; SawFrameEscape = false; SiblingFuncletInfo.clear(); + verifyNoAliasScopeDecl(); + NoAliasScopeDecls.clear(); return !Broken; } @@ -424,6 +436,7 @@ private: void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty); void visitDereferenceableMetadata(Instruction &I, MDNode *MD); void visitProfMetadata(Instruction &I, MDNode *MD); + void visitAnnotationMetadata(MDNode *Annotation); template <class Ty> bool isValidMetadataArray(const MDTuple &N); #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N); @@ -501,8 +514,6 @@ private: void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal); void verifySwiftErrorValue(const Value *SwiftErrorVal); void verifyMustTailCall(CallInst &CI); - bool performTypeCheck(Intrinsic::ID ID, Function *F, Type *Ty, int VT, - unsigned ArgNo, std::string &Suffix); bool verifyAttributeCount(AttributeList Attrs, unsigned Params); void verifyAttributeTypes(AttributeSet Attrs, bool IsFunction, const Value *V); @@ -534,6 +545,9 @@ private: /// Verify all-or-nothing property of DIFile source attribute within a CU. void verifySourceDebugInfo(const DICompileUnit &U, const DIFile &F); + + /// Verify the llvm.experimental.noalias.scope.decl declarations + void verifyNoAliasScopeDecl(); }; } // end anonymous namespace @@ -589,7 +603,8 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { Assert(!GV.isDSOLocal(), "GlobalValue with DLLImport Storage is dso_local!", &GV); - Assert((GV.isDeclaration() && GV.hasExternalLinkage()) || + Assert((GV.isDeclaration() && + (GV.hasExternalLinkage() || GV.hasExternalWeakLinkage())) || GV.hasAvailableExternallyLinkage(), "Global is marked as dllimport, but not external", &GV); } @@ -699,12 +714,16 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { } // Scalable vectors cannot be global variables, since we don't know - // the runtime size. If the global is a struct or an array containing - // scalable vectors, that will be caught by the isValidElementType methods - // in StructType or ArrayType instead. + // the runtime size. If the global is an array containing scalable vectors, + // that will be caught by the isValidElementType methods in StructType or + // ArrayType instead. Assert(!isa<ScalableVectorType>(GV.getValueType()), "Globals cannot contain scalable vectors", &GV); + if (auto *STy = dyn_cast<StructType>(GV.getValueType())) + Assert(!STy->containsScalableVectorType(), + "Globals cannot contain scalable vectors", &GV); + if (!GV.hasInitializer()) { visitGlobalValue(GV); return; @@ -894,7 +913,9 @@ void Verifier::visitDIScope(const DIScope &N) { void Verifier::visitDISubrange(const DISubrange &N) { AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); - AssertDI(N.getRawCountNode() || N.getRawUpperBound(), + bool HasAssumedSizedArraySupport = dwarf::isFortran(CurrentSourceLang); + AssertDI(HasAssumedSizedArraySupport || N.getRawCountNode() || + N.getRawUpperBound(), "Subrange must contain count or upperBound", &N); AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(), "Subrange can have any one of count or upperBound", &N); @@ -920,14 +941,43 @@ void Verifier::visitDISubrange(const DISubrange &N) { "Stride must be signed constant or DIVariable or DIExpression", &N); } +void Verifier::visitDIGenericSubrange(const DIGenericSubrange &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_generic_subrange, "invalid tag", &N); + AssertDI(N.getRawCountNode() || N.getRawUpperBound(), + "GenericSubrange must contain count or upperBound", &N); + AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(), + "GenericSubrange can have any one of count or upperBound", &N); + auto *CBound = N.getRawCountNode(); + AssertDI(!CBound || isa<DIVariable>(CBound) || isa<DIExpression>(CBound), + "Count must be signed constant or DIVariable or DIExpression", &N); + auto *LBound = N.getRawLowerBound(); + AssertDI(LBound, "GenericSubrange must contain lowerBound", &N); + AssertDI(isa<DIVariable>(LBound) || isa<DIExpression>(LBound), + "LowerBound must be signed constant or DIVariable or DIExpression", + &N); + auto *UBound = N.getRawUpperBound(); + AssertDI(!UBound || isa<DIVariable>(UBound) || isa<DIExpression>(UBound), + "UpperBound must be signed constant or DIVariable or DIExpression", + &N); + auto *Stride = N.getRawStride(); + AssertDI(Stride, "GenericSubrange must contain stride", &N); + AssertDI(isa<DIVariable>(Stride) || isa<DIExpression>(Stride), + "Stride must be signed constant or DIVariable or DIExpression", &N); +} + void Verifier::visitDIEnumerator(const DIEnumerator &N) { AssertDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N); } void Verifier::visitDIBasicType(const DIBasicType &N) { AssertDI(N.getTag() == dwarf::DW_TAG_base_type || - N.getTag() == dwarf::DW_TAG_unspecified_type, + N.getTag() == dwarf::DW_TAG_unspecified_type || + N.getTag() == dwarf::DW_TAG_string_type, "invalid tag", &N); +} + +void Verifier::visitDIStringType(const DIStringType &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_string_type, "invalid tag", &N); AssertDI(!(N.isBigEndian() && N.isLittleEndian()) , "has conflicting flags", &N); } @@ -1035,6 +1085,21 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { AssertDI(N.getTag() == dwarf::DW_TAG_array_type, "dataLocation can only appear in array type"); } + + if (N.getRawAssociated()) { + AssertDI(N.getTag() == dwarf::DW_TAG_array_type, + "associated can only appear in array type"); + } + + if (N.getRawAllocated()) { + AssertDI(N.getTag() == dwarf::DW_TAG_array_type, + "allocated can only appear in array type"); + } + + if (N.getRawRank()) { + AssertDI(N.getTag() == dwarf::DW_TAG_array_type, + "rank can only appear in array type"); + } } void Verifier::visitDISubroutineType(const DISubroutineType &N) { @@ -1084,6 +1149,8 @@ void Verifier::visitDICompileUnit(const DICompileUnit &N) { AssertDI(!N.getFile()->getFilename().empty(), "invalid filename", &N, N.getFile()); + CurrentSourceLang = (dwarf::SourceLanguage)N.getSourceLanguage(); + verifySourceDebugInfo(N, *N.getFile()); AssertDI((N.getEmissionKind() <= DICompileUnit::LastEmissionKind), @@ -1525,8 +1592,8 @@ void Verifier::visitModuleFlagCGProfileEntry(const MDOperand &MDO) { if (!FuncMDO) return; auto F = dyn_cast<ValueAsMetadata>(FuncMDO); - Assert(F && isa<Function>(F->getValue()), "expected a Function or null", - FuncMDO); + Assert(F && isa<Function>(F->getValue()->stripPointerCasts()), + "expected a Function or null", FuncMDO); }; auto Node = dyn_cast_or_null<MDNode>(MDO); Assert(Node && Node->getNumOperands() == 3, "expected a MDNode triple", MDO); @@ -1544,6 +1611,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::NoReturn: case Attribute::NoSync: case Attribute::WillReturn: + case Attribute::NoCallback: case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: @@ -1572,6 +1640,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::Builtin: case Attribute::NoBuiltin: case Attribute::Cold: + case Attribute::Hot: case Attribute::OptForFuzzing: case Attribute::OptimizeNone: case Attribute::JumpTable: @@ -1585,6 +1654,8 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::Speculatable: case Attribute::StrictFP: case Attribute::NullPointerIsValid: + case Attribute::MustProgress: + case Attribute::NoProfile: return true; default: break; @@ -1652,9 +1723,10 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, AttrCount += Attrs.hasAttribute(Attribute::StructRet) || Attrs.hasAttribute(Attribute::InReg); AttrCount += Attrs.hasAttribute(Attribute::Nest); + AttrCount += Attrs.hasAttribute(Attribute::ByRef); Assert(AttrCount <= 1, "Attributes 'byval', 'inalloca', 'preallocated', 'inreg', 'nest', " - "and 'sret' are incompatible!", + "'byref', and 'sret' are incompatible!", V); Assert(!(Attrs.hasAttribute(Attribute::InAlloca) && @@ -1699,17 +1771,6 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, "'noinline and alwaysinline' are incompatible!", V); - if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) { - Assert(Attrs.getByValType() == cast<PointerType>(Ty)->getElementType(), - "Attribute 'byval' type does not match parameter!", V); - } - - if (Attrs.hasAttribute(Attribute::Preallocated)) { - Assert(Attrs.getPreallocatedType() == - cast<PointerType>(Ty)->getElementType(), - "Attribute 'preallocated' type does not match parameter!", V); - } - AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty); Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs), "Wrong types for attribute: " + @@ -1720,9 +1781,10 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, SmallPtrSet<Type*, 4> Visited; if (!PTy->getElementType()->isSized(&Visited)) { Assert(!Attrs.hasAttribute(Attribute::ByVal) && - !Attrs.hasAttribute(Attribute::InAlloca) && - !Attrs.hasAttribute(Attribute::Preallocated), - "Attributes 'byval', 'inalloca', and 'preallocated' do not " + !Attrs.hasAttribute(Attribute::ByRef) && + !Attrs.hasAttribute(Attribute::InAlloca) && + !Attrs.hasAttribute(Attribute::Preallocated), + "Attributes 'byval', 'byref', 'inalloca', and 'preallocated' do not " "support unsized types!", V); } @@ -1731,10 +1793,28 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, "Attribute 'swifterror' only applies to parameters " "with pointer to pointer type!", V); + + if (Attrs.hasAttribute(Attribute::ByRef)) { + Assert(Attrs.getByRefType() == PTy->getElementType(), + "Attribute 'byref' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) { + Assert(Attrs.getByValType() == PTy->getElementType(), + "Attribute 'byval' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::Preallocated)) { + Assert(Attrs.getPreallocatedType() == PTy->getElementType(), + "Attribute 'preallocated' type does not match parameter!", V); + } } else { Assert(!Attrs.hasAttribute(Attribute::ByVal), "Attribute 'byval' only applies to parameters with pointer type!", V); + Assert(!Attrs.hasAttribute(Attribute::ByRef), + "Attribute 'byref' only applies to parameters with pointer type!", + V); Assert(!Attrs.hasAttribute(Attribute::SwiftError), "Attribute 'swifterror' only applies to parameters " "with pointer type!", @@ -1765,10 +1845,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, !RetAttrs.hasAttribute(Attribute::Returned) && !RetAttrs.hasAttribute(Attribute::InAlloca) && !RetAttrs.hasAttribute(Attribute::Preallocated) && + !RetAttrs.hasAttribute(Attribute::ByRef) && !RetAttrs.hasAttribute(Attribute::SwiftSelf) && !RetAttrs.hasAttribute(Attribute::SwiftError)), - "Attributes 'byval', 'inalloca', 'preallocated', 'nest', 'sret', " - "'nocapture', 'nofree', " + "Attributes 'byval', 'inalloca', 'preallocated', 'byref', " + "'nest', 'sret', 'nocapture', 'nofree', " "'returned', 'swiftself', and 'swifterror' do not apply to return " "values!", V); @@ -2102,39 +2183,22 @@ void Verifier::verifyStatepoint(const CallBase &Call) { Call); const int NumTransitionArgs = cast<ConstantInt>(NumTransitionArgsV)->getZExtValue(); - Assert(NumTransitionArgs >= 0, - "gc.statepoint number of transition arguments must be positive", Call); + Assert(NumTransitionArgs == 0, + "gc.statepoint w/inline transition bundle is deprecated", Call); const int EndTransitionArgsInx = EndCallArgsInx + 1 + NumTransitionArgs; - // We're migrating away from inline operands to operand bundles, enforce - // the either/or property during transition. - if (Call.getOperandBundle(LLVMContext::OB_gc_transition)) { - Assert(NumTransitionArgs == 0, - "can't use both deopt operands and deopt bundle on a statepoint"); - } - const Value *NumDeoptArgsV = Call.getArgOperand(EndTransitionArgsInx + 1); Assert(isa<ConstantInt>(NumDeoptArgsV), "gc.statepoint number of deoptimization arguments " "must be constant integer", Call); const int NumDeoptArgs = cast<ConstantInt>(NumDeoptArgsV)->getZExtValue(); - Assert(NumDeoptArgs >= 0, - "gc.statepoint number of deoptimization arguments " - "must be positive", - Call); + Assert(NumDeoptArgs == 0, + "gc.statepoint w/inline deopt operands is deprecated", Call); - // We're migrating away from inline operands to operand bundles, enforce - // the either/or property during transition. - if (Call.getOperandBundle(LLVMContext::OB_deopt)) { - Assert(NumDeoptArgs == 0, - "can't use both deopt operands and deopt bundle on a statepoint"); - } - - const int ExpectedNumArgs = - 7 + NumCallArgs + NumTransitionArgs + NumDeoptArgs; - Assert(ExpectedNumArgs <= (int)Call.arg_size(), - "gc.statepoint too few arguments according to length fields", Call); + const int ExpectedNumArgs = 7 + NumCallArgs; + Assert(ExpectedNumArgs == (int)Call.arg_size(), + "gc.statepoint too many arguments", Call); // Check that the only uses of this gc.statepoint are gc.result or // gc.relocate calls which are tied to this statepoint and thus part @@ -2280,6 +2344,11 @@ void Verifier::visitFunction(const Function &F) { default: case CallingConv::C: break; + case CallingConv::X86_INTR: { + Assert(F.arg_empty() || Attrs.hasParamAttribute(0, Attribute::ByVal), + "Calling convention parameter requires byval", &F); + break; + } case CallingConv::AMDGPU_KERNEL: case CallingConv::SPIR_KERNEL: Assert(F.getReturnType()->isVoidTy(), @@ -2292,6 +2361,28 @@ void Verifier::visitFunction(const Function &F) { case CallingConv::AMDGPU_CS: Assert(!F.hasStructRetAttr(), "Calling convention does not allow sret", &F); + if (F.getCallingConv() != CallingConv::SPIR_KERNEL) { + const unsigned StackAS = DL.getAllocaAddrSpace(); + unsigned i = 0; + for (const Argument &Arg : F.args()) { + Assert(!Attrs.hasParamAttribute(i, Attribute::ByVal), + "Calling convention disallows byval", &F); + Assert(!Attrs.hasParamAttribute(i, Attribute::Preallocated), + "Calling convention disallows preallocated", &F); + Assert(!Attrs.hasParamAttribute(i, Attribute::InAlloca), + "Calling convention disallows inalloca", &F); + + if (Attrs.hasParamAttribute(i, Attribute::ByRef)) { + // FIXME: Should also disallow LDS and GDS, but we don't have the enum + // value here. + Assert(Arg.getType()->getPointerAddressSpace() != StackAS, + "Calling convention disallows stack byref", &F); + } + + ++i; + } + } + LLVM_FALLTHROUGH; case CallingConv::Fast: case CallingConv::Cold: @@ -2394,6 +2485,10 @@ void Verifier::visitFunction(const Function &F) { "function must have a single !dbg attachment", &F, I.second); AssertDI(isa<DISubprogram>(I.second), "function !dbg attachment must be a subprogram", &F, I.second); + AssertDI(cast<DISubprogram>(I.second)->isDistinct(), + "function definition may only have a distinct !dbg attachment", + &F); + auto *SP = cast<DISubprogram>(I.second); const Function *&AttachedTo = DISubprogramAttachments[SP]; AssertDI(!AttachedTo || AttachedTo == &F, @@ -2488,15 +2583,10 @@ void Verifier::visitBasicBlock(BasicBlock &BB) { // Check constraints that this basic block imposes on all of the PHI nodes in // it. if (isa<PHINode>(BB.front())) { - SmallVector<BasicBlock*, 8> Preds(pred_begin(&BB), pred_end(&BB)); + SmallVector<BasicBlock *, 8> Preds(predecessors(&BB)); SmallVector<std::pair<BasicBlock*, Value*>, 8> Values; llvm::sort(Preds); for (const PHINode &PN : BB.phis()) { - // Ensure that PHI nodes have at least one entry! - Assert(PN.getNumIncomingValues() != 0, - "PHI nodes must have at least one entry. If the block is dead, " - "the PHI should be removed!", - &PN); Assert(PN.getNumIncomingValues() == Preds.size(), "PHINode should have one entry for each predecessor of its " "parent basic block!", @@ -2887,8 +2977,8 @@ void Verifier::visitAddrSpaceCastInst(AddrSpaceCastInst &I) { Assert(SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace(), "AddrSpaceCast must be between different address spaces", &I); if (auto *SrcVTy = dyn_cast<VectorType>(SrcTy)) - Assert(SrcVTy->getNumElements() == - cast<VectorType>(DestTy)->getNumElements(), + Assert(SrcVTy->getElementCount() == + cast<VectorType>(DestTy)->getElementCount(), "AddrSpaceCast vector pointer number of elements mismatch", &I); visitInstruction(I); } @@ -3174,17 +3264,19 @@ static bool isTypeCongruent(Type *L, Type *R) { static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { static const Attribute::AttrKind ABIAttrs[] = { - Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, - Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftError, - Attribute::Preallocated}; + Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, + Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftError, + Attribute::Preallocated, Attribute::ByRef}; AttrBuilder Copy; for (auto AK : ABIAttrs) { if (Attrs.hasParamAttribute(I, AK)) Copy.addAttribute(AK); } - // `align` is ABI-affecting only in combination with `byval`. + + // `align` is ABI-affecting only in combination with `byval` or `byref`. if (Attrs.hasParamAttribute(I, Attribute::Alignment) && - Attrs.hasParamAttribute(I, Attribute::ByVal)) + (Attrs.hasParamAttribute(I, Attribute::ByVal) || + Attrs.hasParamAttribute(I, Attribute::ByRef))) Copy.addAlignmentAttr(Attrs.getParamAlignment(I)); return Copy; } @@ -3420,7 +3512,7 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) { "GEP base pointer is not a vector or a vector of pointers", &GEP); Assert(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP); - SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end()); + SmallVector<Value *, 16> Idxs(GEP.indices()); Assert(all_of( Idxs, [](Value* V) { return V->getType()->isIntOrIntVectorTy(); }), "GEP indexes must be integers", &GEP); @@ -4205,6 +4297,14 @@ void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) { } } +void Verifier::visitAnnotationMetadata(MDNode *Annotation) { + Assert(isa<MDTuple>(Annotation), "annotation must be a tuple"); + Assert(Annotation->getNumOperands() >= 1, + "annotation must have at least one operand"); + for (const MDOperand &Op : Annotation->operands()) + Assert(isa<MDString>(Op.get()), "operands must be strings"); +} + /// verifyInstruction - Verify that an instruction is well formed. /// void Verifier::visitInstruction(Instruction &I) { @@ -4274,7 +4374,7 @@ void Verifier::visitInstruction(Instruction &I) { F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void || F->getIntrinsicID() == Intrinsic::experimental_patchpoint_i64 || F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint || - F->getIntrinsicID() == Intrinsic::wasm_rethrow_in_catch, + F->getIntrinsicID() == Intrinsic::wasm_rethrow, "Cannot invoke an intrinsic other than donothing, patchpoint, " "statepoint, coro_resume or coro_destroy", &I); @@ -4365,6 +4465,9 @@ void Verifier::visitInstruction(Instruction &I) { if (MDNode *MD = I.getMetadata(LLVMContext::MD_prof)) visitProfMetadata(I, MD); + if (MDNode *Annotation = I.getMetadata(LLVMContext::MD_annotation)) + visitAnnotationMetadata(Annotation); + if (MDNode *N = I.getDebugLoc().getAsMDNode()) { AssertDI(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N); visitMDNode(*N, AreDebugLocsAllowed::Yes); @@ -4785,45 +4888,6 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { "gc.relocate: statepoint base index out of bounds", Call); Assert(DerivedIndex < Opt->Inputs.size(), "gc.relocate: statepoint derived index out of bounds", Call); - } else { - Assert(BaseIndex < StatepointCall.arg_size(), - "gc.relocate: statepoint base index out of bounds", Call); - Assert(DerivedIndex < StatepointCall.arg_size(), - "gc.relocate: statepoint derived index out of bounds", Call); - - // Check that BaseIndex and DerivedIndex fall within the 'gc parameters' - // section of the statepoint's argument. - Assert(StatepointCall.arg_size() > 0, - "gc.statepoint: insufficient arguments"); - Assert(isa<ConstantInt>(StatepointCall.getArgOperand(3)), - "gc.statement: number of call arguments must be constant integer"); - const uint64_t NumCallArgs = - cast<ConstantInt>(StatepointCall.getArgOperand(3))->getZExtValue(); - Assert(StatepointCall.arg_size() > NumCallArgs + 5, - "gc.statepoint: mismatch in number of call arguments"); - Assert(isa<ConstantInt>(StatepointCall.getArgOperand(NumCallArgs + 5)), - "gc.statepoint: number of transition arguments must be " - "a constant integer"); - const uint64_t NumTransitionArgs = - cast<ConstantInt>(StatepointCall.getArgOperand(NumCallArgs + 5)) - ->getZExtValue(); - const uint64_t DeoptArgsStart = 4 + NumCallArgs + 1 + NumTransitionArgs + 1; - Assert(isa<ConstantInt>(StatepointCall.getArgOperand(DeoptArgsStart)), - "gc.statepoint: number of deoptimization arguments must be " - "a constant integer"); - const uint64_t NumDeoptArgs = - cast<ConstantInt>(StatepointCall.getArgOperand(DeoptArgsStart)) - ->getZExtValue(); - const uint64_t GCParamArgsStart = DeoptArgsStart + 1 + NumDeoptArgs; - const uint64_t GCParamArgsEnd = StatepointCall.arg_size(); - Assert(GCParamArgsStart <= BaseIndex && BaseIndex < GCParamArgsEnd, - "gc.relocate: statepoint base index doesn't fall within the " - "'gc parameters' section of the statepoint call", - Call); - Assert(GCParamArgsStart <= DerivedIndex && DerivedIndex < GCParamArgsEnd, - "gc.relocate: statepoint derived index doesn't fall within the " - "'gc parameters' section of the statepoint call", - Call); } // Relocated value must be either a pointer type or vector-of-pointer type, @@ -4952,15 +5016,17 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { case Intrinsic::sadd_sat: case Intrinsic::uadd_sat: case Intrinsic::ssub_sat: - case Intrinsic::usub_sat: { + case Intrinsic::usub_sat: + case Intrinsic::sshl_sat: + case Intrinsic::ushl_sat: { Value *Op1 = Call.getArgOperand(0); Value *Op2 = Call.getArgOperand(1); Assert(Op1->getType()->isIntOrIntVectorTy(), - "first operand of [us][add|sub]_sat must be an int type or vector " - "of ints"); + "first operand of [us][add|sub|shl]_sat must be an int type or " + "vector of ints"); Assert(Op2->getType()->isIntOrIntVectorTy(), - "second operand of [us][add|sub]_sat must be an int type or vector " - "of ints"); + "second operand of [us][add|sub|shl]_sat must be an int type or " + "vector of ints"); break; } case Intrinsic::smul_fix: @@ -5013,6 +5079,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { Assert(Size % 16 == 0, "bswap must be an even number of bytes", &Call); break; } + case Intrinsic::invariant_start: { + ConstantInt *InvariantSize = dyn_cast<ConstantInt>(Call.getArgOperand(0)); + Assert(InvariantSize && + (!InvariantSize->isNegative() || InvariantSize->isMinusOne()), + "invariant_start parameter must be -1, 0 or a positive number", + &Call); + break; + } case Intrinsic::matrix_multiply: case Intrinsic::matrix_transpose: case Intrinsic::matrix_column_major_load: @@ -5076,7 +5150,7 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { "Vector element type mismatch of the result and second operand " "vector!", IF); - Assert(ResultTy->getNumElements() == + Assert(cast<FixedVectorType>(ResultTy)->getNumElements() == NumRows->getZExtValue() * NumColumns->getZExtValue(), "Result of a matrix operation does not fit in the returned vector!"); @@ -5086,6 +5160,30 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { break; } + case Intrinsic::experimental_vector_insert: { + VectorType *VecTy = cast<VectorType>(Call.getArgOperand(0)->getType()); + VectorType *SubVecTy = cast<VectorType>(Call.getArgOperand(1)->getType()); + + Assert(VecTy->getElementType() == SubVecTy->getElementType(), + "experimental_vector_insert parameters must have the same element " + "type.", + &Call); + break; + } + case Intrinsic::experimental_vector_extract: { + VectorType *ResultTy = cast<VectorType>(Call.getType()); + VectorType *VecTy = cast<VectorType>(Call.getArgOperand(0)->getType()); + + Assert(ResultTy->getElementType() == VecTy->getElementType(), + "experimental_vector_extract result must have the same element " + "type as the input vector.", + &Call); + break; + } + case Intrinsic::experimental_noalias_scope_decl: { + NoAliasScopeDecls.push_back(cast<IntrinsicInst>(&Call)); + break; + } }; } @@ -5162,7 +5260,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Assert(Operand->getType()->isFPOrFPVectorTy(), "Intrinsic first argument must be floating point", &FPI); if (auto *OperandT = dyn_cast<VectorType>(Operand->getType())) { - NumSrcElem = OperandT->getNumElements(); + NumSrcElem = cast<FixedVectorType>(OperandT)->getNumElements(); } Operand = &FPI; @@ -5171,7 +5269,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Assert(Operand->getType()->isIntOrIntVectorTy(), "Intrinsic result must be an integer", &FPI); if (auto *OperandT = dyn_cast<VectorType>(Operand->getType())) { - Assert(NumSrcElem == OperandT->getNumElements(), + Assert(NumSrcElem == cast<FixedVectorType>(OperandT)->getNumElements(), "Intrinsic first argument and result vector lengths must be equal", &FPI); } @@ -5185,7 +5283,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Assert(Operand->getType()->isIntOrIntVectorTy(), "Intrinsic first argument must be integer", &FPI); if (auto *OperandT = dyn_cast<VectorType>(Operand->getType())) { - NumSrcElem = OperandT->getNumElements(); + NumSrcElem = cast<FixedVectorType>(OperandT)->getNumElements(); } Operand = &FPI; @@ -5194,7 +5292,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Assert(Operand->getType()->isFPOrFPVectorTy(), "Intrinsic result must be a floating point", &FPI); if (auto *OperandT = dyn_cast<VectorType>(Operand->getType())) { - Assert(NumSrcElem == OperandT->getNumElements(), + Assert(NumSrcElem == cast<FixedVectorType>(OperandT)->getNumElements(), "Intrinsic first argument and result vector lengths must be equal", &FPI); } @@ -5213,9 +5311,8 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Assert(OperandTy->isVectorTy() == ResultTy->isVectorTy(), "Intrinsic first argument and result disagree on vector use", &FPI); if (OperandTy->isVectorTy()) { - auto *OperandVecTy = cast<VectorType>(OperandTy); - auto *ResultVecTy = cast<VectorType>(ResultTy); - Assert(OperandVecTy->getNumElements() == ResultVecTy->getNumElements(), + Assert(cast<FixedVectorType>(OperandTy)->getNumElements() == + cast<FixedVectorType>(ResultTy)->getNumElements(), "Intrinsic first argument and result vector lengths must be equal", &FPI); } @@ -5437,6 +5534,75 @@ void Verifier::verifySourceDebugInfo(const DICompileUnit &U, const DIFile &F) { "inconsistent use of embedded source"); } +void Verifier::verifyNoAliasScopeDecl() { + if (NoAliasScopeDecls.empty()) + return; + + // only a single scope must be declared at a time. + for (auto *II : NoAliasScopeDecls) { + assert(II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl && + "Not a llvm.experimental.noalias.scope.decl ?"); + const auto *ScopeListMV = dyn_cast<MetadataAsValue>( + II->getOperand(Intrinsic::NoAliasScopeDeclScopeArg)); + Assert(ScopeListMV != nullptr, + "llvm.experimental.noalias.scope.decl must have a MetadataAsValue " + "argument", + II); + + const auto *ScopeListMD = dyn_cast<MDNode>(ScopeListMV->getMetadata()); + Assert(ScopeListMD != nullptr, "!id.scope.list must point to an MDNode", + II); + Assert(ScopeListMD->getNumOperands() == 1, + "!id.scope.list must point to a list with a single scope", II); + } + + // Only check the domination rule when requested. Once all passes have been + // adapted this option can go away. + if (!VerifyNoAliasScopeDomination) + return; + + // Now sort the intrinsics based on the scope MDNode so that declarations of + // the same scopes are next to each other. + auto GetScope = [](IntrinsicInst *II) { + const auto *ScopeListMV = cast<MetadataAsValue>( + II->getOperand(Intrinsic::NoAliasScopeDeclScopeArg)); + return &cast<MDNode>(ScopeListMV->getMetadata())->getOperand(0); + }; + + // We are sorting on MDNode pointers here. For valid input IR this is ok. + // TODO: Sort on Metadata ID to avoid non-deterministic error messages. + auto Compare = [GetScope](IntrinsicInst *Lhs, IntrinsicInst *Rhs) { + return GetScope(Lhs) < GetScope(Rhs); + }; + + llvm::sort(NoAliasScopeDecls, Compare); + + // Go over the intrinsics and check that for the same scope, they are not + // dominating each other. + auto ItCurrent = NoAliasScopeDecls.begin(); + while (ItCurrent != NoAliasScopeDecls.end()) { + auto CurScope = GetScope(*ItCurrent); + auto ItNext = ItCurrent; + do { + ++ItNext; + } while (ItNext != NoAliasScopeDecls.end() && + GetScope(*ItNext) == CurScope); + + // [ItCurrent, ItNext) represents the declarations for the same scope. + // Ensure they are not dominating each other.. but only if it is not too + // expensive. + if (ItNext - ItCurrent < 32) + for (auto *I : llvm::make_range(ItCurrent, ItNext)) + for (auto *J : llvm::make_range(ItCurrent, ItNext)) + if (I != J) + Assert(!DT.dominates(I, J), + "llvm.experimental.noalias.scope.decl dominates another one " + "with the same scope", + I); + ItCurrent = ItNext; + } +} + //===----------------------------------------------------------------------===// // Implement the public interfaces to this file... //===----------------------------------------------------------------------===// |