Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.
/ swift-llvm Public archive

Add 'swiftisa' argument attribute [NOT FOR CHECKIN] #62

Open
wants to merge 1 commit into
base: stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,8 @@ enum AttributeKindCodes {
ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
ATTR_KIND_ALLOC_SIZE = 51,
ATTR_KIND_WRITEONLY = 52,
ATTR_KIND_SPECULATABLE = 53
ATTR_KIND_SPECULATABLE = 53,
ATTR_KIND_SWIFT_ISA = 54,
};

enum ComdatSelectionKindCodes {
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 @@ -69,6 +69,9 @@ class Argument final : public Value {
/// Return true if this argument has the swiftself attribute.
bool hasSwiftSelfAttr() const;

/// Return true if this argument has the swiftisa attribute.
bool hasSwiftIsaAttr() const;

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

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 @@ -167,6 +167,9 @@ def SwiftError : EnumAttr<"swifterror">;
/// Argument is swift self/context.
def SwiftSelf : EnumAttr<"swiftself">;

/// Argument is swift isa pointer.
def SwiftIsa : EnumAttr<"swiftisa">;

/// Function must be in a unwind table.
def UWTable : EnumAttr<"uwtable">;

Expand Down
6 changes: 5 additions & 1 deletion include/llvm/Target/TargetCallingConv.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace ISD {
unsigned IsSplitEnd : 1; ///< Last part of a split
unsigned IsSwiftSelf : 1; ///< Swift self parameter
unsigned IsSwiftError : 1; ///< Swift error parameter
unsigned IsSwiftIsa : 1; ///< Swift isa parameter
unsigned IsHva : 1; ///< HVA field for
unsigned IsHvaStart : 1; ///< HVA structure start
unsigned IsSecArgPass : 1; ///< Second argument
Expand All @@ -53,7 +54,7 @@ namespace ISD {
ArgFlagsTy()
: IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0),
IsReturned(0), IsSplit(0), IsInAlloca(0), IsSplitEnd(0),
IsSwiftSelf(0), IsSwiftError(0), IsHva(0), IsHvaStart(0),
IsSwiftSelf(0), IsSwiftError(0), IsSwiftIsa(0), IsHva(0), IsHvaStart(0),
IsSecArgPass(0), ByValAlign(0), OrigAlign(0),
IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0),
IsCopyElisionCandidate(0), ByValSize(0) {
Expand Down Expand Up @@ -84,6 +85,9 @@ namespace ISD {
bool isSwiftError() const { return IsSwiftError; }
void setSwiftError() { IsSwiftError = 1; }

bool isSwiftIsa() const { return IsSwiftIsa; }
void setSwiftIsa() { IsSwiftIsa = 1; }

bool isHva() const { return IsHva; }
void setHva() { IsHva = 1; }

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> {
}

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

/// CCIfSwiftError - If the current argument has swifterror parameter attribute,
/// apply Action A.
class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> {
Expand Down
3 changes: 2 additions & 1 deletion include/llvm/Target/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,13 @@ class TargetLoweringBase {
bool IsReturned : 1;
bool IsSwiftSelf : 1;
bool IsSwiftError : 1;
bool IsSwiftIsa : 1;
uint16_t Alignment = 0;

ArgListEntry()
: IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false),
IsNest(false), IsByVal(false), IsInAlloca(false), IsReturned(false),
IsSwiftSelf(false), IsSwiftError(false) {}
IsSwiftSelf(false), IsSwiftError(false), IsSwiftIsa(false) {}

void setAttributes(ImmutableCallSite *CS, unsigned ArgIdx);
};
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(sanitize_memory);
KEYWORD(swifterror);
KEYWORD(swiftself);
KEYWORD(swiftisa);
KEYWORD(uwtable);
KEYWORD(writeonly);
KEYWORD(zeroext);
Expand Down
3 changes: 3 additions & 0 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_swiftisa:
HaveError |=
Error(Lex.getLoc(),
"invalid use of parameter-only attribute on a function");
Expand Down Expand Up @@ -1425,6 +1426,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
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_swiftisa: B.addAttribute(Attribute::SwiftIsa); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;

Expand Down Expand Up @@ -1515,6 +1517,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_sret:
case lltok::kw_swifterror:
case lltok::kw_swiftself:
case lltok::kw_swiftisa:
HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
break;

Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ enum Kind {
kw_sanitize_memory,
kw_swifterror,
kw_swiftself,
kw_swiftisa,
kw_uwtable,
kw_writeonly,
kw_zeroext,
Expand Down
3 changes: 3 additions & 0 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,7 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
case Attribute::SwiftError: return 1ULL << 52;
case Attribute::WriteOnly: return 1ULL << 53;
case Attribute::Speculatable: return 1ULL << 54;
case Attribute::SwiftIsa: return 1ULL << 55;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
Expand Down Expand Up @@ -1348,6 +1349,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::SwiftError;
case bitc::ATTR_KIND_SWIFT_SELF:
return Attribute::SwiftSelf;
case bitc::ATTR_KIND_SWIFT_ISA:
return Attribute::SwiftIsa;
case bitc::ATTR_KIND_UW_TABLE:
return Attribute::UWTable;
case bitc::ATTR_KIND_WRITEONLY:
Expand Down
2 changes: 2 additions & 0 deletions lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SWIFT_ERROR;
case Attribute::SwiftSelf:
return bitc::ATTR_KIND_SWIFT_SELF;
case Attribute::SwiftIsa:
return bitc::ATTR_KIND_SWIFT_ISA;
case Attribute::UWTable:
return bitc::ATTR_KIND_UW_TABLE;
case Attribute::WriteOnly:
Expand Down
2 changes: 2 additions & 0 deletions lib/CodeGen/GlobalISel/CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
Arg.Flags.setSwiftSelf();
if (Attrs.hasAttribute(OpIdx, Attribute::SwiftError))
Arg.Flags.setSwiftError();
if (Attrs.hasAttribute(OpIdx, Attribute::SwiftIsa))
Arg.Flags.setSwiftIsa();
if (Attrs.hasAttribute(OpIdx, Attribute::ByVal))
Arg.Flags.setByVal();
if (Attrs.hasAttribute(OpIdx, Attribute::InAlloca))
Expand Down
2 changes: 2 additions & 0 deletions lib/CodeGen/SelectionDAG/FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,8 @@ bool FastISel::lowerCallTo(CallLoweringInfo &CLI) {
Flags.setSwiftSelf();
if (Arg.IsSwiftError)
Flags.setSwiftError();
if (Arg.IsSwiftIsa)
Flags.setSwiftIsa();
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 @@ -8021,6 +8021,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
Entry.IsReturned = false;
Entry.IsSwiftSelf = false;
Entry.IsSwiftError = false;
Entry.IsSwiftIsa = false;
Entry.Alignment = Align;
CLI.getArgs().insert(CLI.getArgs().begin(), Entry);
CLI.RetTy = Type::getVoidTy(CLI.RetTy->getContext());
Expand Down Expand Up @@ -8113,6 +8114,8 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const {
Flags.setSwiftSelf();
if (Args[i].IsSwiftError)
Flags.setSwiftError();
if (Args[i].IsSwiftIsa)
Flags.setSwiftIsa();
if (Args[i].IsByVal)
Flags.setByVal();
if (Args[i].IsInAlloca) {
Expand Down Expand Up @@ -8595,6 +8598,8 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
Flags.setSwiftSelf();
if (Arg.hasAttribute(Attribute::SwiftError))
Flags.setSwiftError();
if (Arg.hasAttribute(Attribute::SwiftIsa))
Flags.setSwiftIsa();
if (Arg.hasAttribute(Attribute::ByVal))
Flags.setByVal();
if (Arg.hasAttribute(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 @@ -110,6 +110,7 @@ void TargetLoweringBase::ArgListEntry::setAttributes(ImmutableCallSite *CS,
IsReturned = CS->paramHasAttr(ArgIdx, Attribute::Returned);
IsSwiftSelf = CS->paramHasAttr(ArgIdx, Attribute::SwiftSelf);
IsSwiftError = CS->paramHasAttr(ArgIdx, Attribute::SwiftError);
IsSwiftIsa = CS->paramHasAttr(ArgIdx, Attribute::SwiftIsa);
Alignment = CS->getParamAlignment(ArgIdx);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "swifterror";
if (hasAttribute(Attribute::SwiftSelf))
return "swiftself";
if (hasAttribute(Attribute::SwiftIsa))
return "swiftisa";
if (hasAttribute(Attribute::InaccessibleMemOnly))
return "inaccessiblememonly";
if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly))
Expand Down
11 changes: 9 additions & 2 deletions lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,7 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
bool SawReturned = false;
bool SawSRet = false;
bool SawSwiftSelf = false;
bool SawSwiftIsa = false;
bool SawSwiftError = false;

// Verify return value attributes.
Expand All @@ -1540,10 +1541,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
!RetAttrs.hasAttribute(Attribute::Returned) &&
!RetAttrs.hasAttribute(Attribute::InAlloca) &&
!RetAttrs.hasAttribute(Attribute::SwiftSelf) &&
!RetAttrs.hasAttribute(Attribute::SwiftIsa) &&
!RetAttrs.hasAttribute(Attribute::SwiftError)),
"Attributes 'byval', 'inalloca', 'nest', 'sret', 'nocapture', "
"'returned', 'swiftself', and 'swifterror' do not apply to return "
"values!",
"'returned', 'swiftself', 'swiftisa' and 'swifterror' do not "
"apply to return values!",
V);
Assert((!RetAttrs.hasAttribute(Attribute::ReadOnly) &&
!RetAttrs.hasAttribute(Attribute::WriteOnly) &&
Expand Down Expand Up @@ -1586,6 +1588,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
SawSwiftSelf = true;
}

if (ArgAttrs.hasAttribute(Attribute::SwiftIsa)) {
Assert(!SawSwiftIsa, "Cannot have multiple 'swiftisa' parameters!", V);
SawSwiftIsa = true;
}

if (ArgAttrs.hasAttribute(Attribute::SwiftError)) {
Assert(!SawSwiftError, "Cannot have multiple 'swifterror' parameters!",
V);
Expand Down
3 changes: 3 additions & 0 deletions lib/Target/AArch64/AArch64CallingConvention.td
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def CC_AArch64_AAPCS : CallingConv<[
// A SwiftError is passed in X21.
CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X21], [W21]>>>,

// A SwiftIsa is passed in X22.
CCIfSwiftIsa<CCIfType<[i64], CCAssignToRegWithShadow<[X22], [W22]>>>,

CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>,

// Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers,
Expand Down
2 changes: 1 addition & 1 deletion lib/Target/AArch64/AArch64FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3177,7 +3177,7 @@ bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {

for (auto Flag : CLI.OutFlags)
if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal() ||
Flag.isSwiftSelf() || Flag.isSwiftError())
Flag.isSwiftSelf() || Flag.isSwiftError() || Flag.isSwiftIsa())
return false;

// Set up the argument vectors.
Expand Down
2 changes: 1 addition & 1 deletion lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3333,7 +3333,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,

if (VA.isRegLoc()) {
if (realArgIdx == 0 && Flags.isReturned() && !Flags.isSwiftSelf() &&
Outs[0].VT == MVT::i64) {
!Flags.isSwiftIsa() && Outs[0].VT == MVT::i64) {
assert(VA.getLocVT() == MVT::i64 &&
"unexpected calling convention register assignment");
assert(!Ins.empty() && Ins[0].VT == MVT::i64 &&
Expand Down
3 changes: 3 additions & 0 deletions lib/Target/ARM/ARMCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def CC_ARM_APCS : CallingConv<[

CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,

// Pass SwiftIsa in a callee saved register.
CCIfSwiftIsa<CCIfType<[i32], CCAssignToReg<[R11]>>>,

// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,

Expand Down
2 changes: 1 addition & 1 deletion lib/Target/ARM/ARMISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
}
} else if (VA.isRegLoc()) {
if (realArgIdx == 0 && Flags.isReturned() && !Flags.isSwiftSelf() &&
Outs[0].VT == MVT::i32) {
!Flags.isSwiftIsa() && Outs[0].VT == MVT::i32) {
assert(VA.getLocVT() == MVT::i32 &&
"unexpected calling convention register assignment");
assert(!Ins.empty() && Ins[0].VT == MVT::i32 &&
Expand Down
3 changes: 2 additions & 1 deletion lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,8 @@ static bool canUseSiblingCall(const CCState &ArgCCInfo,
unsigned Reg = VA.getLocReg();
if (Reg == SystemZ::R6H || Reg == SystemZ::R6L || Reg == SystemZ::R6D)
return false;
if (Outs[I].Flags.isSwiftSelf() || Outs[I].Flags.isSwiftError())
if (Outs[I].Flags.isSwiftSelf() || Outs[I].Flags.isSwiftError() ||
Outs[I].Flags.isSwiftIsa())
return false;
}
return true;
Expand Down
1 change: 1 addition & 0 deletions lib/Target/X86/X86CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ bool X86CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
Arg.hasAttribute(Attribute::StructRet) ||
Arg.hasAttribute(Attribute::SwiftSelf) ||
Arg.hasAttribute(Attribute::SwiftError) ||
Arg.hasAttribute(Attribute::SwiftIsa) ||
Arg.hasAttribute(Attribute::Nest))
return false;

Expand Down
3 changes: 3 additions & 0 deletions lib/Target/X86/X86CallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ def CC_X86_64_C : CallingConv<[
CCIfNest<CCIfSubtarget<"isTarget64BitILP32()", CCAssignToReg<[R10D]>>>,
CCIfNest<CCAssignToReg<[R10]>>,

// Pass SwiftIsa in a callee saved register.
CCIfSwiftIsa<CCIfType<[i64], CCAssignToReg<[R14]>>>,

// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[R13]>>>,

Expand Down
1 change: 1 addition & 0 deletions lib/Target/X86/X86FastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3051,6 +3051,7 @@ bool X86FastISel::fastLowerArguments() {
Arg.hasAttribute(Attribute::StructRet) ||
Arg.hasAttribute(Attribute::SwiftSelf) ||
Arg.hasAttribute(Attribute::SwiftError) ||
Arg.hasAttribute(Attribute::SwiftIsa) ||
Arg.hasAttribute(Attribute::Nest))
return false;

Expand Down
6 changes: 6 additions & 0 deletions test/Bitcode/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ define i32 @f52(i32, i8** swifterror)
ret i32 0
}

; CHECK: define void @f52a(i8* swiftisa)
define void @f52a(i8* swiftisa)
{
ret void;
}

%swift_error = type {i64, i8}
declare float @foo(%swift_error** swifterror %error_ptr_ref)

Expand Down
41 changes: 41 additions & 0 deletions test/CodeGen/X86/swiftisa.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown-unknown -o - %s | FileCheck --check-prefix=CHECK --check-prefix=OPT %s
; RUN: llc -O0 -verify-machineinstrs -mtriple=x86_64-unknown-unknown -o - %s | FileCheck %s

; Parameter with swiftisa should be allocated to r14.
; CHECK-LABEL: swiftisa_param:
; CHECK: movq %r14, %rax
define i8 *@swiftisa_param(i8* swiftisa %addr0) {
ret i8 *%addr0
}

; Check that r14 is used to pass a swiftisa argument.
; CHECK-LABEL: call_swiftisa:
; CHECK: movq %rdi, %r14
; CHECK: callq {{_?}}swiftisa_param
define i8 *@call_swiftisa(i8* %arg) {
%res = call i8 *@swiftisa_param(i8* swiftisa %arg)
ret i8 *%res
}

; r14 should be saved by the callee even if used for swiftisa
; CHECK-LABEL: swiftisa_clobber:
; CHECK: pushq %r14
; ...
; CHECK: popq %r14
define i8 *@swiftisa_clobber(i8* swiftisa %addr0) {
call void asm sideeffect "nop", "~{r14}"()
ret i8 *%addr0
}

; Demonstrate that we do not need any movs when calling multiple functions
; with swiftisa argument.
; CHECK-LABEL: swiftisa_passthrough:
; OPT-NOT: mov{{.*}}r14
; OPT: callq {{_?}}swiftisa_param
; OPT-NOT: mov{{.*}}r14
; OPT-NEXT: callq {{_?}}swiftisa_param
define void @swiftisa_passthrough(i8* swiftisa %addr0) {
call i8 *@swiftisa_param(i8* swiftisa %addr0)
call i8 *@swiftisa_param(i8* swiftisa %addr0)
ret void
}
4 changes: 4 additions & 0 deletions test/Verifier/swiftisa.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s

declare void @a(i32* swiftisa %a, i32* swiftisa %b)
; CHECK: Cannot have multiple 'swiftisa' parameters!