Skip to content

Commit

Permalink
Swift Calling Convention: add swifterror attribute.
Browse files Browse the repository at this point in the history
A ``swifterror`` attribute can be applied to a function parameter or an
AllocaInst.

This commit does not include any target-specific change. The target-specific
optimization will come as a follow-up patch.

Differential Revision: http://reviews.llvm.org/D18092


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265189 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
manman-ren committed Apr 1, 2016
1 parent 44e6fff commit 4bda882
Show file tree
Hide file tree
Showing 26 changed files with 236 additions and 11 deletions.
19 changes: 19 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,25 @@ Currently, only the following parameter attributes are defined:
a valid attribute for return values and can only be applied to one
parameter.

``swifterror``
This attribute is motivated to model and optimize Swift error handling. It
can be applied to a parameter with pointer to pointer type or a
pointer-sized alloca. At the call site, the actual argument that corresponds
to a ``swifterror`` parameter has to come from a ``swifterror`` alloca. A
``swifterror`` value (either the parameter or the alloca) can only be loaded
and stored from, or used as a ``swifterror`` argument. This is not a valid
attribute for return values and can only be applied to one parameter.

These constraints allow the calling convention to optimize access to
``swifterror`` variables by associating them with a specific register at
call boundaries rather than placing them in memory. Since this does change
the calling convention, a function which uses the ``swifterror`` attribute
on a parameter is not ABI-compatible with one which does not.

These constraints also allow LLVM to assume that a ``swifterror`` argument
does not alias any other memory visible within a function and that a
``swifterror`` alloca passed as an argument does not escape.

.. _gc:

Garbage Collector Strategy Names
Expand Down
1 change: 1 addition & 0 deletions include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef enum {
LLVMConvergentAttribute = 1ULL << 46,
LLVMSafeStackAttribute = 1ULL << 47,
LLVMSwiftSelfAttribute = 1ULL << 48,
LLVMSwiftErrorAttribute = 1ULL << 49,
*/
} LLVMAttribute;

Expand Down
3 changes: 2 additions & 1 deletion include/llvm/CodeGen/FastISel.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ class FastISel {
bool IsInAlloca : 1;
bool IsReturned : 1;
bool IsSwiftSelf : 1;
bool IsSwiftError : 1;
uint16_t Alignment;

ArgListEntry()
: Val(nullptr), Ty(nullptr), IsSExt(false), IsZExt(false),
IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false),
IsInAlloca(false), IsReturned(false), IsSwiftSelf(false),
Alignment(0) {}
IsSwiftError(false), Alignment(0) {}

/// \brief Set CallLoweringInfo attribute flags based on a call instruction
/// and called function attributes.
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/IR/Argument.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class Argument : public Value, public ilist_node<Argument> {
/// \brief Return true if this argument has the swiftself attribute.
bool hasSwiftSelfAttr() const;

/// \brief Return true if this argument has the swifterror attribute.
bool hasSwiftErrorAttr() const;

/// \brief Return true if this argument has the byval attribute or inalloca
/// attribute on it in its containing function. These attributes both
/// represent arguments being passed by value.
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ def SanitizeThread : EnumAttr<"sanitize_thread">;
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory">;

/// Argument is swift error.
def SwiftError : EnumAttr<"swifterror">;

/// Argument is swift self/context.
def SwiftSelf : EnumAttr<"swiftself">;

Expand Down
12 changes: 12 additions & 0 deletions include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ class AllocaInst : public UnaryInstruction {
(V ? 32 : 0));
}

/// \brief Return true if this alloca is used as a swifterror argument to a
/// call.
bool isSwiftError() const {
return getSubclassDataFromInstruction() & 64;
}

/// \brief Specify whether this alloca is used to represent a swifterror.
void setSwiftError(bool V) {
setInstructionSubclassData((getSubclassDataFromInstruction() & ~64) |
(V ? 64 : 0));
}

// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::Alloca);
Expand Down
5 changes: 5 additions & 0 deletions include/llvm/Target/TargetCallingConv.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ namespace ISD {
static const uint64_t SplitEndOffs = 13;
static const uint64_t SwiftSelf = 1ULL<<14; ///< Swift self parameter
static const uint64_t SwiftSelfOffs = 14;
static const uint64_t SwiftError = 1ULL<<15; ///< Swift error parameter
static const uint64_t SwiftErrorOffs = 15;
static const uint64_t OrigAlign = 0x1FULL<<27;
static const uint64_t OrigAlignOffs = 27;
static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size
Expand Down Expand Up @@ -87,6 +89,9 @@ namespace ISD {
bool isSwiftSelf() const { return Flags & SwiftSelf; }
void setSwiftSelf() { Flags |= One << SwiftSelfOffs; }

bool isSwiftError() const { return Flags & SwiftError; }
void setSwiftError() { Flags |= One << SwiftErrorOffs; }

bool isNest() const { return Flags & Nest; }
void setNest() { Flags |= One << NestOffs; }

Expand Down
5 changes: 5 additions & 0 deletions include/llvm/Target/TargetCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> {
class CCIfSwiftSelf<CCAction A> : CCIf<"ArgFlags.isSwiftSelf()", A> {
}

/// CCIfSwiftError - If the current argument has swifterror parameter attribute,
/// apply Action A.
class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> {
}

/// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs
/// parameter attribute, apply Action A.
class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> {
Expand Down
4 changes: 3 additions & 1 deletion include/llvm/Target/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -2327,11 +2327,13 @@ class TargetLowering : public TargetLoweringBase {
bool isInAlloca : 1;
bool isReturned : 1;
bool isSwiftSelf : 1;
bool isSwiftError : 1;
uint16_t Alignment;

ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
isSRet(false), isNest(false), isByVal(false), isInAlloca(false),
isReturned(false), isSwiftSelf(false), Alignment(0) { }
isReturned(false), isSwiftSelf(false), isSwiftError(false),
Alignment(0) { }

void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx);
};
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(sanitize_address);
KEYWORD(sanitize_thread);
KEYWORD(sanitize_memory);
KEYWORD(swifterror);
KEYWORD(swiftself);
KEYWORD(uwtable);
KEYWORD(zeroext);
Expand Down
8 changes: 7 additions & 1 deletion lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_nonnull:
case lltok::kw_returned:
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
HaveError |=
Error(Lex.getLoc(),
Expand Down Expand Up @@ -1362,6 +1363,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break;
case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break;
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;

Expand Down Expand Up @@ -1450,6 +1452,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_nocapture:
case lltok::kw_returned:
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
break;
Expand Down Expand Up @@ -5802,14 +5805,16 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
//===----------------------------------------------------------------------===//

/// ParseAlloc
/// ::= 'alloca' 'inalloca'? Type (',' TypeAndValue)? (',' 'align' i32)?
/// ::= 'alloca' 'inalloca'? 'swifterror'? Type (',' TypeAndValue)?
/// (',' 'align' i32)?
int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
Value *Size = nullptr;
LocTy SizeLoc, TyLoc;
unsigned Alignment = 0;
Type *Ty = nullptr;

bool IsInAlloca = EatIfPresent(lltok::kw_inalloca);
bool IsSwiftError = EatIfPresent(lltok::kw_swifterror);

if (ParseType(Ty, TyLoc)) return true;

Expand All @@ -5834,6 +5839,7 @@ int LLParser::ParseAlloc(Instruction *&Inst, PerFunctionState &PFS) {

AllocaInst *AI = new AllocaInst(Ty, Size, Alignment);
AI->setUsedWithInAlloca(IsInAlloca);
AI->setSwiftError(IsSwiftError);
Inst = AI;
return AteExtraComma ? InstExtraComma : InstNormal;
}
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ namespace lltok {
kw_sret,
kw_sanitize_thread,
kw_sanitize_memory,
kw_swifterror,
kw_swiftself,
kw_uwtable,
kw_zeroext,
Expand Down
10 changes: 7 additions & 3 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::SanitizeThread;
case bitc::ATTR_KIND_SANITIZE_MEMORY:
return Attribute::SanitizeMemory;
case bitc::ATTR_KIND_SWIFT_ERROR:
return Attribute::SwiftError;
case bitc::ATTR_KIND_SWIFT_SELF:
return Attribute::SwiftSelf;
case bitc::ATTR_KIND_UW_TABLE:
Expand Down Expand Up @@ -4843,10 +4845,11 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
uint64_t AlignRecord = Record[3];
const uint64_t InAllocaMask = uint64_t(1) << 5;
const uint64_t ExplicitTypeMask = uint64_t(1) << 6;
// Reserve bit 7 for SwiftError flag.
// const uint64_t SwiftErrorMask = uint64_t(1) << 7;
const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask;
const uint64_t SwiftErrorMask = uint64_t(1) << 7;
const uint64_t FlagMask = InAllocaMask | ExplicitTypeMask |
SwiftErrorMask;
bool InAlloca = AlignRecord & InAllocaMask;
bool SwiftError = AlignRecord & SwiftErrorMask;
Type *Ty = getTypeByID(Record[0]);
if ((AlignRecord & ExplicitTypeMask) == 0) {
auto *PTy = dyn_cast_or_null<PointerType>(Ty);
Expand All @@ -4865,6 +4868,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
return error("Invalid record");
AllocaInst *AI = new AllocaInst(Ty, Size, Align);
AI->setUsedWithInAlloca(InAlloca);
AI->setSwiftError(SwiftError);
I = AI;
InstructionList.push_back(I);
break;
Expand Down
5 changes: 3 additions & 2 deletions lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SANITIZE_THREAD;
case Attribute::SanitizeMemory:
return bitc::ATTR_KIND_SANITIZE_MEMORY;
case Attribute::SwiftError:
return bitc::ATTR_KIND_SWIFT_ERROR;
case Attribute::SwiftSelf:
return bitc::ATTR_KIND_SWIFT_SELF;
case Attribute::UWTable:
Expand Down Expand Up @@ -2142,8 +2144,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
assert(AlignRecord < 1 << 5 && "alignment greater than 1 << 64");
AlignRecord |= AI.isUsedWithInAlloca() << 5;
AlignRecord |= 1 << 6;
// Reserve bit 7 for SwiftError flag.
// AlignRecord |= AI.isSwiftError() << 7;
AlignRecord |= AI.isSwiftError() << 7;
Vals.push_back(AlignRecord);
break;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/CodeGen/SelectionDAG/FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ void FastISel::ArgListEntry::setAttributes(ImmutableCallSite *CS,
IsInAlloca = CS->paramHasAttr(AttrIdx, Attribute::InAlloca);
IsReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
IsSwiftSelf = CS->paramHasAttr(AttrIdx, Attribute::SwiftSelf);
IsSwiftError = CS->paramHasAttr(AttrIdx, Attribute::SwiftError);
Alignment = CS->getParamAlignment(AttrIdx);
}

Expand Down Expand Up @@ -960,6 +961,8 @@ bool FastISel::lowerCallTo(CallLoweringInfo &CLI) {
Flags.setSRet();
if (Arg.IsSwiftSelf)
Flags.setSwiftSelf();
if (Arg.IsSwiftError)
Flags.setSwiftError();
if (Arg.IsByVal)
Flags.setByVal();
if (Arg.IsInAlloca) {
Expand Down
5 changes: 5 additions & 0 deletions lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7282,6 +7282,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
Entry.isByVal = false;
Entry.isReturned = false;
Entry.isSwiftSelf = false;
Entry.isSwiftError = false;
Entry.Alignment = Align;
CLI.getArgs().insert(CLI.getArgs().begin(), Entry);
CLI.RetTy = Type::getVoidTy(CLI.RetTy->getContext());
Expand Down Expand Up @@ -7341,6 +7342,8 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
Flags.setSRet();
if (Args[i].isSwiftSelf)
Flags.setSwiftSelf();
if (Args[i].isSwiftError)
Flags.setSwiftError();
if (Args[i].isByVal)
Flags.setByVal();
if (Args[i].isInAlloca) {
Expand Down Expand Up @@ -7623,6 +7626,8 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
Flags.setSRet();
if (F.getAttributes().hasAttribute(Idx, Attribute::SwiftSelf))
Flags.setSwiftSelf();
if (F.getAttributes().hasAttribute(Idx, Attribute::SwiftError))
Flags.setSwiftError();
if (F.getAttributes().hasAttribute(Idx, Attribute::ByVal))
Flags.setByVal();
if (F.getAttributes().hasAttribute(Idx, Attribute::InAlloca)) {
Expand Down
1 change: 1 addition & 0 deletions lib/CodeGen/SelectionDAG/TargetLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ void TargetLowering::ArgListEntry::setAttributes(ImmutableCallSite *CS,
isInAlloca = CS->paramHasAttr(AttrIdx, Attribute::InAlloca);
isReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
isSwiftSelf = CS->paramHasAttr(AttrIdx, Attribute::SwiftSelf);
isSwiftError = CS->paramHasAttr(AttrIdx, Attribute::SwiftError);
Alignment = CS->getParamAlignment(AttrIdx);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3028,6 +3028,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
Out << ' ';
if (AI->isUsedWithInAlloca())
Out << "inalloca ";
if (AI->isSwiftError())
Out << "swifterror ";
TypePrinter.print(AI->getAllocatedType(), Out);

// Explicitly write the array size if the code is broken, if it's an array
Expand Down
3 changes: 3 additions & 0 deletions lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "byval";
if (hasAttribute(Attribute::Convergent))
return "convergent";
if (hasAttribute(Attribute::SwiftError))
return "swifterror";
if (hasAttribute(Attribute::SwiftSelf))
return "swiftself";
if (hasAttribute(Attribute::InaccessibleMemOnly))
Expand Down Expand Up @@ -451,6 +453,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::InaccessibleMemOnly: return 1ULL << 49;
case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50;
case Attribute::SwiftSelf: return 1ULL << 51;
case Attribute::SwiftError: return 1ULL << 52;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
Expand Down
5 changes: 5 additions & 0 deletions lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ bool Argument::hasSwiftSelfAttr() const {
hasAttribute(getArgNo()+1, Attribute::SwiftSelf);
}

bool Argument::hasSwiftErrorAttr() const {
return getParent()->getAttributes().
hasAttribute(getArgNo()+1, Attribute::SwiftError);
}

/// \brief Return true if this argument has the inalloca attribute on it in
/// its containing function.
bool Argument::hasInAllocaAttr() const {
Expand Down
1 change: 1 addition & 0 deletions lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3811,6 +3811,7 @@ AllocaInst *AllocaInst::cloneImpl() const {
AllocaInst *Result = new AllocaInst(getAllocatedType(),
(Value *)getOperand(0), getAlignment());
Result->setUsedWithInAlloca(isUsedWithInAlloca());
Result->setSwiftError(isSwiftError());
return Result;
}

Expand Down
Loading

0 comments on commit 4bda882

Please sign in to comment.