diff options
author | Oliver Stannard <oliver.stannard@arm.com> | 2014-05-09 14:01:47 +0000 |
---|---|---|
committer | Oliver Stannard <oliver.stannard@arm.com> | 2014-05-09 14:01:47 +0000 |
commit | e2948385b92b5aec6ac5187ca4fee367db2f0dd1 (patch) | |
tree | 8a8ce832cbbde87255db369fe716cf4c6938acdd /include | |
parent | ba148a1b8f04f20fc8e70a50585ffffadac3368d (diff) | |
download | llvm-e2948385b92b5aec6ac5187ca4fee367db2f0dd1.tar.gz llvm-e2948385b92b5aec6ac5187ca4fee367db2f0dd1.tar.bz2 llvm-e2948385b92b5aec6ac5187ca4fee367db2f0dd1.tar.xz |
ARM: HFAs must be passed in consecutive registers
When using the ARM AAPCS, HFAs (Homogeneous Floating-point Aggregates) must
be passed in a block of consecutive floating-point registers, or on the stack.
This means that unused floating-point registers cannot be back-filled with
part of an HFA, however this can currently happen. This patch, along with the
corresponding clang patch (http://reviews.llvm.org/D3083) prevents this.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208413 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r-- | include/llvm/CodeGen/CallingConvLower.h | 48 | ||||
-rw-r--r-- | include/llvm/Target/TargetCallingConv.h | 12 | ||||
-rw-r--r-- | include/llvm/Target/TargetCallingConv.td | 5 | ||||
-rw-r--r-- | include/llvm/Target/TargetLowering.h | 9 |
4 files changed, 73 insertions, 1 deletions
diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 3da7bef9fe..04af4bd4d5 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -112,6 +112,23 @@ public: return Ret; } + // There is no need to differentiate between a pending CCValAssign and other + // kinds, as they are stored in a different list. + static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, + LocInfo HTP) { + return getReg(ValNo, ValVT, 0, LocVT, HTP); + } + + void convertToReg(unsigned RegNo) { + Loc = RegNo; + isMem = false; + } + + void convertToMem(unsigned Offset) { + Loc = Offset; + isMem = true; + } + unsigned getValNo() const { return ValNo; } MVT getValVT() const { return ValVT; } @@ -164,6 +181,7 @@ private: unsigned StackOffset; SmallVector<uint32_t, 16> UsedRegs; + SmallVector<CCValAssign, 4> PendingLocs; // ByValInfo and SmallVector<ByValInfo, 4> ByValRegs: // @@ -317,6 +335,31 @@ public: return Reg; } + /// AllocateRegBlock - Attempt to allocate a block of RegsRequired consecutive + /// registers. If this is not possible, return zero. Otherwise, return the first + /// register of the block that were allocated, marking the entire block as allocated. + unsigned AllocateRegBlock(const uint16_t *Regs, unsigned NumRegs, unsigned RegsRequired) { + for (unsigned StartIdx = 0; StartIdx <= NumRegs - RegsRequired; ++StartIdx) { + bool BlockAvailable = true; + // Check for already-allocated regs in this block + for (unsigned BlockIdx = 0; BlockIdx < RegsRequired; ++BlockIdx) { + if (isAllocated(Regs[StartIdx + BlockIdx])) { + BlockAvailable = false; + break; + } + } + if (BlockAvailable) { + // Mark the entire block as allocated + for (unsigned BlockIdx = 0; BlockIdx < RegsRequired; ++BlockIdx) { + MarkAllocated(Regs[StartIdx + BlockIdx]); + } + return Regs[StartIdx]; + } + } + // No block was available + return 0; + } + /// Version of AllocateReg with list of registers to be shadowed. unsigned AllocateReg(const MCPhysReg *Regs, const MCPhysReg *ShadowRegs, unsigned NumRegs) { @@ -411,6 +454,11 @@ public: ParmContext getCallOrPrologue() const { return CallOrPrologue; } + // Get list of pending assignments + SmallVectorImpl<llvm::CCValAssign> &getPendingLocs() { + return PendingLocs; + } + private: /// MarkAllocated - Mark a register and all of its aliases as allocated. void MarkAllocated(unsigned Reg); diff --git a/include/llvm/Target/TargetCallingConv.h b/include/llvm/Target/TargetCallingConv.h index a660403b41..a0f26741a8 100644 --- a/include/llvm/Target/TargetCallingConv.h +++ b/include/llvm/Target/TargetCallingConv.h @@ -47,8 +47,12 @@ namespace ISD { static const uint64_t InAllocaOffs = 12; static const uint64_t OrigAlign = 0x1FULL<<27; static const uint64_t OrigAlignOffs = 27; - static const uint64_t ByValSize = 0xffffffffULL<<32; ///< Struct size + static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size static const uint64_t ByValSizeOffs = 32; + static const uint64_t InConsecutiveRegsLast = 0x1ULL<<62; ///< Struct size + static const uint64_t InConsecutiveRegsLastOffs = 62; + static const uint64_t InConsecutiveRegs = 0x1ULL<<63; ///< Struct size + static const uint64_t InConsecutiveRegsOffs = 63; static const uint64_t One = 1ULL; ///< 1 of this type, for shifts @@ -80,6 +84,12 @@ namespace ISD { bool isReturned() const { return Flags & Returned; } void setReturned() { Flags |= One << ReturnedOffs; } + bool isInConsecutiveRegs() const { return Flags & InConsecutiveRegs; } + void setInConsecutiveRegs() { Flags |= One << InConsecutiveRegsOffs; } + + bool isInConsecutiveRegsLast() const { return Flags & InConsecutiveRegsLast; } + void setInConsecutiveRegsLast() { Flags |= One << InConsecutiveRegsLastOffs; } + unsigned getByValAlign() const { return (unsigned) ((One << ((Flags & ByValAlign) >> ByValAlignOffs)) / 2); diff --git a/include/llvm/Target/TargetCallingConv.td b/include/llvm/Target/TargetCallingConv.td index 9d1dc3837a..8f31e08983 100644 --- a/include/llvm/Target/TargetCallingConv.td +++ b/include/llvm/Target/TargetCallingConv.td @@ -42,6 +42,11 @@ class CCIf<string predicate, CCAction A> : CCPredicateAction<A> { class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> { } +/// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs +/// parameter attribute, apply Action A. +class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> { +} + /// CCIfCC - Match if the current calling convention is 'CC'. class CCIfCC<string CC, CCAction A> : CCIf<!strconcat("State.getCallingConv() == ", CC), A> {} diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 5ce0643ea7..c03ddbc963 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -2233,6 +2233,15 @@ public: return VT.bitsLT(MinVT) ? MinVT : VT; } + /// For some targets, an LLVM struct type must be broken down into multiple + /// simple types, but the calling convention specifies that the entire struct + /// must be passed in a block of consecutive registers. + virtual bool + functionArgumentNeedsConsecutiveRegisters(Type *Ty, CallingConv::ID CallConv, + bool isVarArg) const { + return false; + } + /// Returns a 0 terminated array of registers that can be safely used as /// scratch registers. virtual const MCPhysReg *getScratchRegisters(CallingConv::ID CC) const { |