Index: llvm/include/llvm/CodeGen/TargetCallingConv.h =================================================================== --- llvm/include/llvm/CodeGen/TargetCallingConv.h +++ llvm/include/llvm/CodeGen/TargetCallingConv.h @@ -31,6 +31,7 @@ unsigned IsInReg : 1; ///< Passed in register unsigned IsSRet : 1; ///< Hidden struct-ret ptr unsigned IsByVal : 1; ///< Struct passed by value + unsigned IsByRef : 1; ///< Passed in memory unsigned IsNest : 1; ///< Nested fn static chain unsigned IsReturned : 1; ///< Always returned unsigned IsSplit : 1; @@ -43,25 +44,31 @@ unsigned IsHva : 1; ///< HVA field for unsigned IsHvaStart : 1; ///< HVA structure start unsigned IsSecArgPass : 1; ///< Second argument - unsigned ByValAlign : 4; ///< Log 2 of byval alignment + unsigned ByValOrByRefAlign : 4; ///< Log 2 of byval/byref alignment unsigned OrigAlign : 5; ///< Log 2 of original alignment unsigned IsInConsecutiveRegsLast : 1; unsigned IsInConsecutiveRegs : 1; unsigned IsCopyElisionCandidate : 1; ///< Argument copy elision candidate unsigned IsPointer : 1; - unsigned ByValSize; ///< Byval struct size + unsigned ByValOrByRefSize; ///< Byval or byref struct size unsigned PointerAddrSpace; ///< Address space of pointer argument + /// Set the alignment used by byref or byval parameters. + void setAlignImpl(Align A) { + ByValOrByRefAlign = encode(A); + assert(getNonZeroByValAlign() == A && "bitfield overflow"); + } + public: ArgFlagsTy() - : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0), - IsReturned(0), IsSplit(0), IsInAlloca(0), IsPreallocated(0), + : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsByRef(0), + IsNest(0), IsReturned(0), IsSplit(0), IsInAlloca(0), IsPreallocated(0), IsSplitEnd(0), IsSwiftSelf(0), IsSwiftError(0), IsCFGuardTarget(0), - IsHva(0), IsHvaStart(0), IsSecArgPass(0), ByValAlign(0), OrigAlign(0), - IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), - IsCopyElisionCandidate(0), IsPointer(0), ByValSize(0), + IsHva(0), IsHvaStart(0), IsSecArgPass(0), ByValOrByRefAlign(0), + OrigAlign(0), IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), + IsCopyElisionCandidate(0), IsPointer(0), ByValOrByRefSize(0), PointerAddrSpace(0) { static_assert(sizeof(*this) == 3 * sizeof(unsigned), "flags are too big"); } @@ -81,6 +88,9 @@ bool isByVal() const { return IsByVal; } void setByVal() { IsByVal = 1; } + bool isByRef() const { return IsByRef; } + void setByRef() { IsByRef = 1; } + bool isInAlloca() const { return IsInAlloca; } void setInAlloca() { IsInAlloca = 1; } @@ -131,17 +141,22 @@ LLVM_ATTRIBUTE_DEPRECATED(unsigned getByValAlign() const, "Use getNonZeroByValAlign() instead") { - MaybeAlign A = decodeMaybeAlign(ByValAlign); + MaybeAlign A = decodeMaybeAlign(ByValOrByRefAlign); return A ? A->value() : 0; } Align getNonZeroByValAlign() const { - MaybeAlign A = decodeMaybeAlign(ByValAlign); + MaybeAlign A = decodeMaybeAlign(ByValOrByRefAlign); assert(A && "ByValAlign must be defined"); return *A; } void setByValAlign(Align A) { - ByValAlign = encode(A); - assert(getNonZeroByValAlign() == A && "bitfield overflow"); + assert(isByVal() && !isByRef()); + setAlignImpl(A); + } + + void setByRefAlign(Align A) { + assert(!isByVal() && isByRef()); + setAlignImpl(A); } LLVM_ATTRIBUTE_DEPRECATED(unsigned getOrigAlign() const, @@ -157,8 +172,23 @@ assert(getNonZeroOrigAlign() == A && "bitfield overflow"); } - unsigned getByValSize() const { return ByValSize; } - void setByValSize(unsigned S) { ByValSize = S; } + unsigned getByValSize() const { + assert(isByVal() && !isByRef()); + return ByValOrByRefSize; + } + void setByValSize(unsigned S) { + assert(isByVal() && !isByRef()); + ByValOrByRefSize = S; + } + + unsigned getByRefSize() const { + assert(!isByVal() && isByRef()); + return ByValOrByRefSize; + } + void setByRefSize(unsigned S) { + assert(!isByVal() && isByRef()); + ByValOrByRefSize = S; + } unsigned getPointerAddrSpace() const { return PointerAddrSpace; } void setPointerAddrSpace(unsigned AS) { PointerAddrSpace = AS; } Index: llvm/include/llvm/CodeGen/TargetLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLowering.h +++ llvm/include/llvm/CodeGen/TargetLowering.h @@ -278,6 +278,7 @@ bool IsSRet : 1; bool IsNest : 1; bool IsByVal : 1; + bool IsByRef : 1; bool IsInAlloca : 1; bool IsPreallocated : 1; bool IsReturned : 1; @@ -290,7 +291,7 @@ ArgListEntry() : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), - IsNest(false), IsByVal(false), IsInAlloca(false), + IsNest(false), IsByVal(false), IsByRef(false), IsInAlloca(false), IsPreallocated(false), IsReturned(false), IsSwiftSelf(false), IsSwiftError(false), IsCFGuardTarget(false) {} Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9118,6 +9118,7 @@ Entry.IsSRet = true; Entry.IsNest = false; Entry.IsByVal = false; + Entry.IsByRef = false; Entry.IsReturned = false; Entry.IsSwiftSelf = false; Entry.IsSwiftError = false; @@ -9238,6 +9239,8 @@ Flags.setCFGuardTarget(); if (Args[i].IsByVal) Flags.setByVal(); + if (Args[i].IsByRef) + Flags.setByRef(); if (Args[i].IsPreallocated) { Flags.setPreallocated(); // Set the byval flag for CCAssignFn callbacks that don't know about @@ -9751,6 +9754,8 @@ Flags.setSwiftError(); if (Arg.hasAttribute(Attribute::ByVal)) Flags.setByVal(); + if (Arg.hasAttribute(Attribute::ByRef)) + Flags.setByRef(); if (Arg.hasAttribute(Attribute::InAlloca)) { Flags.setInAlloca(); // Set the byval flag for CCAssignFn callbacks that don't know about @@ -9769,27 +9774,39 @@ // preallocated handling in the various CC lowering callbacks. Flags.setByVal(); } + + Type *ArgMemTy = nullptr; if (F.getCallingConv() == CallingConv::X86_INTR) { // IA Interrupt passes frame (1st parameter) by value in the stack. - if (ArgNo == 0) + if (ArgNo == 0) { Flags.setByVal(); + // FIXME: Dependence on pointee element type. See bug 46672. + ArgMemTy = Arg.getType()->getPointerElementType(); + } } - if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated()) { - Type *ElementTy = Arg.getParamByValType(); - - // 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()); - Flags.setByValSize(FrameSize); - - unsigned FrameAlign; - if (Arg.getParamAlignment()) - FrameAlign = Arg.getParamAlignment(); - else - FrameAlign = TLI->getByValTypeAlignment(ElementTy, DL); - Flags.setByValAlign(Align(FrameAlign)); + if (Flags.isByVal() || Flags.isInAlloca() || Flags.isPreallocated() || + Flags.isByRef()) { + if (!ArgMemTy) + ArgMemTy = Arg.getPointeeInMemoryValueType(); + + uint64_t MemSize = DL.getTypeAllocSize(ArgMemTy); + + // For in-memory arguments, 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. + MaybeAlign MemAlign = Arg.getParamAlign(); + if (!MemAlign) + MemAlign = Align(TLI->getByValTypeAlignment(ArgMemTy, DL)); + + if (Flags.isByRef()) { + Flags.setByRefSize(MemSize); + Flags.setByRefAlign(*MemAlign); + } else { + Flags.setByValSize(MemSize); + Flags.setByValAlign(*MemAlign); + } } + if (Arg.hasAttribute(Attribute::Nest)) Flags.setNest(); if (NeedsRegBlock)