summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2019-05-29 19:12:48 +0000
committerTim Northover <tnorthover@apple.com>2019-05-29 19:12:48 +0000
commit6e07f16fae605c42014aa4f1f2babf3e7767c95c (patch)
tree0fc6d7bdebcdd3d743976cbbee35393af81f9a62 /llvm/lib
parentee37e28fd1c670ecabea64a15b9cc8698ca62b86 (diff)
downloadbcm5719-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.cpp24
-rw-r--r--llvm/lib/AsmParser/LLParser.h1
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp50
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp15
-rw-r--r--llvm/lib/Bitcode/Writer/ValueEnumerator.cpp6
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp5
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FastISel.cpp8
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp18
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp1
-rw-r--r--llvm/lib/IR/AttributeImpl.h32
-rw-r--r--llvm/lib/IR/Attributes.cpp108
-rw-r--r--llvm/lib/IR/Function.cpp5
-rw-r--r--llvm/lib/IR/Verifier.cpp5
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: " +
OpenPOWER on IntegriCloud