``dereferenceable(<n>)``). This attribute may only be applied to
pointer typed parameters.
+``swiftself``
+ This indicates that the parameter is the self/context parameter. This is not
+ a valid attribute for return values and can only be applied to one
+ parameter.
+
.. _gc:
Garbage Collector Strategy Names
LLVMJumpTableAttribute = 1ULL << 45,
LLVMConvergentAttribute = 1ULL << 46,
LLVMSafeStackAttribute = 1ULL << 47,
+ LLVMSwiftSelfAttribute = 1ULL << 48,
*/
} LLVMAttribute;
bool IsByVal : 1;
bool IsInAlloca : 1;
bool IsReturned : 1;
+ bool IsSwiftSelf : 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), Alignment(0) {}
+ IsInAlloca(false), IsReturned(false), IsSwiftSelf(false),
+ Alignment(0) {}
/// \brief Set CallLoweringInfo attribute flags based on a call instruction
/// and called function attributes.
/// containing function.
bool hasByValAttr() const;
+ /// \brief Return true if this argument has the swiftself attribute.
+ bool hasSwiftSelfAttr() 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.
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory">;
+/// Argument is swift self/context.
+def SwiftSelf : EnumAttr<"swiftself">;
+
/// Function must be in a unwind table.
def UWTable : EnumAttr<"uwtable">;
static const uint64_t InAllocaOffs = 12;
static const uint64_t SplitEnd = 1ULL<<13; ///< Last part of a split
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 OrigAlign = 0x1FULL<<27;
static const uint64_t OrigAlignOffs = 27;
static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size
bool isInAlloca() const { return Flags & InAlloca; }
void setInAlloca() { Flags |= One << InAllocaOffs; }
+ bool isSwiftSelf() const { return Flags & SwiftSelf; }
+ void setSwiftSelf() { Flags |= One << SwiftSelfOffs; }
+
bool isNest() const { return Flags & Nest; }
void setNest() { Flags |= One << NestOffs; }
class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> {
}
+/// CCIfSwiftSelf - If the current argument has swiftself parameter attribute,
+/// apply Action A.
+class CCIfSwiftSelf<CCAction A> : CCIf<"ArgFlags.isSwiftSelf()", A> {
+}
+
/// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs
/// parameter attribute, apply Action A.
class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> {
bool isByVal : 1;
bool isInAlloca : 1;
bool isReturned : 1;
+ bool isSwiftSelf : 1;
uint16_t Alignment;
ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
isSRet(false), isNest(false), isByVal(false), isInAlloca(false),
- isReturned(false), Alignment(0) { }
+ isReturned(false), isSwiftSelf(false), Alignment(0) { }
void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx);
};
KEYWORD(sanitize_address);
KEYWORD(sanitize_thread);
KEYWORD(sanitize_memory);
+ KEYWORD(swiftself);
KEYWORD(uwtable);
KEYWORD(zeroext);
case lltok::kw_nonnull:
case lltok::kw_returned:
case lltok::kw_sret:
+ case lltok::kw_swiftself:
HaveError |=
Error(Lex.getLoc(),
"invalid use of parameter-only attribute on a function");
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_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
case lltok::kw_alignstack:
case lltok::kw_nocapture:
case lltok::kw_returned:
case lltok::kw_sret:
+ case lltok::kw_swiftself:
HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
break;
kw_sret,
kw_sanitize_thread,
kw_sanitize_memory,
+ kw_swiftself,
kw_uwtable,
kw_zeroext,
return Attribute::SanitizeThread;
case bitc::ATTR_KIND_SANITIZE_MEMORY:
return Attribute::SanitizeMemory;
+ case bitc::ATTR_KIND_SWIFT_SELF:
+ return Attribute::SwiftSelf;
case bitc::ATTR_KIND_UW_TABLE:
return Attribute::UWTable;
case bitc::ATTR_KIND_Z_EXT:
return bitc::ATTR_KIND_SANITIZE_THREAD;
case Attribute::SanitizeMemory:
return bitc::ATTR_KIND_SANITIZE_MEMORY;
+ case Attribute::SwiftSelf:
+ return bitc::ATTR_KIND_SWIFT_SELF;
case Attribute::UWTable:
return bitc::ATTR_KIND_UW_TABLE;
case Attribute::ZExt:
IsByVal = CS->paramHasAttr(AttrIdx, Attribute::ByVal);
IsInAlloca = CS->paramHasAttr(AttrIdx, Attribute::InAlloca);
IsReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
+ IsSwiftSelf = CS->paramHasAttr(AttrIdx, Attribute::SwiftSelf);
Alignment = CS->getParamAlignment(AttrIdx);
}
Flags.setInReg();
if (Arg.IsSRet)
Flags.setSRet();
+ if (Arg.IsSwiftSelf)
+ Flags.setSwiftSelf();
if (Arg.IsByVal)
Flags.setByVal();
if (Arg.IsInAlloca) {
Entry.isNest = false;
Entry.isByVal = false;
Entry.isReturned = false;
+ Entry.isSwiftSelf = false;
Entry.Alignment = Align;
CLI.getArgs().insert(CLI.getArgs().begin(), Entry);
CLI.RetTy = Type::getVoidTy(CLI.RetTy->getContext());
Flags.setInReg();
if (Args[i].isSRet)
Flags.setSRet();
+ if (Args[i].isSwiftSelf)
+ Flags.setSwiftSelf();
if (Args[i].isByVal)
Flags.setByVal();
if (Args[i].isInAlloca) {
Flags.setInReg();
if (F.getAttributes().hasAttribute(Idx, Attribute::StructRet))
Flags.setSRet();
+ if (F.getAttributes().hasAttribute(Idx, Attribute::SwiftSelf))
+ Flags.setSwiftSelf();
if (F.getAttributes().hasAttribute(Idx, Attribute::ByVal))
Flags.setByVal();
if (F.getAttributes().hasAttribute(Idx, Attribute::InAlloca)) {
isByVal = CS->paramHasAttr(AttrIdx, Attribute::ByVal);
isInAlloca = CS->paramHasAttr(AttrIdx, Attribute::InAlloca);
isReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
+ isSwiftSelf = CS->paramHasAttr(AttrIdx, Attribute::SwiftSelf);
Alignment = CS->getParamAlignment(AttrIdx);
}
return "byval";
if (hasAttribute(Attribute::Convergent))
return "convergent";
+ if (hasAttribute(Attribute::SwiftSelf))
+ return "swiftself";
if (hasAttribute(Attribute::InaccessibleMemOnly))
return "inaccessiblememonly";
if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly))
case Attribute::NoRecurse: return 1ULL << 48;
case Attribute::InaccessibleMemOnly: return 1ULL << 49;
case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50;
+ case Attribute::SwiftSelf: return 1ULL << 51;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
return hasAttribute(Attribute::ByVal);
}
+bool Argument::hasSwiftSelfAttr() const {
+ return getParent()->getAttributes().
+ hasAttribute(getArgNo()+1, Attribute::SwiftSelf);
+}
+
/// \brief Return true if this argument has the inalloca attribute on it in
/// its containing function.
bool Argument::hasInAllocaAttr() const {
!Attrs.hasAttribute(Idx, Attribute::StructRet) &&
!Attrs.hasAttribute(Idx, Attribute::NoCapture) &&
!Attrs.hasAttribute(Idx, Attribute::Returned) &&
- !Attrs.hasAttribute(Idx, Attribute::InAlloca),
- "Attributes 'byval', 'inalloca', 'nest', 'sret', 'nocapture', and "
- "'returned' do not apply to return values!",
+ !Attrs.hasAttribute(Idx, Attribute::InAlloca) &&
+ !Attrs.hasAttribute(Idx, Attribute::SwiftSelf),
+ "Attributes 'byval', 'inalloca', 'nest', 'sret', 'nocapture', "
+ "'returned', and 'swiftself' do not apply to return "
+ "values!",
V);
// Check for mutually incompatible attributes. Only inreg is compatible with
bool SawNest = false;
bool SawReturned = false;
bool SawSRet = false;
+ bool SawSwiftSelf = false;
for (unsigned i = 0, e = Attrs.getNumSlots(); i != e; ++i) {
unsigned Idx = Attrs.getSlotIndex(i);
SawSRet = true;
}
+ if (Attrs.hasAttribute(Idx, Attribute::SwiftSelf)) {
+ Assert(!SawSwiftSelf, "Cannot have multiple 'swiftself' parameters!", V);
+ SawSwiftSelf = true;
+ }
+
if (Attrs.hasAttribute(Idx, Attribute::InAlloca)) {
Assert(Idx == FT->getNumParams(), "inalloca isn't on the last parameter!",
V);
static AttrBuilder getParameterABIAttributes(int I, AttributeSet Attrs) {
static const Attribute::AttrKind ABIAttrs[] = {
Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca,
- Attribute::InReg, Attribute::Returned};
+ Attribute::InReg, Attribute::Returned, Attribute::SwiftSelf};
AttrBuilder Copy;
for (auto AK : ABIAttrs) {
if (Attrs.hasAttribute(I + 1, AK))
// slot is 64-bit.
CCIfByVal<CCPassByVal<8, 8>>,
+ // A SwiftSelf is passed in X9.
+ CCIfSwiftSelf<CCIfType<[i64], CCAssignToRegWithShadow<[X9], [W9]>>>,
+
CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>,
// Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers,
if (F->getAttributes().hasAttribute(Idx, Attribute::ByVal) ||
F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
+ F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
F->getAttributes().hasAttribute(Idx, Attribute::Nest))
return false;
return false;
for (auto Flag : CLI.OutFlags)
- if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal())
+ if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal() ||
+ Flag.isSwiftSelf())
return false;
// Set up the argument vectors.
CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+ // A SwiftSelf is passed in R9.
+ CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
+
// Handle all vector types as either f64 or v2f64.
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ // A SwiftSelf is passed in R9.
+ CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
+
CCIfType<[f64, v2f64], CCCustom<"CC_ARM_AAPCS_Custom_f64">>,
CCIfType<[f32], CCBitConvertToType<i32>>,
CCDelegateTo<CC_ARM_AAPCS_Common>
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ // A SwiftSelf is passed in R9.
+ CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R9]>>>,
+
// HFAs are passed in a contiguous block of registers, or on the stack
CCIfConsecutiveRegs<CCCustom<"CC_ARM_AAPCS_Custom_Aggregate">>,
// FIXME: Only handle *easy* calls for now.
if (CS.paramHasAttr(AttrInd, Attribute::InReg) ||
CS.paramHasAttr(AttrInd, Attribute::StructRet) ||
+ CS.paramHasAttr(AttrInd, Attribute::SwiftSelf) ||
CS.paramHasAttr(AttrInd, Attribute::Nest) ||
CS.paramHasAttr(AttrInd, Attribute::ByVal))
return false;
if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
+ F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
F->getAttributes().hasAttribute(Idx, Attribute::ByVal))
return false;
CCIfNest<CCIfSubtarget<"isTarget64BitILP32()", CCAssignToReg<[R10D]>>>,
CCIfNest<CCAssignToReg<[R10]>>,
+ // A SwiftSelf is passed in R10.
+ CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R10]>>>,
+
// The first 6 integer arguments are passed in integer registers.
CCIfType<[i32], CCAssignToReg<[EDI, ESI, EDX, ECX, R8D, R9D]>>,
CCIfType<[i64], CCAssignToReg<[RDI, RSI, RDX, RCX, R8 , R9 ]>>,
if (F->getAttributes().hasAttribute(Idx, Attribute::ByVal) ||
F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
+ F->getAttributes().hasAttribute(Idx, Attribute::SwiftSelf) ||
F->getAttributes().hasAttribute(Idx, Attribute::Nest))
return false;
ret void
}
+; CHECK: define void @f50(i8* swiftself)
+define void @f50(i8* swiftself)
+{
+ ret void;
+}
+
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
--- /dev/null
+; RUN: llc -verify-machineinstrs < %s -mtriple=aarch64-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s
+; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=aarch64-apple-ios | FileCheck --check-prefix=CHECK-O0 %s
+
+; Parameter with swiftself should be allocated to x9.
+define void @check_swiftself(i32* swiftself %addr0) {
+; CHECK-APPLE-LABEL: check_swiftself:
+; CHECK-O0-LABEL: check_swiftself:
+
+ %val0 = load volatile i32, i32* %addr0
+; CHECK-APPLE: ldr w{{.*}}, [x9]
+; CHECK-O0: ldr w{{.*}}, [x9]
+ ret void
+}
+
+@var8_3 = global i8 0
+declare void @take_swiftself(i8* swiftself %addr0)
+
+define void @simple_args() {
+; CHECK-APPLE-LABEL: simple_args:
+; CHECK-O0-LABEL: simple_args:
+
+ call void @take_swiftself(i8* @var8_3)
+; CHECK-APPLE: add x9,
+; CHECK-APPLE: bl {{_?}}take_swiftself
+; CHECK-O0: add x9,
+; CHECK-O0: bl {{_?}}take_swiftself
+
+ ret void
+}
--- /dev/null
+; RUN: llc -verify-machineinstrs < %s -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 | FileCheck --check-prefix=CHECK-APPLE %s
+; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 | FileCheck --check-prefix=CHECK-O0 %s
+
+; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s
+; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s
+
+; Parameter with swiftself should be allocated to r9.
+define void @check_swiftself(i32* swiftself %addr0) {
+; CHECK-APPLE-LABEL: check_swiftself:
+; CHECK-O0-LABEL: check_swiftself:
+
+ %val0 = load volatile i32, i32* %addr0
+; CHECK-APPLE: ldr r{{.*}}, [r9]
+; CHECK-O0: ldr r{{.*}}, [r9]
+ ret void
+}
+
+@var8_3 = global i8 0
+declare void @take_swiftself(i8* swiftself %addr0)
+
+define void @simple_args() {
+; CHECK-APPLE-LABEL: simple_args:
+; CHECK-O0-LABEL: simple_args:
+
+ call void @take_swiftself(i8* @var8_3)
+; CHECK-APPLE: add r9, pc
+; CHECK-APPLE: bl {{_?}}take_swiftself
+; CHECK-O0: add r9, pc
+; CHECK-O0: bl {{_?}}take_swiftself
+
+ ret void
+}
--- /dev/null
+; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
+; RUN: llc -O0 -verify-machineinstrs < %s -mtriple=x86_64-unknown-unknown | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: llc -verify-machineinstrs < %s -march=x86 -mcpu=yonah -mtriple=i386-apple-darwin | FileCheck --check-prefix=CHECK-i386 %s
+; RUN: llc -O0 -verify-machineinstrs < %s -march=x86 -mcpu=yonah -mtriple=i386-apple-darwin | FileCheck --check-prefix=CHECK-i386-O0 %s
+
+; Parameter with swiftself should be allocated to r10.
+define void @check_swiftself(i32* swiftself %addr0) {
+; CHECK-LABEL: check_swiftself:
+; CHECK-O0-LABEL: check_swiftself:
+; CHECK-i386-LABEL: check_swiftself:
+; CHECK-i386-O0-LABEL: check_swiftself:
+
+ %val0 = load volatile i32, i32* %addr0
+; CHECK: movl (%r10),
+; CHECK-O0: movl (%r10),
+; CHECK-i386: movl {{[0-9a-f]+}}(%esp)
+; CHECK-i386-O0: movl {{[0-9a-f]+}}(%esp)
+ ret void
+}
+
+@var8_3 = global i8 0
+declare void @take_swiftself(i8* swiftself %addr0)
+
+define void @simple_args() {
+; CHECK-LABEL: simple_args:
+; CHECK-O0-LABEL: simple_args:
+; CHECK-i386-LABEL: simple_args:
+; CHECK-i386-O0-LABEL: simple_args:
+
+ call void @take_swiftself(i8* @var8_3)
+; CHECK: movl {{.*}}, %r10d
+; CHECK: callq {{_?}}take_swiftself
+; CHECK-O0: movabsq {{.*}}, %r10
+; CHECK-O0: callq {{_?}}take_swiftself
+; CHECK-i386: movl {{.*}}, (%esp)
+; CHECK-i386: calll {{.*}}take_swiftself
+; CHECK-i386-O0: movl {{.*}}, (%esp)
+; CHECK-i386-O0: calll {{.*}}take_swiftself
+
+ ret void
+}
--- /dev/null
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+declare void @a(i32* swiftself %a, i32* swiftself %b)
+; CHECK: Cannot have multiple 'swiftself' parameters!