diff options
author | Tim Northover <tnorthover@apple.com> | 2019-05-29 19:12:48 +0000 |
---|---|---|
committer | Tim Northover <tnorthover@apple.com> | 2019-05-29 19:12:48 +0000 |
commit | 6e07f16fae605c42014aa4f1f2babf3e7767c95c (patch) | |
tree | 0fc6d7bdebcdd3d743976cbbee35393af81f9a62 /llvm/lib | |
parent | ee37e28fd1c670ecabea64a15b9cc8698ca62b86 (diff) | |
download | bcm5719-llvm-6e07f16fae605c42014aa4f1f2babf3e7767c95c.tar.gz bcm5719-llvm-6e07f16fae605c42014aa4f1f2babf3e7767c95c.zip |
IR: add optional type to 'byval' function parameters
When we switch to opaque pointer types we will need some way to describe
how many bytes a 'byval' parameter should occupy on the stack. This adds
a (for now) optional extra type parameter.
If present, the type must match the pointee type of the argument.
Note to front-end maintainers: if this causes test failures, it's probably
because the "byval" attribute is printed after attributes without any parameter
after this change.
llvm-svn: 362012
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 24 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 1 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 50 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/ValueEnumerator.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/IR/AttributeImpl.h | 32 | ||||
-rw-r--r-- | llvm/lib/IR/Attributes.cpp | 108 | ||||
-rw-r--r-- | llvm/lib/IR/Function.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/IR/Verifier.cpp | 5 |
13 files changed, 252 insertions, 26 deletions
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 95646675cb2..0a9a09e644d 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1601,7 +1601,13 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) { B.addAlignmentAttr(Alignment); continue; } - case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break; + case lltok::kw_byval: { + Type *Ty; + if (ParseByValWithOptionalType(Ty)) + return true; + B.addByValAttr(Ty); + continue; + } case lltok::kw_dereferenceable: { uint64_t Bytes; if (ParseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes)) @@ -2454,6 +2460,22 @@ bool LLParser::ParseParameterList(SmallVectorImpl<ParamInfo> &ArgList, return false; } +/// ParseByValWithOptionalType +/// ::= byval +/// ::= byval(<ty>) +bool LLParser::ParseByValWithOptionalType(Type *&Result) { + Result = nullptr; + if (!EatIfPresent(lltok::kw_byval)) + return true; + if (!EatIfPresent(lltok::lparen)) + return false; + if (ParseType(Result)) + return true; + if (!EatIfPresent(lltok::rparen)) + return Error(Lex.getLoc(), "expected ')'"); + return false; +} + /// ParseOptionalOperandBundles /// ::= /*empty*/ /// ::= '[' OperandBundle [, OperandBundle ]* ']' diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index ad169afb935..ec4a61b5498 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -339,6 +339,7 @@ namespace llvm { bool ParseFnAttributeValuePairs(AttrBuilder &B, std::vector<unsigned> &FwdRefAttrGrps, bool inAttrGrp, LocTy &BuiltinLoc); + bool ParseByValWithOptionalType(Type *&Result); // Module Summary Index Parsing. bool SkipModuleSummaryEntry(); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 134ce036703..9f562ba82db 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -638,6 +638,10 @@ private: return getFnValueByID(ValNo, Ty); } + /// Upgrades old-style typeless byval attributes by adding the corresponding + /// argument's pointee type. + void propagateByValTypes(CallBase *CB); + /// Converts alignment exponent (i.e. power of two (or zero)) to the /// corresponding alignment to use. If alignment is too large, returns /// a corresponding error code. @@ -1492,6 +1496,12 @@ Error BitcodeReader::parseAttributeGroupBlock() { if (Error Err = parseAttrKind(Record[++i], &Kind)) return Err; + // Upgrade old-style byval attribute to one with a type, even if it's + // nullptr. We will have to insert the real type when we associate + // this AttributeList with a function. + if (Kind == Attribute::ByVal) + B.addByValAttr(nullptr); + B.addAttribute(Kind); } else if (Record[i] == 1) { // Integer attribute Attribute::AttrKind Kind; @@ -1507,9 +1517,7 @@ Error BitcodeReader::parseAttributeGroupBlock() { B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); - } else { // String attribute - assert((Record[i] == 3 || Record[i] == 4) && - "Invalid attribute group entry"); + } else if (Record[i] == 3 || Record[i] == 4) { // String attribute bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; SmallString<64> ValStr; @@ -1527,6 +1535,15 @@ Error BitcodeReader::parseAttributeGroupBlock() { } B.addAttribute(KindStr.str(), ValStr.str()); + } else { + assert((Record[i] == 5 || Record[i] == 6) && + "Invalid attribute group entry"); + bool HasType = Record[i] == 6; + Attribute::AttrKind Kind; + if (Error Err = parseAttrKind(Record[++i], &Kind)) + return Err; + if (Kind == Attribute::ByVal) + B.addByValAttr(HasType ? getTypeByID(Record[++i]) : nullptr); } } @@ -3028,6 +3045,17 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) { Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); + // Upgrade any old-style byval without a type by propagating the argument's + // pointee type. There should be no opaque pointers where the byval type is + // implicit. + for (auto &Arg : Func->args()) { + if (Arg.hasByValAttr() && !Arg.getParamByValType()) { + Arg.removeAttr(Attribute::ByVal); + Arg.addAttr(Attribute::getWithByValType( + Context, Arg.getType()->getPointerElementType())); + } + } + unsigned Alignment; if (Error Err = parseAlignmentValue(Record[5], Alignment)) return Err; @@ -3441,6 +3469,19 @@ Error BitcodeReader::typeCheckLoadStoreInst(Type *ValType, Type *PtrType) { return Error::success(); } +void BitcodeReader::propagateByValTypes(CallBase *CB) { + for (unsigned i = 0; i < CB->getNumArgOperands(); ++i) { + if (CB->paramHasAttr(i, Attribute::ByVal) && + !CB->getAttribute(i, Attribute::ByVal).getValueAsType()) { + CB->removeParamAttr(i, Attribute::ByVal); + CB->addParamAttr( + i, Attribute::getWithByValType( + Context, + CB->getArgOperand(i)->getType()->getPointerElementType())); + } + } +} + /// Lazily parse the specified function body block. Error BitcodeReader::parseFunctionBody(Function *F) { if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) @@ -4256,6 +4297,8 @@ Error BitcodeReader::parseFunctionBody(Function *F) { cast<InvokeInst>(I)->setCallingConv( static_cast<CallingConv::ID>(CallingConv::MaxID & CCInfo)); cast<InvokeInst>(I)->setAttributes(PAL); + propagateByValTypes(cast<CallBase>(I)); + break; } case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] @@ -4731,6 +4774,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) { TCK = CallInst::TCK_NoTail; cast<CallInst>(I)->setTailCallKind(TCK); cast<CallInst>(I)->setAttributes(PAL); + propagateByValTypes(cast<CallBase>(I)); if (FMF.any()) { if (!isa<FPMathOperator>(I)) return error("Fast-math-flags specified for call without " diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 8e1e06226bb..d243815667f 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -747,7 +747,7 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() { Record.push_back(1); Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum())); Record.push_back(Attr.getValueAsInt()); - } else { + } else if (Attr.isStringAttribute()) { StringRef Kind = Attr.getKindAsString(); StringRef Val = Attr.getValueAsString(); @@ -758,6 +758,13 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() { Record.append(Val.begin(), Val.end()); Record.push_back(0); } + } else { + assert(Attr.isTypeAttribute()); + Type *Ty = Attr.getValueAsType(); + Record.push_back(Ty ? 6 : 5); + Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum())); + if (Ty) + Record.push_back(VE.getTypeID(Attr.getValueAsType())); } } @@ -4126,15 +4133,15 @@ void ModuleBitcodeWriter::write() { // Emit blockinfo, which defines the standard abbreviations etc. writeBlockInfo(); + // Emit information describing all of the types in the module. + writeTypeTable(); + // Emit information about attribute groups. writeAttributeGroupTable(); // Emit information about parameter attributes. writeAttributeTable(); - // Emit information describing all of the types in the module. - writeTypeTable(); - writeComdats(); // Emit top-level description of module, including target triple, inline asm, diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp index 72d7000fad9..143570fb20a 100644 --- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -949,9 +949,11 @@ void ValueEnumerator::incorporateFunction(const Function &F) { incorporateFunctionMetadata(F); // Adding function arguments to the value table. - for (const auto &I : F.args()) + for (const auto &I : F.args()) { EnumerateValue(&I); - + if (I.hasAttribute(Attribute::ByVal) && I.getParamByValType()) + EnumerateType(I.getParamByValType()); + } FirstFuncConstantID = Values.size(); // Add all function-level constants to the value table. diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index f144b18aa63..93727406a08 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -87,7 +87,10 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx, if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) { Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType(); - Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy)); + + auto Ty = Attrs.getAttribute(OpIdx, Attribute::ByVal).getValueAsType(); + Arg.Flags.setByValSize(DL.getTypeAllocSize(Ty ? Ty : ElementTy)); + // For ByVal, alignment should be passed from FE. BE will guess if // this info is not there but there are cases it cannot get right. unsigned FrameAlign; diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 8fb1a7b5bb9..d887ed73c44 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1204,9 +1204,11 @@ bool FastISel::lowerCallTo(CallLoweringInfo &CLI) { if (Arg.IsByVal || Arg.IsInAlloca) { PointerType *Ty = cast<PointerType>(Arg.Ty); Type *ElementTy = Ty->getElementType(); - unsigned FrameSize = DL.getTypeAllocSize(ElementTy); - // For ByVal, alignment should come from FE. BE will guess if this info is - // not there, but there are cases it cannot get right. + unsigned FrameSize = + DL.getTypeAllocSize(Arg.ByValType ? Arg.ByValType : ElementTy); + + // For ByVal, alignment should come from FE. BE will guess if this info + // is not there, but there are cases it cannot get right. unsigned FrameAlign = Arg.Alignment; if (!FrameAlign) FrameAlign = TLI.getByValTypeAlignment(ElementTy, DL); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index fe857f73b25..da06ac7a414 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9076,8 +9076,11 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const { if (Args[i].IsByVal || Args[i].IsInAlloca) { PointerType *Ty = cast<PointerType>(Args[i].Ty); Type *ElementTy = Ty->getElementType(); - Flags.setByValSize(DL.getTypeAllocSize(ElementTy)); - // For ByVal, alignment should come from FE. BE will guess if this + + unsigned FrameSize = DL.getTypeAllocSize( + Args[i].ByValType ? Args[i].ByValType : ElementTy); + Flags.setByValSize(FrameSize); + // info is not there but there are cases it cannot get right. unsigned FrameAlign; if (Args[i].Alignment) @@ -9574,9 +9577,14 @@ void SelectionDAGISel::LowerArguments(const Function &F) { if (Flags.isByVal() || Flags.isInAlloca()) { PointerType *Ty = cast<PointerType>(Arg.getType()); Type *ElementTy = Ty->getElementType(); - Flags.setByValSize(DL.getTypeAllocSize(ElementTy)); - // For ByVal, alignment should be passed from FE. BE will guess if - // this info is not there but there are cases it cannot get right. + + // For ByVal, size and alignment should be passed from FE. BE will + // guess if this info is not there but there are cases it cannot get + // right. + unsigned FrameSize = DL.getTypeAllocSize( + Arg.getParamByValType() ? Arg.getParamByValType() : ElementTy); + Flags.setByValSize(FrameSize); + unsigned FrameAlign; if (Arg.getParamAlignment()) FrameAlign = Arg.getParamAlignment(); diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index d636e613363..4ad578d80fa 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -112,6 +112,7 @@ void TargetLoweringBase::ArgListEntry::setAttributes(const CallBase *Call, IsSwiftSelf = Call->paramHasAttr(ArgIdx, Attribute::SwiftSelf); IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError); Alignment = Call->getParamAlignment(ArgIdx); + ByValType = Call->getParamByValType(ArgIdx); } /// Generate a libcall taking the given operands as arguments and returning a diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h index 8ebcb04a565..f6898476382 100644 --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -29,6 +29,7 @@ namespace llvm { class LLVMContext; +class Type; //===----------------------------------------------------------------------===// /// \class @@ -41,7 +42,8 @@ protected: enum AttrEntryKind { EnumAttrEntry, IntAttrEntry, - StringAttrEntry + StringAttrEntry, + TypeAttrEntry, }; AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {} @@ -56,6 +58,7 @@ public: bool isEnumAttribute() const { return KindID == EnumAttrEntry; } bool isIntAttribute() const { return KindID == IntAttrEntry; } bool isStringAttribute() const { return KindID == StringAttrEntry; } + bool isTypeAttribute() const { return KindID == TypeAttrEntry; } bool hasAttribute(Attribute::AttrKind A) const; bool hasAttribute(StringRef Kind) const; @@ -66,16 +69,20 @@ public: StringRef getKindAsString() const; StringRef getValueAsString() const; + Type *getValueAsType() const; + /// Used when sorting the attributes. bool operator<(const AttributeImpl &AI) const; void Profile(FoldingSetNodeID &ID) const { if (isEnumAttribute()) - Profile(ID, getKindAsEnum(), 0); + Profile(ID, getKindAsEnum(), static_cast<uint64_t>(0)); else if (isIntAttribute()) Profile(ID, getKindAsEnum(), getValueAsInt()); - else + else if (isStringAttribute()) Profile(ID, getKindAsString(), getValueAsString()); + else + Profile(ID, getKindAsEnum(), getValueAsType()); } static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, @@ -88,6 +95,12 @@ public: ID.AddString(Kind); if (!Values.empty()) ID.AddString(Values); } + + static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, + Type *Ty) { + ID.AddInteger(Kind); + ID.AddPointer(Ty); + } }; //===----------------------------------------------------------------------===// @@ -145,6 +158,18 @@ public: StringRef getStringValue() const { return Val; } }; +class TypeAttributeImpl : public EnumAttributeImpl { + virtual void anchor(); + + Type *Ty; + +public: + TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) + : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} + + Type *getTypeValue() const { return Ty; } +}; + //===----------------------------------------------------------------------===// /// \class /// This class represents a group of attributes that apply to one @@ -189,6 +214,7 @@ public: uint64_t getDereferenceableOrNullBytes() const; std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const; std::string getAsString(bool InAttrGrp) const; + Type *getByValType() const; using iterator = const Attribute *; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 0be09a05e82..839ef46b4f4 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -121,6 +121,27 @@ Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) { return Attribute(PA); } +Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, + Type *Ty) { + LLVMContextImpl *pImpl = Context.pImpl; + FoldingSetNodeID ID; + ID.AddInteger(Kind); + ID.AddPointer(Ty); + + void *InsertPoint; + AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); + + if (!PA) { + // If we didn't find any existing attributes of the same shape then create a + // new one and insert it. + PA = new TypeAttributeImpl(Kind, Ty); + pImpl->AttrsSet.InsertNode(PA, InsertPoint); + } + + // Return the Attribute that we found or created. + return Attribute(PA); +} + Attribute Attribute::getWithAlignment(LLVMContext &Context, uint64_t Align) { assert(isPowerOf2_32(Align) && "Alignment must be a power of two."); assert(Align <= 0x40000000 && "Alignment too large."); @@ -146,6 +167,10 @@ Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context, return get(Context, DereferenceableOrNull, Bytes); } +Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { + return get(Context, ByVal, Ty); +} + Attribute Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, const Optional<unsigned> &NumElemsArg) { @@ -170,9 +195,13 @@ bool Attribute::isStringAttribute() const { return pImpl && pImpl->isStringAttribute(); } +bool Attribute::isTypeAttribute() const { + return pImpl && pImpl->isTypeAttribute(); +} + Attribute::AttrKind Attribute::getKindAsEnum() const { if (!pImpl) return None; - assert((isEnumAttribute() || isIntAttribute()) && + assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) && "Invalid attribute type to get the kind as an enum!"); return pImpl->getKindAsEnum(); } @@ -198,6 +227,14 @@ StringRef Attribute::getValueAsString() const { return pImpl->getValueAsString(); } +Type *Attribute::getValueAsType() const { + if (!pImpl) return {}; + assert(isTypeAttribute() && + "Invalid attribute type to get the value as a type!"); + return pImpl->getValueAsType(); +} + + bool Attribute::hasAttribute(AttrKind Kind) const { return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None); } @@ -252,8 +289,6 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "argmemonly"; if (hasAttribute(Attribute::Builtin)) return "builtin"; - if (hasAttribute(Attribute::ByVal)) - return "byval"; if (hasAttribute(Attribute::Convergent)) return "convergent"; if (hasAttribute(Attribute::SwiftError)) @@ -353,6 +388,19 @@ std::string Attribute::getAsString(bool InAttrGrp) const { if (hasAttribute(Attribute::ImmArg)) return "immarg"; + if (hasAttribute(Attribute::ByVal)) { + std::string Result; + Result += "byval"; + if (Type *Ty = getValueAsType()) { + raw_string_ostream OS(Result); + Result += '('; + Ty->print(OS, false, true); + OS.flush(); + Result += ')'; + } + return Result; + } + // FIXME: These should be output like this: // // align=4 @@ -451,6 +499,8 @@ void IntAttributeImpl::anchor() {} void StringAttributeImpl::anchor() {} +void TypeAttributeImpl::anchor() {} + bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const { if (isStringAttribute()) return false; return getKindAsEnum() == A; @@ -462,7 +512,7 @@ bool AttributeImpl::hasAttribute(StringRef Kind) const { } Attribute::AttrKind AttributeImpl::getKindAsEnum() const { - assert(isEnumAttribute() || isIntAttribute()); + assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute()); return static_cast<const EnumAttributeImpl *>(this)->getEnumKind(); } @@ -481,6 +531,11 @@ StringRef AttributeImpl::getValueAsString() const { return static_cast<const StringAttributeImpl *>(this)->getStringValue(); } +Type *AttributeImpl::getValueAsType() const { + assert(isTypeAttribute()); + return static_cast<const TypeAttributeImpl *>(this)->getTypeValue(); +} + bool AttributeImpl::operator<(const AttributeImpl &AI) const { // This sorts the attributes with Attribute::AttrKinds coming first (sorted // relative to their enum value) and then strings. @@ -488,10 +543,23 @@ bool AttributeImpl::operator<(const AttributeImpl &AI) const { if (AI.isEnumAttribute()) return getKindAsEnum() < AI.getKindAsEnum(); if (AI.isIntAttribute()) return true; if (AI.isStringAttribute()) return true; + if (AI.isTypeAttribute()) return true; + } + + if (isTypeAttribute()) { + if (AI.isEnumAttribute()) return false; + if (AI.isTypeAttribute()) { + assert(getKindAsEnum() != AI.getKindAsEnum() && + "Comparison of types would be unstable"); + return getKindAsEnum() < AI.getKindAsEnum(); + } + if (AI.isIntAttribute()) return true; + if (AI.isStringAttribute()) return true; } if (isIntAttribute()) { if (AI.isEnumAttribute()) return false; + if (AI.isTypeAttribute()) return false; if (AI.isIntAttribute()) { if (getKindAsEnum() == AI.getKindAsEnum()) return getValueAsInt() < AI.getValueAsInt(); @@ -500,7 +568,9 @@ bool AttributeImpl::operator<(const AttributeImpl &AI) const { if (AI.isStringAttribute()) return true; } + assert(isStringAttribute()); if (AI.isEnumAttribute()) return false; + if (AI.isTypeAttribute()) return false; if (AI.isIntAttribute()) return false; if (getKindAsString() == AI.getKindAsString()) return getValueAsString() < AI.getValueAsString(); @@ -608,6 +678,10 @@ uint64_t AttributeSet::getDereferenceableOrNullBytes() const { return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0; } +Type *AttributeSet::getByValType() const { + return SetNode ? SetNode->getByValType() : nullptr; +} + std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs() const { return SetNode ? SetNode->getAllocSizeArgs() : std::pair<unsigned, Optional<unsigned>>(0, 0); @@ -691,6 +765,9 @@ AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) { Attribute Attr; switch (Kind) { + case Attribute::ByVal: + Attr = Attribute::getWithByValType(C, B.getByValType()); + break; case Attribute::Alignment: Attr = Attribute::getWithAlignment(C, B.getAlignment()); break; @@ -760,6 +837,13 @@ unsigned AttributeSetNode::getStackAlignment() const { return 0; } +Type *AttributeSetNode::getByValType() const { + for (const auto I : *this) + if (I.hasAttribute(Attribute::ByVal)) + return I.getValueAsType(); + return 0; +} + uint64_t AttributeSetNode::getDereferenceableBytes() const { for (const auto I : *this) if (I.hasAttribute(Attribute::Dereferenceable)) @@ -1258,6 +1342,11 @@ unsigned AttributeList::getParamAlignment(unsigned ArgNo) const { return getAttributes(ArgNo + FirstArgIndex).getAlignment(); } +Type *AttributeList::getParamByValType(unsigned Index) const { + return getAttributes(Index+FirstArgIndex).getByValType(); +} + + unsigned AttributeList::getStackAlignment(unsigned Index) const { return getAttributes(Index).getStackAlignment(); } @@ -1336,6 +1425,7 @@ void AttrBuilder::clear() { TargetDepAttrs.clear(); Alignment = StackAlignment = DerefBytes = DerefOrNullBytes = 0; AllocSizeArgs = 0; + ByValType = nullptr; } AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) { @@ -1360,6 +1450,8 @@ AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { Alignment = Attr.getAlignment(); else if (Kind == Attribute::StackAlignment) StackAlignment = Attr.getStackAlignment(); + else if (Kind == Attribute::ByVal) + ByValType = Attr.getValueAsType(); else if (Kind == Attribute::Dereferenceable) DerefBytes = Attr.getDereferenceableBytes(); else if (Kind == Attribute::DereferenceableOrNull) @@ -1382,6 +1474,8 @@ AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { Alignment = 0; else if (Val == Attribute::StackAlignment) StackAlignment = 0; + else if (Val == Attribute::ByVal) + ByValType = nullptr; else if (Val == Attribute::Dereferenceable) DerefBytes = 0; else if (Val == Attribute::DereferenceableOrNull) @@ -1464,6 +1558,12 @@ AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) { return *this; } +AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { + Attrs[Attribute::ByVal] = true; + ByValType = Ty; + return *this; +} + AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { // FIXME: What if both have alignments, but they don't match?! if (!Alignment) diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index b00deb677b3..a4a78ca4deb 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -113,6 +113,11 @@ unsigned Argument::getParamAlignment() const { return getParent()->getParamAlignment(getArgNo()); } +Type *Argument::getParamByValType() const { + assert(getType()->isPointerTy() && "Only pointers have byval types"); + return getParent()->getParamByValType(getArgNo()); +} + uint64_t Argument::getDereferenceableBytes() const { assert(getType()->isPointerTy() && "Only pointers have dereferenceable bytes"); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index d5c3287e713..963bf82c989 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1695,6 +1695,11 @@ 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!"); + } + AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty); Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs), "Wrong types for attribute: " + |