<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, May 9, 2014 at 7:25 PM, David Blaikie <span dir="ltr"><<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">On Fri, May 9, 2014 at 9:29 AM, James Molloy <<a href="mailto:james@jamesmolloy.co.uk">james@jamesmolloy.co.uk</a>> wrote:<br>

> Hi,<br>
><br>
> I've fixed the test to only run with an asserts build - builds should now be<br>
> green again.<br>
<br>
</div>Why does this test require asserts?<br></blockquote><div><br></div><div>Because it uses <span style="font-family:arial,sans-serif;font-size:13px"> </span><span style="font-family:arial,sans-serif;font-size:13px">llc -debug-only</span> flag, which is conditionally compiled on !NDEBUG.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><div class="h5"><br>
><br>
> Cheers,<br>
><br>
> James<br>
><br>
><br>
> On 9 May 2014 17:12, Alexander Kornienko <<a href="mailto:alexfh@google.com">alexfh@google.com</a>> wrote:<br>
>><br>
>> This breaks our builds as well. Please fix or revert.<br>
>><br>
>><br>
>><br>
>> On Fri, May 9, 2014 at 6:05 PM, Aaron Ballman <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>><br>
>> wrote:<br>
>>><br>
>>> FYI: This appears to have broken at least one of the bots:<br>
>>><br>
>>> <a href="http://bb.pgr.jp/builders/cmake-llvm-x86_64-linux/builds/12820" target="_blank">http://bb.pgr.jp/builders/cmake-llvm-x86_64-linux/builds/12820</a><br>
>>><br>
>>> ~Aaron<br>
>>><br>
>>> On Fri, May 9, 2014 at 10:01 AM, Oliver Stannard<br>
>>> <<a href="mailto:oliver.stannard@arm.com">oliver.stannard@arm.com</a>> wrote:<br>
>>> > Author: olista01<br>
>>> > Date: Fri May  9 09:01:47 2014<br>
>>> > New Revision: 208413<br>
>>> ><br>
>>> > URL: <a href="http://llvm.org/viewvc/llvm-project?rev=208413&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=208413&view=rev</a><br>
>>> > Log:<br>
>>> > ARM: HFAs must be passed in consecutive registers<br>
>>> ><br>
>>> > When using the ARM AAPCS, HFAs (Homogeneous Floating-point Aggregates)<br>
>>> > must<br>
>>> > be passed in a block of consecutive floating-point registers, or on the<br>
>>> > stack.<br>
>>> > This means that unused floating-point registers cannot be back-filled<br>
>>> > with<br>
>>> > part of an HFA, however this can currently happen. This patch, along<br>
>>> > with the<br>
>>> > corresponding clang patch (<a href="http://reviews.llvm.org/D3083" target="_blank">http://reviews.llvm.org/D3083</a>) prevents<br>
>>> > this.<br>
>>> ><br>
>>> ><br>
>>> > Added:<br>
>>> >     llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll<br>
>>> >     llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll<br>
>>> > Modified:<br>
>>> >     llvm/trunk/include/llvm/CodeGen/CallingConvLower.h<br>
>>> >     llvm/trunk/include/llvm/Target/TargetCallingConv.h<br>
>>> >     llvm/trunk/include/llvm/Target/TargetCallingConv.td<br>
>>> >     llvm/trunk/include/llvm/Target/TargetLowering.h<br>
>>> >     llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp<br>
>>> >     llvm/trunk/lib/Target/ARM/ARMCallingConv.h<br>
>>> >     llvm/trunk/lib/Target/ARM/ARMCallingConv.td<br>
>>> >     llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp<br>
>>> >     llvm/trunk/lib/Target/ARM/ARMISelLowering.h<br>
>>> ><br>
>>> > Modified: llvm/trunk/include/llvm/CodeGen/CallingConvLower.h<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/CallingConvLower.h?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/CallingConvLower.h?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/include/llvm/CodeGen/CallingConvLower.h (original)<br>
>>> > +++ llvm/trunk/include/llvm/CodeGen/CallingConvLower.h Fri May  9<br>
>>> > 09:01:47 2014<br>
>>> > @@ -112,6 +112,23 @@ public:<br>
>>> >      return Ret;<br>
>>> >    }<br>
>>> ><br>
>>> > +  // There is no need to differentiate between a pending CCValAssign<br>
>>> > and other<br>
>>> > +  // kinds, as they are stored in a different list.<br>
>>> > +  static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT,<br>
>>> > +                                LocInfo HTP) {<br>
>>> > +    return getReg(ValNo, ValVT, 0, LocVT, HTP);<br>
>>> > +  }<br>
>>> > +<br>
>>> > +  void convertToReg(unsigned RegNo) {<br>
>>> > +    Loc = RegNo;<br>
>>> > +    isMem = false;<br>
>>> > +  }<br>
>>> > +<br>
>>> > +  void convertToMem(unsigned Offset) {<br>
>>> > +    Loc = Offset;<br>
>>> > +    isMem = true;<br>
>>> > +  }<br>
>>> > +<br>
>>> >    unsigned getValNo() const { return ValNo; }<br>
>>> >    MVT getValVT() const { return ValVT; }<br>
>>> ><br>
>>> > @@ -164,6 +181,7 @@ private:<br>
>>> ><br>
>>> >    unsigned StackOffset;<br>
>>> >    SmallVector<uint32_t, 16> UsedRegs;<br>
>>> > +  SmallVector<CCValAssign, 4> PendingLocs;<br>
>>> ><br>
>>> >    // ByValInfo and SmallVector<ByValInfo, 4> ByValRegs:<br>
>>> >    //<br>
>>> > @@ -317,6 +335,31 @@ public:<br>
>>> >      return Reg;<br>
>>> >    }<br>
>>> ><br>
>>> > +  /// AllocateRegBlock - Attempt to allocate a block of RegsRequired<br>
>>> > consecutive<br>
>>> > +  /// registers. If this is not possible, return zero. Otherwise,<br>
>>> > return the first<br>
>>> > +  /// register of the block that were allocated, marking the entire<br>
>>> > block as allocated.<br>
>>> > +  unsigned AllocateRegBlock(const uint16_t *Regs, unsigned NumRegs,<br>
>>> > unsigned RegsRequired) {<br>
>>> > +    for (unsigned StartIdx = 0; StartIdx <= NumRegs - RegsRequired;<br>
>>> > ++StartIdx) {<br>
>>> > +      bool BlockAvailable = true;<br>
>>> > +      // Check for already-allocated regs in this block<br>
>>> > +      for (unsigned BlockIdx = 0; BlockIdx < RegsRequired; ++BlockIdx)<br>
>>> > {<br>
>>> > +        if (isAllocated(Regs[StartIdx + BlockIdx])) {<br>
>>> > +          BlockAvailable = false;<br>
>>> > +          break;<br>
>>> > +        }<br>
>>> > +      }<br>
>>> > +      if (BlockAvailable) {<br>
>>> > +        // Mark the entire block as allocated<br>
>>> > +        for (unsigned BlockIdx = 0; BlockIdx < RegsRequired;<br>
>>> > ++BlockIdx) {<br>
>>> > +          MarkAllocated(Regs[StartIdx + BlockIdx]);<br>
>>> > +        }<br>
>>> > +        return Regs[StartIdx];<br>
>>> > +      }<br>
>>> > +    }<br>
>>> > +    // No block was available<br>
>>> > +    return 0;<br>
>>> > +  }<br>
>>> > +<br>
>>> >    /// Version of AllocateReg with list of registers to be shadowed.<br>
>>> >    unsigned AllocateReg(const MCPhysReg *Regs, const MCPhysReg<br>
>>> > *ShadowRegs,<br>
>>> >                         unsigned NumRegs) {<br>
>>> > @@ -411,6 +454,11 @@ public:<br>
>>> ><br>
>>> >    ParmContext getCallOrPrologue() const { return CallOrPrologue; }<br>
>>> ><br>
>>> > +  // Get list of pending assignments<br>
>>> > +  SmallVectorImpl<llvm::CCValAssign> &getPendingLocs() {<br>
>>> > +    return PendingLocs;<br>
>>> > +  }<br>
>>> > +<br>
>>> >  private:<br>
>>> >    /// MarkAllocated - Mark a register and all of its aliases as<br>
>>> > allocated.<br>
>>> >    void MarkAllocated(unsigned Reg);<br>
>>> ><br>
>>> > Modified: llvm/trunk/include/llvm/Target/TargetCallingConv.h<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetCallingConv.h?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetCallingConv.h?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/include/llvm/Target/TargetCallingConv.h (original)<br>
>>> > +++ llvm/trunk/include/llvm/Target/TargetCallingConv.h Fri May  9<br>
>>> > 09:01:47 2014<br>
>>> > @@ -47,8 +47,12 @@ namespace ISD {<br>
>>> >      static const uint64_t InAllocaOffs   = 12;<br>
>>> >      static const uint64_t OrigAlign      = 0x1FULL<<27;<br>
>>> >      static const uint64_t OrigAlignOffs  = 27;<br>
>>> > -    static const uint64_t ByValSize      = 0xffffffffULL<<32; ///<<br>
>>> > Struct size<br>
>>> > +    static const uint64_t ByValSize      = 0x3fffffffULL<<32; ///<<br>
>>> > Struct size<br>
>>> >      static const uint64_t ByValSizeOffs  = 32;<br>
>>> > +    static const uint64_t InConsecutiveRegsLast      = 0x1ULL<<62;<br>
>>> > ///< Struct size<br>
>>> > +    static const uint64_t InConsecutiveRegsLastOffs  = 62;<br>
>>> > +    static const uint64_t InConsecutiveRegs      = 0x1ULL<<63; ///<<br>
>>> > Struct size<br>
>>> > +    static const uint64_t InConsecutiveRegsOffs  = 63;<br>
>>> ><br>
>>> >      static const uint64_t One            = 1ULL; ///< 1 of this type,<br>
>>> > for shifts<br>
>>> ><br>
>>> > @@ -80,6 +84,12 @@ namespace ISD {<br>
>>> >      bool isReturned()  const { return Flags & Returned; }<br>
>>> >      void setReturned() { Flags |= One << ReturnedOffs; }<br>
>>> ><br>
>>> > +    bool isInConsecutiveRegs()  const { return Flags &<br>
>>> > InConsecutiveRegs; }<br>
>>> > +    void setInConsecutiveRegs() { Flags |= One <<<br>
>>> > InConsecutiveRegsOffs; }<br>
>>> > +<br>
>>> > +    bool isInConsecutiveRegsLast()  const { return Flags &<br>
>>> > InConsecutiveRegsLast; }<br>
>>> > +    void setInConsecutiveRegsLast() { Flags |= One <<<br>
>>> > InConsecutiveRegsLastOffs; }<br>
>>> > +<br>
>>> >      unsigned getByValAlign() const {<br>
>>> >        return (unsigned)<br>
>>> >          ((One << ((Flags & ByValAlign) >> ByValAlignOffs)) / 2);<br>
>>> ><br>
>>> > Modified: llvm/trunk/include/llvm/Target/TargetCallingConv.td<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetCallingConv.td?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetCallingConv.td?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/include/llvm/Target/TargetCallingConv.td (original)<br>
>>> > +++ llvm/trunk/include/llvm/Target/TargetCallingConv.td Fri May  9<br>
>>> > 09:01:47 2014<br>
>>> > @@ -42,6 +42,11 @@ class CCIf<string predicate, CCAction A><br>
>>> >  class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> {<br>
>>> >  }<br>
>>> ><br>
>>> > +/// CCIfConsecutiveRegs - If the current argument has<br>
>>> > InConsecutiveRegs<br>
>>> > +/// parameter attribute, apply Action A.<br>
>>> > +class CCIfConsecutiveRegs<CCAction A> :<br>
>>> > CCIf<"ArgFlags.isInConsecutiveRegs()", A> {<br>
>>> > +}<br>
>>> > +<br>
>>> >  /// CCIfCC - Match if the current calling convention is 'CC'.<br>
>>> >  class CCIfCC<string CC, CCAction A><br>
>>> >    : CCIf<!strconcat("State.getCallingConv() == ", CC), A> {}<br>
>>> ><br>
>>> > Modified: llvm/trunk/include/llvm/Target/TargetLowering.h<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/include/llvm/Target/TargetLowering.h (original)<br>
>>> > +++ llvm/trunk/include/llvm/Target/TargetLowering.h Fri May  9 09:01:47<br>
>>> > 2014<br>
>>> > @@ -2233,6 +2233,15 @@ public:<br>
>>> >      return VT.bitsLT(MinVT) ? MinVT : VT;<br>
>>> >    }<br>
>>> ><br>
>>> > +  /// For some targets, an LLVM struct type must be broken down into<br>
>>> > multiple<br>
>>> > +  /// simple types, but the calling convention specifies that the<br>
>>> > entire struct<br>
>>> > +  /// must be passed in a block of consecutive registers.<br>
>>> > +  virtual bool<br>
>>> > +  functionArgumentNeedsConsecutiveRegisters(Type *Ty, CallingConv::ID<br>
>>> > CallConv,<br>
>>> > +                                            bool isVarArg) const {<br>
>>> > +    return false;<br>
>>> > +  }<br>
>>> > +<br>
>>> >    /// Returns a 0 terminated array of registers that can be safely<br>
>>> > used as<br>
>>> >    /// scratch registers.<br>
>>> >    virtual const MCPhysReg *getScratchRegisters(CallingConv::ID CC)<br>
>>> > const {<br>
>>> ><br>
>>> > Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp<br>
>>> > (original)<br>
>>> > +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Fri May<br>
>>> > 9 09:01:47 2014<br>
>>> > @@ -7128,8 +7128,13 @@ TargetLowering::LowerCallTo(TargetLoweri<br>
>>> >    for (unsigned i = 0, e = Args.size(); i != e; ++i) {<br>
>>> >      SmallVector<EVT, 4> ValueVTs;<br>
>>> >      ComputeValueVTs(*this, Args[i].Ty, ValueVTs);<br>
>>> > -    for (unsigned Value = 0, NumValues = ValueVTs.size();<br>
>>> > -         Value != NumValues; ++Value) {<br>
>>> > +    Type *FinalType = Args[i].Ty;<br>
>>> > +    if (Args[i].isByVal)<br>
>>> > +      FinalType = cast<PointerType>(Args[i].Ty)->getElementType();<br>
>>> > +    bool NeedsRegBlock = functionArgumentNeedsConsecutiveRegisters(<br>
>>> > +        FinalType, CLI.CallConv, CLI.IsVarArg);<br>
>>> > +    for (unsigned Value = 0, NumValues = ValueVTs.size(); Value !=<br>
>>> > NumValues;<br>
>>> > +         ++Value) {<br>
>>> >        EVT VT = ValueVTs[Value];<br>
>>> >        Type *ArgTy = VT.getTypeForEVT(CLI.RetTy->getContext());<br>
>>> >        SDValue Op = SDValue(Args[i].Node.getNode(),<br>
>>> > @@ -7171,6 +7176,11 @@ TargetLowering::LowerCallTo(TargetLoweri<br>
>>> >        }<br>
>>> >        if (Args[i].isNest)<br>
>>> >          Flags.setNest();<br>
>>> > +      if (NeedsRegBlock) {<br>
>>> > +        Flags.setInConsecutiveRegs();<br>
>>> > +        if (Value == NumValues - 1)<br>
>>> > +          Flags.setInConsecutiveRegsLast();<br>
>>> > +      }<br>
>>> >        Flags.setOrigAlign(OriginalAlignment);<br>
>>> ><br>
>>> >        MVT PartVT = getRegisterType(CLI.RetTy->getContext(), VT);<br>
>>> > @@ -7356,6 +7366,11 @@ void SelectionDAGISel::LowerArguments(co<br>
>>> >      ComputeValueVTs(*TLI, I->getType(), ValueVTs);<br>
>>> >      bool isArgValueUsed = !I->use_empty();<br>
>>> >      unsigned PartBase = 0;<br>
>>> > +    Type *FinalType = I->getType();<br>
>>> > +    if (F.getAttributes().hasAttribute(Idx, Attribute::ByVal))<br>
>>> > +      FinalType = cast<PointerType>(FinalType)->getElementType();<br>
>>> > +    bool NeedsRegBlock =<br>
>>> > TLI->functionArgumentNeedsConsecutiveRegisters(<br>
>>> > +        FinalType, F.getCallingConv(), F.isVarArg());<br>
>>> >      for (unsigned Value = 0, NumValues = ValueVTs.size();<br>
>>> >           Value != NumValues; ++Value) {<br>
>>> >        EVT VT = ValueVTs[Value];<br>
>>> > @@ -7397,6 +7412,11 @@ void SelectionDAGISel::LowerArguments(co<br>
>>> >        }<br>
>>> >        if (F.getAttributes().hasAttribute(Idx, Attribute::Nest))<br>
>>> >          Flags.setNest();<br>
>>> > +      if (NeedsRegBlock) {<br>
>>> > +        Flags.setInConsecutiveRegs();<br>
>>> > +        if (Value == NumValues - 1)<br>
>>> > +          Flags.setInConsecutiveRegsLast();<br>
>>> > +      }<br>
>>> >        Flags.setOrigAlign(OriginalAlignment);<br>
>>> ><br>
>>> >        MVT RegisterVT = TLI->getRegisterType(*CurDAG->getContext(),<br>
>>> > VT);<br>
>>> ><br>
>>> > Modified: llvm/trunk/lib/Target/ARM/ARMCallingConv.h<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCallingConv.h?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCallingConv.h?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/lib/Target/ARM/ARMCallingConv.h (original)<br>
>>> > +++ llvm/trunk/lib/Target/ARM/ARMCallingConv.h Fri May  9 09:01:47 2014<br>
>>> > @@ -160,6 +160,96 @@ static bool RetCC_ARM_AAPCS_Custom_f64(u<br>
>>> >                                     State);<br>
>>> >  }<br>
>>> ><br>
>>> > +static const uint16_t SRegList[] = { ARM::S0,  ARM::S1,  ARM::S2,<br>
>>> > ARM::S3,<br>
>>> > +                                     ARM::S4,  ARM::S5,  ARM::S6,<br>
>>> > ARM::S7,<br>
>>> > +                                     ARM::S8,  ARM::S9,  ARM::S10,<br>
>>> > ARM::S11,<br>
>>> > +                                     ARM::S12, ARM::S13, ARM::S14,<br>
>>> > ARM::S15 };<br>
>>> > +static const uint16_t DRegList[] = { ARM::D0, ARM::D1, ARM::D2,<br>
>>> > ARM::D3,<br>
>>> > +                                     ARM::D4, ARM::D5, ARM::D6,<br>
>>> > ARM::D7 };<br>
>>> > +static const uint16_t QRegList[] = { ARM::Q0, ARM::Q1, ARM::Q2,<br>
>>> > ARM::Q3 };<br>
>>> > +<br>
>>> > +// Allocate part of an AAPCS HFA or HVA. We assume that each member of<br>
>>> > the HA<br>
>>> > +// has InConsecutiveRegs set, and that the last member also has<br>
>>> > +// InConsecutiveRegsLast set. We must process all members of the HA<br>
>>> > before<br>
>>> > +// we can allocate it, as we need to know the total number of<br>
>>> > registers that<br>
>>> > +// will be needed in order to (attempt to) allocate a contiguous<br>
>>> > block.<br>
>>> > +static bool CC_ARM_AAPCS_Custom_HA(unsigned &ValNo, MVT &ValVT, MVT<br>
>>> > &LocVT,<br>
>>> > +                                   CCValAssign::LocInfo &LocInfo,<br>
>>> > +                                   ISD::ArgFlagsTy &ArgFlags, CCState<br>
>>> > &State) {<br>
>>> > +  SmallVectorImpl<CCValAssign> &PendingHAMembers =<br>
>>> > State.getPendingLocs();<br>
>>> > +<br>
>>> > +  // AAPCS HFAs must have 1-4 elements, all of the same type<br>
>>> > +  assert(PendingHAMembers.size() < 4);<br>
>>> > +  if (PendingHAMembers.size() > 0)<br>
>>> > +    assert(PendingHAMembers[0].getLocVT() == LocVT);<br>
>>> > +<br>
>>> > +  // Add the argument to the list to be allocated once we know the<br>
>>> > size of the<br>
>>> > +  // HA<br>
>>> > +  PendingHAMembers.push_back(<br>
>>> > +      CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));<br>
>>> > +<br>
>>> > +  if (ArgFlags.isInConsecutiveRegsLast()) {<br>
>>> > +    assert(PendingHAMembers.size() > 0 && PendingHAMembers.size() <= 4<br>
>>> > &&<br>
>>> > +           "Homogeneous aggregates must have between 1 and 4<br>
>>> > members");<br>
>>> > +<br>
>>> > +    // Try to allocate a contiguous block of registers, each of the<br>
>>> > correct<br>
>>> > +    // size to hold one member.<br>
>>> > +    const uint16_t *RegList;<br>
>>> > +    unsigned NumRegs;<br>
>>> > +    switch (LocVT.SimpleTy) {<br>
>>> > +    case MVT::f32:<br>
>>> > +      RegList = SRegList;<br>
>>> > +      NumRegs = 16;<br>
>>> > +      break;<br>
>>> > +    case MVT::f64:<br>
>>> > +      RegList = DRegList;<br>
>>> > +      NumRegs = 8;<br>
>>> > +      break;<br>
>>> > +    case MVT::v2f64:<br>
>>> > +      RegList = QRegList;<br>
>>> > +      NumRegs = 4;<br>
>>> > +      break;<br>
>>> > +    default:<br>
>>> > +      llvm_unreachable("Unexpected member type for HA");<br>
>>> > +      break;<br>
>>> > +    }<br>
>>> > +<br>
>>> > +    unsigned RegResult =<br>
>>> > +        State.AllocateRegBlock(RegList, NumRegs,<br>
>>> > PendingHAMembers.size());<br>
>>> > +<br>
>>> > +    if (RegResult) {<br>
>>> > +      for (SmallVectorImpl<CCValAssign>::iterator It =<br>
>>> > PendingHAMembers.begin();<br>
>>> > +           It != PendingHAMembers.end(); ++It) {<br>
>>> > +        It->convertToReg(RegResult);<br>
>>> > +        State.addLoc(*It);<br>
>>> > +        ++RegResult;<br>
>>> > +      }<br>
>>> > +      PendingHAMembers.clear();<br>
>>> > +      return true;<br>
>>> > +    }<br>
>>> > +<br>
>>> > +    // Register allocation failed, fall back to the stack<br>
>>> > +<br>
>>> > +    // Mark all VFP regs as unavailable (AAPCS rule C.2.vfp)<br>
>>> > +    for (unsigned regNo = 0; regNo < 16; ++regNo)<br>
>>> > +      State.AllocateReg(SRegList[regNo]);<br>
>>> > +<br>
>>> > +    unsigned Size = LocVT.getSizeInBits() / 8;<br>
>>> > +    unsigned Align = LocVT.SimpleTy == MVT::v2f64 ? 8 : Size;<br>
>>> > +<br>
>>> > +    for (auto It : PendingHAMembers) {<br>
>>> > +      It.convertToMem(State.AllocateStack(Size, Align));<br>
>>> > +      State.addLoc(It);<br>
>>> > +    }<br>
>>> > +<br>
>>> > +    // All pending members have now been allocated<br>
>>> > +    PendingHAMembers.clear();<br>
>>> > +  }<br>
>>> > +<br>
>>> > +  // This will be allocated by the last member of the HA<br>
>>> > +  return true;<br>
>>> > +}<br>
>>> > +<br>
>>> >  } // End llvm namespace<br>
>>> ><br>
>>> >  #endif<br>
>>> ><br>
>>> > Modified: llvm/trunk/lib/Target/ARM/ARMCallingConv.td<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCallingConv.td?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCallingConv.td?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/lib/Target/ARM/ARMCallingConv.td (original)<br>
>>> > +++ llvm/trunk/lib/Target/ARM/ARMCallingConv.td Fri May  9 09:01:47<br>
>>> > 2014<br>
>>> > @@ -174,6 +174,9 @@ def CC_ARM_AAPCS_VFP : CallingConv<[<br>
>>> >    CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32],<br>
>>> > CCBitConvertToType<f64>>,<br>
>>> >    CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32],<br>
>>> > CCBitConvertToType<v2f64>>,<br>
>>> ><br>
>>> > +  // HFAs are passed in a contiguous block of registers, or on the<br>
>>> > stack<br>
>>> > +  CCIfConsecutiveRegs<CCCustom<"CC_ARM_AAPCS_Custom_HA">>,<br>
>>> > +<br>
>>> >    CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>,<br>
>>> >    CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>,<br>
>>> >    CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8,<br>
>>> ><br>
>>> > Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)<br>
>>> > +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Fri May  9 09:01:47<br>
>>> > 2014<br>
>>> > @@ -43,6 +43,7 @@<br>
>>> >  #include "llvm/IR/Type.h"<br>
>>> >  #include "llvm/MC/MCSectionMachO.h"<br>
>>> >  #include "llvm/Support/CommandLine.h"<br>
>>> > +#include "llvm/Support/Debug.h"<br>
>>> >  #include "llvm/Support/ErrorHandling.h"<br>
>>> >  #include "llvm/Support/MathExtras.h"<br>
>>> >  #include "llvm/Target/TargetOptions.h"<br>
>>> > @@ -1211,40 +1212,58 @@ static void FPCCToARMCC(ISD::CondCode CC<br>
>>> ><br>
>>> >  #include "ARMGenCallingConv.inc"<br>
>>> ><br>
>>> > -/// CCAssignFnForNode - Selects the correct CCAssignFn for a the<br>
>>> > -/// given CallingConvention value.<br>
>>> > -CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC,<br>
>>> > -                                                 bool Return,<br>
>>> > -                                                 bool isVarArg) const<br>
>>> > {<br>
>>> > +/// getEffectiveCallingConv - Get the effective calling convention,<br>
>>> > taking into<br>
>>> > +/// account presence of floating point hardware and calling convention<br>
>>> > +/// limitations, such as support for variadic functions.<br>
>>> > +CallingConv::ID<br>
>>> > +ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,<br>
>>> > +                                           bool isVarArg) const {<br>
>>> >    switch (CC) {<br>
>>> >    default:<br>
>>> >      llvm_unreachable("Unsupported calling convention");<br>
>>> > -  case CallingConv::Fast:<br>
>>> > -    if (Subtarget->hasVFP2() && !isVarArg) {<br>
>>> > -      if (!Subtarget->isAAPCS_ABI())<br>
>>> > -        return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS);<br>
>>> > -      // For AAPCS ABI targets, just use VFP variant of the calling<br>
>>> > convention.<br>
>>> > -      return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);<br>
>>> > -    }<br>
>>> > -    // Fallthrough<br>
>>> > -  case CallingConv::C: {<br>
>>> > -    // Use target triple & subtarget features to do actual dispatch.<br>
>>> > +  case CallingConv::ARM_AAPCS:<br>
>>> > +  case CallingConv::ARM_APCS:<br>
>>> > +  case CallingConv::GHC:<br>
>>> > +    return CC;<br>
>>> > +  case CallingConv::ARM_AAPCS_VFP:<br>
>>> > +    return isVarArg ? CallingConv::ARM_AAPCS :<br>
>>> > CallingConv::ARM_AAPCS_VFP;<br>
>>> > +  case CallingConv::C:<br>
>>> >      if (!Subtarget->isAAPCS_ABI())<br>
>>> > -      return (Return ? RetCC_ARM_APCS : CC_ARM_APCS);<br>
>>> > +      return CallingConv::ARM_APCS;<br>
>>> >      else if (Subtarget->hasVFP2() &&<br>
>>> >               getTargetMachine().Options.FloatABIType == FloatABI::Hard<br>
>>> > &&<br>
>>> >               !isVarArg)<br>
>>> > -      return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);<br>
>>> > -    return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS);<br>
>>> > +      return CallingConv::ARM_AAPCS_VFP;<br>
>>> > +    else<br>
>>> > +      return CallingConv::ARM_AAPCS;<br>
>>> > +  case CallingConv::Fast:<br>
>>> > +    if (!Subtarget->isAAPCS_ABI()) {<br>
>>> > +      if (Subtarget->hasVFP2() && !isVarArg)<br>
>>> > +        return CallingConv::Fast;<br>
>>> > +      return CallingConv::ARM_APCS;<br>
>>> > +    } else if (Subtarget->hasVFP2() && !isVarArg)<br>
>>> > +      return CallingConv::ARM_AAPCS_VFP;<br>
>>> > +    else<br>
>>> > +      return CallingConv::ARM_AAPCS;<br>
>>> >    }<br>
>>> > -  case CallingConv::ARM_AAPCS_VFP:<br>
>>> > -    if (!isVarArg)<br>
>>> > -      return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);<br>
>>> > -    // Fallthrough<br>
>>> > -  case CallingConv::ARM_AAPCS:<br>
>>> > -    return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS);<br>
>>> > +}<br>
>>> > +<br>
>>> > +/// CCAssignFnForNode - Selects the correct CCAssignFn for the given<br>
>>> > +/// CallingConvention.<br>
>>> > +CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC,<br>
>>> > +                                                 bool Return,<br>
>>> > +                                                 bool isVarArg) const<br>
>>> > {<br>
>>> > +  switch (getEffectiveCallingConv(CC, isVarArg)) {<br>
>>> > +  default:<br>
>>> > +    llvm_unreachable("Unsupported calling convention");<br>
>>> >    case CallingConv::ARM_APCS:<br>
>>> >      return (Return ? RetCC_ARM_APCS : CC_ARM_APCS);<br>
>>> > +  case CallingConv::ARM_AAPCS:<br>
>>> > +    return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS);<br>
>>> > +  case CallingConv::ARM_AAPCS_VFP:<br>
>>> > +    return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);<br>
>>> > +  case CallingConv::Fast:<br>
>>> > +    return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS);<br>
>>> >    case CallingConv::GHC:<br>
>>> >      return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC);<br>
>>> >    }<br>
>>> > @@ -10628,3 +10647,77 @@ Value *ARMTargetLowering::emitStoreCondi<br>
>>> >                   Val, Strex->getFunctionType()->getParamType(0)),<br>
>>> >        Addr);<br>
>>> >  }<br>
>>> > +<br>
>>> > +enum HABaseType {<br>
>>> > +  HA_UNKNOWN = 0,<br>
>>> > +  HA_FLOAT,<br>
>>> > +  HA_DOUBLE,<br>
>>> > +  HA_VECT64,<br>
>>> > +  HA_VECT128<br>
>>> > +};<br>
>>> > +<br>
>>> > +static bool isHomogeneousAggregate(Type *Ty, HABaseType &Base,<br>
>>> > +                                   uint64_t &Members) {<br>
>>> > +  if (const StructType *ST = dyn_cast<StructType>(Ty)) {<br>
>>> > +    for (unsigned i = 0; i < ST->getNumElements(); ++i) {<br>
>>> > +      uint64_t SubMembers = 0;<br>
>>> > +      if (!isHomogeneousAggregate(ST->getElementType(i), Base,<br>
>>> > SubMembers))<br>
>>> > +        return false;<br>
>>> > +      Members += SubMembers;<br>
>>> > +    }<br>
>>> > +  } else if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {<br>
>>> > +    uint64_t SubMembers = 0;<br>
>>> > +    if (!isHomogeneousAggregate(AT->getElementType(), Base,<br>
>>> > SubMembers))<br>
>>> > +      return false;<br>
>>> > +    Members += SubMembers * AT->getNumElements();<br>
>>> > +  } else if (Ty->isFloatTy()) {<br>
>>> > +    if (Base != HA_UNKNOWN && Base != HA_FLOAT)<br>
>>> > +      return false;<br>
>>> > +    Members = 1;<br>
>>> > +    Base = HA_FLOAT;<br>
>>> > +  } else if (Ty->isDoubleTy()) {<br>
>>> > +    if (Base != HA_UNKNOWN && Base != HA_DOUBLE)<br>
>>> > +      return false;<br>
>>> > +    Members = 1;<br>
>>> > +    Base = HA_DOUBLE;<br>
>>> > +  } else if (const VectorType *VT = dyn_cast<VectorType>(Ty)) {<br>
>>> > +    Members = 1;<br>
>>> > +    switch (Base) {<br>
>>> > +    case HA_FLOAT:<br>
>>> > +    case HA_DOUBLE:<br>
>>> > +      return false;<br>
>>> > +    case HA_VECT64:<br>
>>> > +      return VT->getBitWidth() == 64;<br>
>>> > +    case HA_VECT128:<br>
>>> > +      return VT->getBitWidth() == 128;<br>
>>> > +    case HA_UNKNOWN:<br>
>>> > +      switch (VT->getBitWidth()) {<br>
>>> > +      case 64:<br>
>>> > +        Base = HA_VECT64;<br>
>>> > +        return true;<br>
>>> > +      case 128:<br>
>>> > +        Base = HA_VECT128;<br>
>>> > +        return true;<br>
>>> > +      default:<br>
>>> > +        return false;<br>
>>> > +      }<br>
>>> > +    }<br>
>>> > +  }<br>
>>> > +<br>
>>> > +  return (Members > 0 && Members <= 4);<br>
>>> > +}<br>
>>> > +<br>
>>> > +/// \brief Return true if a type is an AAPCS-VFP homogeneous<br>
>>> > aggregate.<br>
>>> > +bool ARMTargetLowering::functionArgumentNeedsConsecutiveRegisters(<br>
>>> > +    Type *Ty, CallingConv::ID CallConv, bool isVarArg) const {<br>
>>> > +  if (getEffectiveCallingConv(CallConv, isVarArg) ==<br>
>>> > +      CallingConv::ARM_AAPCS_VFP) {<br>
>>> > +    HABaseType Base = HA_UNKNOWN;<br>
>>> > +    uint64_t Members = 0;<br>
>>> > +    bool result = isHomogeneousAggregate(Ty, Base, Members);<br>
>>> > +    DEBUG(dbgs() << "isHA: " << result << " "; Ty->dump(); dbgs() <<<br>
>>> > "\n");<br>
>>> > +    return result;<br>
>>> > +  } else {<br>
>>> > +    return false;<br>
>>> > +  }<br>
>>> > +}<br>
>>> ><br>
>>> > Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.h<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=208413&r1=208412&r2=208413&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=208413&r1=208412&r2=208413&view=diff</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/lib/Target/ARM/ARMISelLowering.h (original)<br>
>>> > +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.h Fri May  9 09:01:47<br>
>>> > 2014<br>
>>> > @@ -384,6 +384,11 @@ namespace llvm {<br>
>>> >      bool shouldConvertConstantLoadToIntImm(const APInt &Imm,<br>
>>> >                                             Type *Ty) const override;<br>
>>> ><br>
>>> > +    /// \brief Returns true if an argument of type Ty needs to be<br>
>>> > passed in a<br>
>>> > +    /// contiguous block of registers in calling convention CallConv.<br>
>>> > +    bool functionArgumentNeedsConsecutiveRegisters(<br>
>>> > +        Type *Ty, CallingConv::ID CallConv, bool isVarArg) const<br>
>>> > override;<br>
>>> > +<br>
>>> >      Value *emitLoadLinked(IRBuilder<> &Builder, Value *Addr,<br>
>>> >                            AtomicOrdering Ord) const override;<br>
>>> >      Value *emitStoreConditional(IRBuilder<> &Builder, Value *Val,<br>
>>> > @@ -424,6 +429,8 @@ namespace llvm {<br>
>>> >                                   SDValue &Root, SelectionDAG &DAG,<br>
>>> >                                   SDLoc dl) const;<br>
>>> ><br>
>>> > +    CallingConv::ID getEffectiveCallingConv(CallingConv::ID CC,<br>
>>> > +                                            bool isVarArg) const;<br>
>>> >      CCAssignFn *CCAssignFnForNode(CallingConv::ID CC, bool Return,<br>
>>> >                                    bool isVarArg) const;<br>
>>> >      SDValue LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, SDValue<br>
>>> > Arg,<br>
>>> > @@ -577,7 +584,6 @@ namespace llvm {<br>
>>> >      OtherModImm<br>
>>> >    };<br>
>>> ><br>
>>> > -<br>
>>> >    namespace ARM {<br>
>>> >      FastISel *createFastISel(FunctionLoweringInfo &funcInfo,<br>
>>> >                               const TargetLibraryInfo *libInfo);<br>
>>> ><br>
>>> > Added: llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll?rev=208413&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll?rev=208413&view=auto</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll (added)<br>
>>> > +++ llvm/trunk/test/CodeGen/ARM/aapcs-hfa.ll Fri May  9 09:01:47 2014<br>
>>> > @@ -0,0 +1,163 @@<br>
>>> > +; RUN: llc < %s -float-abi=hard -debug-only arm-isel 2>&1 | FileCheck<br>
>>> > %s<br>
>>> > +; RUN: llc < %s -float-abi=soft -debug-only arm-isel 2>&1 | FileCheck<br>
>>> > %s --check-prefix=SOFT<br>
>>> > +<br>
>>> > +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"<br>
>>> > +target triple = "armv7-none--eabi"<br>
>>> > +<br>
>>> > +; SOFT-NOT: isHA<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { float }<br>
>>> > +define void @f0b({ float } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { float, float }<br>
>>> > +define void @f1({ float, float } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { float, float, float }<br>
>>> > +define void @f1b({ float, float, float } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { float, float, float, float }<br>
>>> > +define void @f1c({ float, float, float, float } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { float, float, float, float, float }<br>
>>> > +define void @f2({ float, float, float, float, float } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { double }<br>
>>> > +define void @f3({ double } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { double, double, double, double }<br>
>>> > +define void @f4({ double, double, double, double } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { double, double, double, double, double }<br>
>>> > +define void @f5({ double, double, double, double, double } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { i32, i32 }<br>
>>> > +define void @f5b({ i32, i32 } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { [1 x float] }<br>
>>> > +define void @f6({ [1 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { [4 x float] }<br>
>>> > +define void @f7({ [4 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { [5 x float] }<br>
>>> > +define void @f8({ [5 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 [1 x float]<br>
>>> > +define void @f6b([1 x float] %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 [4 x float]<br>
>>> > +define void @f7b([4 x float] %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 [5 x float]<br>
>>> > +define void @f8b([5 x float] %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { [2 x float], [2 x float] }<br>
>>> > +define void @f9({ [2 x float], [2 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { [1 x float], [3 x float] }<br>
>>> > +define void @f9b({ [1 x float], [3 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { [3 x float], [3 x float] }<br>
>>> > +define void @f10({ [3 x float], [3 x float] } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <2 x float> }<br>
>>> > +define void @f11({ <2 x float>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { <3 x float> }<br>
>>> > +define void @f12({ <3 x float>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <4 x float> }<br>
>>> > +define void @f13({ <4 x float>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <2 x float>, <2 x float> }<br>
>>> > +define void @f15({ <2 x float>, <2 x float>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { <2 x float>, float }<br>
>>> > +define void @f15b({ <2 x float>, float  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { <2 x float>, [2 x float] }<br>
>>> > +define void @f15c({ <2 x float>, [2 x float]  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { <2 x float>, <4 x float> }<br>
>>> > +define void @f16({ <2 x float>, <4 x float>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <2 x double> }<br>
>>> > +define void @f17({ <2 x double>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <2 x i32> }<br>
>>> > +define void @f18({ <2 x i32>  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { <2 x i64>, <4 x i32> }<br>
>>> > +define void @f19({ <2 x i64>, <4 x i32> } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 1 { [4 x <4 x float>] }<br>
>>> > +define void @f20({ [4 x <4 x float>]  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK: isHA: 0 { [5 x <4 x float>] }<br>
>>> > +define void @f21({ [5 x <4 x float>]  } %a) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> > +; CHECK-NOT: isHA<br>
>>> > +define void @f22({ float } %a, ...) {<br>
>>> > +  ret void<br>
>>> > +}<br>
>>> > +<br>
>>> ><br>
>>> > Added: llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll<br>
>>> > URL:<br>
>>> > <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll?rev=208413&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll?rev=208413&view=auto</a><br>

>>> ><br>
>>> > ==============================================================================<br>
>>> > --- llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll (added)<br>
>>> > +++ llvm/trunk/test/CodeGen/ARM/hfa-in-contiguous-registers.ll Fri May<br>
>>> > 9 09:01:47 2014<br>
>>> > @@ -0,0 +1,94 @@<br>
>>> > +; RUN: llc < %s | FileCheck %s<br>
>>> > +<br>
>>> > +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"<br>
>>> > +target triple = "armv7-none--gnueabihf"<br>
>>> > +<br>
>>> > +%struct.s = type { float, float }<br>
>>> > +%union.t = type { [4 x float] }<br>
>>> > +<br>
>>> > +; Equivalent C code:<br>
>>> > +; struct s { float a; float b; };<br>
>>> > +; float foo(float a, double b, struct s c) { return c.a; }<br>
>>> > +; Argument allocation:<br>
>>> > +; a -> s0<br>
>>> > +; b -> d1<br>
>>> > +; c -> s4, s5<br>
>>> > +; s1 is unused<br>
>>> > +; return in s0<br>
>>> > +define float @test1(float %a, double %b, %struct.s %c) {<br>
>>> > +entry:<br>
>>> > +; CHECK-LABEL: test1<br>
>>> > +; CHECK: vmov.f32  s0, s4<br>
>>> > +; CHECK-NOT: vmov.f32        s0, s1<br>
>>> > +<br>
>>> > +  %result = extractvalue %struct.s %c, 0<br>
>>> > +  ret float %result<br>
>>> > +}<br>
>>> > +<br>
>>> > +; Equivalent C code:<br>
>>> > +; union t { float a[4] };<br>
>>> > +; float foo(float a, double b, union s c) { return c.a[0]; }<br>
>>> > +; Argument allocation:<br>
>>> > +; a -> s0<br>
>>> > +; b -> d1<br>
>>> > +; c -> s4..s7<br>
>>> > +define float @test2(float %a, double %b, %union.t %c) #0 {<br>
>>> > +entry:<br>
>>> > +; CHECK-LABEL: test2<br>
>>> > +; CHECK: vmov.f32  s0, s4<br>
>>> > +; CHECK-NOT: vmov.f32        s0, s1<br>
>>> > +<br>
>>> > +  %result = extractvalue %union.t %c, 0, 0<br>
>>> > +  ret float %result<br>
>>> > +}<br>
>>> > +<br>
>>> > +; Equivalent C code:<br>
>>> > +; struct s { float a; float b; };<br>
>>> > +; float foo(float a, double b, struct s c, float d) { return d; }<br>
>>> > +; Argument allocation:<br>
>>> > +; a -> s0<br>
>>> > +; b -> d1<br>
>>> > +; c -> s4, s5<br>
>>> > +; d -> s1<br>
>>> > +; return in s0<br>
>>> > +define float @test3(float %a, double %b, %struct.s %c, float %d) {<br>
>>> > +entry:<br>
>>> > +; CHECK-LABEL: test3<br>
>>> > +; CHECK: vmov.f32  s0, s1<br>
>>> > +; CHECK-NOT: vmov.f32        s0, s5<br>
>>> > +<br>
>>> > +  ret float %d<br>
>>> > +}<br>
>>> > +<br>
>>> > +; Equivalent C code:<br>
>>> > +; struct s { float a; float b; };<br>
>>> > +; float foo(struct s a, struct s b) { return b.b; }<br>
>>> > +; Argument allocation:<br>
>>> > +; a -> s0, s1<br>
>>> > +; b -> s2, s3<br>
>>> > +; return in s0<br>
>>> > +define float @test4(%struct.s %a, %struct.s %b) {<br>
>>> > +entry:<br>
>>> > +; CHECK-LABEL: test4<br>
>>> > +; CHECK: vmov.f32  s0, s3<br>
>>> > +<br>
>>> > +  %result = extractvalue %struct.s %b, 1<br>
>>> > +  ret float %result<br>
>>> > +}<br>
>>> > +<br>
>>> > +; Equivalent C code:<br>
>>> > +; struct s { float a; float b; };<br>
>>> > +; float foo(struct s a, float b, struct s c) { return c.a; }<br>
>>> > +; Argument allocation:<br>
>>> > +; a -> s0, s1<br>
>>> > +; b -> s2<br>
>>> > +; c -> s3, s4<br>
>>> > +; return in s0<br>
>>> > +define float @test5(%struct.s %a, float %b, %struct.s %c) {<br>
>>> > +entry:<br>
>>> > +; CHECK-LABEL: test5<br>
>>> > +; CHECK: vmov.f32  s0, s3<br>
>>> > +<br>
>>> > +  %result = extractvalue %struct.s %c, 0<br>
>>> > +  ret float %result<br>
>>> > +}<br>
>>> ><br>
>>> ><br></div></div></blockquote></div>
</div></div>