diff options
| -rw-r--r-- | llvm/lib/Target/Hexagon/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/Hexagon.td | 1 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonCallingConv.td | 134 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLowering.cpp | 650 | ||||
| -rw-r--r-- | llvm/test/CodeGen/Hexagon/vec-vararg-align.ll | 2 | ||||
| -rw-r--r-- | llvm/test/MC/Hexagon/inst_select.ll | 8 |
6 files changed, 260 insertions, 536 deletions
diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt index 5e75cb6a589..df86fabf417 100644 --- a/llvm/lib/Target/Hexagon/CMakeLists.txt +++ b/llvm/lib/Target/Hexagon/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_TARGET_DEFINITIONS Hexagon.td) tablegen(LLVM HexagonGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv) tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel) tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer) tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler) diff --git a/llvm/lib/Target/Hexagon/Hexagon.td b/llvm/lib/Target/Hexagon/Hexagon.td index 73617da2575..169704cbfba 100644 --- a/llvm/lib/Target/Hexagon/Hexagon.td +++ b/llvm/lib/Target/Hexagon/Hexagon.td @@ -300,6 +300,7 @@ include "HexagonDepITypes.td" include "HexagonInstrFormats.td" include "HexagonDepInstrFormats.td" include "HexagonDepInstrInfo.td" +include "HexagonCallingConv.td" include "HexagonPseudo.td" include "HexagonPatterns.td" include "HexagonPatternsHVX.td" diff --git a/llvm/lib/Target/Hexagon/HexagonCallingConv.td b/llvm/lib/Target/Hexagon/HexagonCallingConv.td new file mode 100644 index 00000000000..ed2f87570d6 --- /dev/null +++ b/llvm/lib/Target/Hexagon/HexagonCallingConv.td @@ -0,0 +1,134 @@ +//===- HexagonCallingConv.td ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class CCIfArgIsVarArg<CCAction A> + : CCIf<"State.isVarArg() && " + "ValNo >= static_cast<HexagonCCState&>(State)" + ".getNumNamedVarArgParams()", A>; + +def CC_HexagonStack: CallingConv<[ + CCIfType<[i32,v2i16,v4i8], + CCAssignToStack<4,4>>, + CCIfType<[i64,v2i32,v4i16,v8i8], + CCAssignToStack<8,8>> +]>; + +def CC_Hexagon: CallingConv<[ + CCIfType<[i1,i8,i16], + CCPromoteToType<i32>>, + CCIfType<[f32], + CCBitConvertToType<i32>>, + CCIfType<[f64], + CCBitConvertToType<i64>>, + + CCIfByVal< + CCPassByVal<8,8>>, + CCIfArgIsVarArg< + CCDelegateTo<CC_HexagonStack>>, + + // Pass split values in pairs, allocate odd register if necessary. + CCIfType<[i32], + CCIfSplit< + CCCustom<"CC_SkipOdd">>>, + + CCIfType<[i32,v2i16,v4i8], + CCAssignToReg<[R0,R1,R2,R3,R4,R5]>>, + // Make sure to allocate any skipped 32-bit register, so it does not get + // allocated to a subsequent 32-bit value. + CCIfType<[i64,v2i32,v4i16,v8i8], + CCCustom<"CC_SkipOdd">>, + CCIfType<[i64,v2i32,v4i16,v8i8], + CCAssignToReg<[D0,D1,D2]>>, + + CCDelegateTo<CC_HexagonStack> +]>; + +def RetCC_Hexagon: CallingConv<[ + CCIfType<[i1,i8,i16], + CCPromoteToType<i32>>, + CCIfType<[f32], + CCBitConvertToType<i32>>, + CCIfType<[f64], + CCBitConvertToType<i64>>, + + // Small structures are returned in a pair of registers, (which is + // always r1:0). In such case, what is returned are two i32 values + // without any additional information (in ArgFlags) stating that + // they are parts of a structure. Because of that there is no way + // to differentiate that situation from an attempt to return two + // values, so always assign R0 and R1. + CCIfSplit< + CCAssignToReg<[R0,R1]>>, + CCIfType<[i32,v2i16,v4i8], + CCAssignToReg<[R0,R1]>>, + CCIfType<[i64,v2i32,v4i16,v8i8], + CCAssignToReg<[D0]>> +]>; + + +class CCIfHvx64<CCAction A> + : CCIf<"State.getMachineFunction().getSubtarget<HexagonSubtarget>()" + ".useHVX64BOps()", A>; + +class CCIfHvx128<CCAction A> + : CCIf<"State.getMachineFunction().getSubtarget<HexagonSubtarget>()" + ".useHVX128BOps()", A>; + +def CC_Hexagon_HVX: CallingConv<[ + // HVX 64-byte mode + CCIfHvx64< + CCIfType<[v16i32,v32i16,v64i8], + CCAssignToReg<[V0,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15]>>>, + CCIfHvx64< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToReg<[W0,W1,W2,W3,W4,W5,W6,W7]>>>, + CCIfHvx64< + CCIfType<[v16i32,v32i16,v64i8], + CCAssignToStack<64,64>>>, + CCIfHvx64< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToStack<128,64>>>, + + // HVX 128-byte mode + CCIfHvx128< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToReg<[V0,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15]>>>, + CCIfHvx128< + CCIfType<[v64i32,v128i16,v256i8], + CCAssignToReg<[W0,W1,W2,W3,W4,W5,W6,W7]>>>, + CCIfHvx128< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToStack<128,128>>>, + CCIfHvx128< + CCIfType<[v64i32,v128i16,v256i8], + CCAssignToStack<256,128>>>, + + CCDelegateTo<CC_Hexagon> +]>; + +def RetCC_Hexagon_HVX: CallingConv<[ + // HVX 64-byte mode + CCIfHvx64< + CCIfType<[v16i32,v32i16,v64i8], + CCAssignToReg<[V0]>>>, + CCIfHvx64< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToReg<[W0]>>>, + + // HVX 128-byte mode + CCIfHvx128< + CCIfType<[v32i32,v64i16,v128i8], + CCAssignToReg<[V0]>>>, + CCIfHvx128< + CCIfType<[v64i32,v128i16,v256i8], + CCAssignToReg<[W0]>>>, + + CCDelegateTo<RetCC_Hexagon> +]>; + diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index ef387379bd0..8151d23e1ef 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -110,10 +110,10 @@ namespace { unsigned NumNamedVarArgParams; public: - HexagonCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF, + HexagonCCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF, SmallVectorImpl<CCValAssign> &locs, LLVMContext &C, int NumNamedVarArgParams) - : CCState(CC, isVarArg, MF, locs, C), + : CCState(CC, IsVarArg, MF, locs, C), NumNamedVarArgParams(NumNamedVarArgParams) {} unsigned getNumNamedVarArgParams() const { return NumNamedVarArgParams; } @@ -127,398 +127,31 @@ namespace { } // end anonymous namespace -// Implement calling convention for Hexagon. - -static bool -CC_Hexagon(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -CC_Hexagon32(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -CC_Hexagon64(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -CC_HexagonVector(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -RetCC_Hexagon(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -RetCC_Hexagon32(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -RetCC_Hexagon64(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -RetCC_HexagonVector(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State); - -static bool -CC_Hexagon_VarArg (unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - HexagonCCState &HState = static_cast<HexagonCCState &>(State); - - if (ValNo < HState.getNumNamedVarArgParams()) { - // Deal with named arguments. - return CC_Hexagon(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State); - } - - // Deal with un-named arguments. - unsigned Offset; - if (ArgFlags.isByVal()) { - // If pass-by-value, the size allocated on stack is decided - // by ArgFlags.getByValSize(), not by the size of LocVT. - Offset = State.AllocateStack(ArgFlags.getByValSize(), - ArgFlags.getByValAlign()); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::i1 || LocVT == MVT::i8 || LocVT == MVT::i16) { - LocVT = MVT::i32; - ValVT = MVT::i32; - if (ArgFlags.isSExt()) - LocInfo = CCValAssign::SExt; - else if (ArgFlags.isZExt()) - LocInfo = CCValAssign::ZExt; - else - LocInfo = CCValAssign::AExt; - } - if (LocVT == MVT::i32 || LocVT == MVT::f32) { - Offset = State.AllocateStack(4, 4); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::i64 || LocVT == MVT::f64) { - Offset = State.AllocateStack(8, 8); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::v2i64 || LocVT == MVT::v4i32 || LocVT == MVT::v8i16 || - LocVT == MVT::v16i8) { - Offset = State.AllocateStack(16, 16); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::v4i64 || LocVT == MVT::v8i32 || LocVT == MVT::v16i16 || - LocVT == MVT::v32i8) { - Offset = State.AllocateStack(32, 32); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::v16i32 || LocVT == MVT::v32i16 || - LocVT == MVT::v64i8 || LocVT == MVT::v512i1) { - Offset = State.AllocateStack(64, 64); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::v32i32 || LocVT == MVT::v64i16 || - LocVT == MVT::v128i8 || LocVT == MVT::v1024i1) { - Offset = State.AllocateStack(128, 128); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (LocVT == MVT::v64i32 || LocVT == MVT::v128i16 || - LocVT == MVT::v256i8) { - Offset = State.AllocateStack(256, 256); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - - llvm_unreachable(nullptr); -} - -static bool CC_Hexagon (unsigned ValNo, MVT ValVT, MVT LocVT, - CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { - if (ArgFlags.isByVal()) { - // Passed on stack. - unsigned Offset = State.AllocateStack(ArgFlags.getByValSize(), - ArgFlags.getByValAlign()); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - - if (LocVT == MVT::i1) { - LocVT = MVT::i32; - } else if (LocVT == MVT::i8 || LocVT == MVT::i16) { - LocVT = MVT::i32; - ValVT = MVT::i32; - if (ArgFlags.isSExt()) - LocInfo = CCValAssign::SExt; - else if (ArgFlags.isZExt()) - LocInfo = CCValAssign::ZExt; - else - LocInfo = CCValAssign::AExt; - } else if (LocVT == MVT::v4i8 || LocVT == MVT::v2i16) { - LocVT = MVT::i32; - LocInfo = CCValAssign::BCvt; - } else if (LocVT == MVT::v8i8 || LocVT == MVT::v4i16 || LocVT == MVT::v2i32) { - LocVT = MVT::i64; - LocInfo = CCValAssign::BCvt; - } - - if (LocVT == MVT::i32 || LocVT == MVT::f32) { - if (!CC_Hexagon32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - - if (LocVT == MVT::i64 || LocVT == MVT::f64) { - if (!CC_Hexagon64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - - if (LocVT == MVT::v8i32 || LocVT == MVT::v16i16 || LocVT == MVT::v32i8) { - unsigned Offset = State.AllocateStack(ArgFlags.getByValSize(), 32); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - - auto &HST = State.getMachineFunction().getSubtarget<HexagonSubtarget>(); - if (HST.isHVXVectorType(LocVT)) { - if (!CC_HexagonVector(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - - return true; // CC didn't match. -} +// Implement calling convention for Hexagon. -static bool CC_Hexagon32(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - static const MCPhysReg RegList[] = { - Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4, - Hexagon::R5 +static bool CC_SkipOdd(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + static const MCPhysReg ArgRegs[] = { + Hexagon::R0, Hexagon::R1, Hexagon::R2, + Hexagon::R3, Hexagon::R4, Hexagon::R5 }; - if (unsigned Reg = State.AllocateReg(RegList)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - - unsigned Offset = State.AllocateStack(4, 4); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; -} + const unsigned NumArgRegs = array_lengthof(ArgRegs); + unsigned RegNum = State.getFirstUnallocated(ArgRegs); -static bool CC_Hexagon64(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - if (unsigned Reg = State.AllocateReg(Hexagon::D0)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } + // RegNum is an index into ArgRegs: skip a register if RegNum is odd. + if (RegNum != NumArgRegs && RegNum % 2 == 1) + State.AllocateReg(ArgRegs[RegNum]); - static const MCPhysReg RegList1[] = { - Hexagon::D1, Hexagon::D2 - }; - static const MCPhysReg RegList2[] = { - Hexagon::R1, Hexagon::R3 - }; - if (unsigned Reg = State.AllocateReg(RegList1, RegList2)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - - unsigned Offset = State.AllocateStack(8, 8, Hexagon::D2); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + // Always return false here, as this function only makes sure that the first + // unallocated register has an even register number and does not actually + // allocate a register for the current argument. return false; } -static bool CC_HexagonVector(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - static const MCPhysReg VecLstS[] = { - Hexagon::V0, Hexagon::V1, Hexagon::V2, Hexagon::V3, Hexagon::V4, - Hexagon::V5, Hexagon::V6, Hexagon::V7, Hexagon::V8, Hexagon::V9, - Hexagon::V10, Hexagon::V11, Hexagon::V12, Hexagon::V13, Hexagon::V14, - Hexagon::V15 - }; - static const MCPhysReg VecLstD[] = { - Hexagon::W0, Hexagon::W1, Hexagon::W2, Hexagon::W3, Hexagon::W4, - Hexagon::W5, Hexagon::W6, Hexagon::W7 - }; - auto &MF = State.getMachineFunction(); - auto &HST = MF.getSubtarget<HexagonSubtarget>(); - - if (HST.useHVX64BOps() && - (LocVT == MVT::v16i32 || LocVT == MVT::v32i16 || - LocVT == MVT::v64i8 || LocVT == MVT::v512i1)) { - if (unsigned Reg = State.AllocateReg(VecLstS)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - unsigned Offset = State.AllocateStack(64, 64); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (HST.useHVX64BOps() && (LocVT == MVT::v32i32 || - LocVT == MVT::v64i16 || LocVT == MVT::v128i8)) { - if (unsigned Reg = State.AllocateReg(VecLstD)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - unsigned Offset = State.AllocateStack(128, 128); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - // 128B Mode - if (HST.useHVX128BOps() && (LocVT == MVT::v64i32 || - LocVT == MVT::v128i16 || LocVT == MVT::v256i8)) { - if (unsigned Reg = State.AllocateReg(VecLstD)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - unsigned Offset = State.AllocateStack(256, 256); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - if (HST.useHVX128BOps() && - (LocVT == MVT::v32i32 || LocVT == MVT::v64i16 || - LocVT == MVT::v128i8 || LocVT == MVT::v1024i1)) { - if (unsigned Reg = State.AllocateReg(VecLstS)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - unsigned Offset = State.AllocateStack(128, 128); - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - return false; - } - return true; -} +#include "HexagonGenCallingConv.inc" -static bool RetCC_Hexagon(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - auto &MF = State.getMachineFunction(); - auto &HST = MF.getSubtarget<HexagonSubtarget>(); - - if (LocVT == MVT::i1) { - // Return values of type MVT::i1 still need to be assigned to R0, but - // the value type needs to remain i1. LowerCallResult will deal with it, - // but it needs to recognize i1 as the value type. - LocVT = MVT::i32; - } else if (LocVT == MVT::i8 || LocVT == MVT::i16) { - LocVT = MVT::i32; - ValVT = MVT::i32; - if (ArgFlags.isSExt()) - LocInfo = CCValAssign::SExt; - else if (ArgFlags.isZExt()) - LocInfo = CCValAssign::ZExt; - else - LocInfo = CCValAssign::AExt; - } else if (LocVT == MVT::v4i8 || LocVT == MVT::v2i16) { - LocVT = MVT::i32; - LocInfo = CCValAssign::BCvt; - } else if (LocVT == MVT::v8i8 || LocVT == MVT::v4i16 || LocVT == MVT::v2i32) { - LocVT = MVT::i64; - LocInfo = CCValAssign::BCvt; - } else if (LocVT == MVT::v64i8 || LocVT == MVT::v32i16 || - LocVT == MVT::v16i32 || LocVT == MVT::v512i1) { - LocVT = MVT::v16i32; - ValVT = MVT::v16i32; - LocInfo = CCValAssign::Full; - } else if (LocVT == MVT::v128i8 || LocVT == MVT::v64i16 || - LocVT == MVT::v32i32 || - (LocVT == MVT::v1024i1 && HST.useHVX128BOps())) { - LocVT = MVT::v32i32; - ValVT = MVT::v32i32; - LocInfo = CCValAssign::Full; - } else if (LocVT == MVT::v256i8 || LocVT == MVT::v128i16 || - LocVT == MVT::v64i32) { - LocVT = MVT::v64i32; - ValVT = MVT::v64i32; - LocInfo = CCValAssign::Full; - } - if (LocVT == MVT::i32 || LocVT == MVT::f32) { - if (!RetCC_Hexagon32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - - if (LocVT == MVT::i64 || LocVT == MVT::f64) { - if (!RetCC_Hexagon64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - if (LocVT == MVT::v16i32 || LocVT == MVT::v32i32 || LocVT == MVT::v64i32) { - if (!RetCC_HexagonVector(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State)) - return false; - } - return true; // CC didn't match. -} - -static bool RetCC_Hexagon32(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - if (LocVT == MVT::i32 || LocVT == MVT::f32) { - // Note that use of registers beyond R1 is not ABI compliant. However there - // are (experimental) IR passes which generate internal functions that - // return structs using these additional registers. - static const uint16_t RegList[] = { Hexagon::R0, Hexagon::R1, - Hexagon::R2, Hexagon::R3, - Hexagon::R4, Hexagon::R5 }; - if (unsigned Reg = State.AllocateReg(RegList)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - } - - return true; -} - -static bool RetCC_Hexagon64(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - if (LocVT == MVT::i64 || LocVT == MVT::f64) { - if (unsigned Reg = State.AllocateReg(Hexagon::D0)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - } - - return true; -} - -static bool RetCC_HexagonVector(unsigned ValNo, MVT ValVT, - MVT LocVT, CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - auto &MF = State.getMachineFunction(); - auto &HST = MF.getSubtarget<HexagonSubtarget>(); - - if (LocVT == MVT::v16i32) { - if (unsigned Reg = State.AllocateReg(Hexagon::V0)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - } else if (LocVT == MVT::v32i32) { - unsigned Req = HST.useHVX128BOps() ? Hexagon::V0 : Hexagon::W0; - if (unsigned Reg = State.AllocateReg(Req)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - } else if (LocVT == MVT::v64i32) { - if (unsigned Reg = State.AllocateReg(Hexagon::W0)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; - } - } - - return true; -} void HexagonTargetLowering::promoteLdStType(MVT VT, MVT PromotedLdStVT) { if (VT != PromotedLdStVT) { @@ -553,11 +186,14 @@ static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst, bool HexagonTargetLowering::CanLowerReturn( - CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { SmallVector<CCValAssign, 16> RVLocs; - CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context); + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); + + if (MF.getSubtarget<HexagonSubtarget>().useHVXOps()) + return CCInfo.CheckReturn(Outs, RetCC_Hexagon_HVX); return CCInfo.CheckReturn(Outs, RetCC_Hexagon); } @@ -566,7 +202,7 @@ HexagonTargetLowering::CanLowerReturn( // the value is stored in memory pointed by a pointer passed by caller. SDValue HexagonTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, - bool isVarArg, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SDLoc &dl, SelectionDAG &DAG) const { @@ -574,11 +210,14 @@ HexagonTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, SmallVector<CCValAssign, 16> RVLocs; // CCState - Info about the registers and stack slot. - CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, *DAG.getContext()); // Analyze return values of ISD::RET - CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon); + if (Subtarget.useHVXOps()) + CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon_HVX); + else + CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon); SDValue Flag; SmallVector<SDValue, 4> RetOps(1, Chain); @@ -619,17 +258,20 @@ bool HexagonTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { /// being lowered. Returns a SDNode with the same number of values as the /// ISD::CALL. SDValue HexagonTargetLowering::LowerCallResult( - SDValue Chain, SDValue Glue, CallingConv::ID CallConv, bool isVarArg, + SDValue Chain, SDValue Glue, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals, const SmallVectorImpl<SDValue> &OutVals, SDValue Callee) const { // Assign locations to each value returned by this call. SmallVector<CCValAssign, 16> RVLocs; - CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, *DAG.getContext()); - CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon); + if (Subtarget.useHVXOps()) + CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon_HVX); + else + CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { @@ -678,7 +320,6 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; - bool &IsTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool IsVarArg = CLI.IsVarArg; bool DoesNotReturn = CLI.DoesNotReturn; @@ -689,7 +330,8 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, auto PtrVT = getPointerTy(MF.getDataLayout()); // Check for varargs. - unsigned NumNamedVarArgParams = -1U; + unsigned NumNamedVarArgParams = 0; + if (GlobalAddressSDNode *GAN = dyn_cast<GlobalAddressSDNode>(Callee)) { const GlobalValue *GV = GAN->getGlobal(); Callee = DAG.getTargetGlobalAddress(GV, dl, MVT::i32); @@ -704,41 +346,40 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; - HexagonCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, - *DAG.getContext(), NumNamedVarArgParams); + HexagonCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + ArgLocs, *DAG.getContext(), NumNamedVarArgParams); - if (IsVarArg) - CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_VarArg); + if (Subtarget.useHVXOps()) + CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_HVX); else CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon); auto Attr = MF.getFunction().getFnAttribute("disable-tail-calls"); if (Attr.getValueAsString() == "true") - IsTailCall = false; + CLI.IsTailCall = false; - if (IsTailCall) { + if (CLI.IsTailCall) { bool StructAttrFlag = MF.getFunction().hasStructRetAttr(); - IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, - IsVarArg, IsStructRet, - StructAttrFlag, - Outs, OutVals, Ins, DAG); + CLI.IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, + IsVarArg, IsStructRet, StructAttrFlag, Outs, + OutVals, Ins, DAG); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; if (VA.isMemLoc()) { - IsTailCall = false; + CLI.IsTailCall = false; break; } } - DEBUG(dbgs() << (IsTailCall ? "Eligible for Tail Call\n" - : "Argument must be passed on stack. " - "Not eligible for Tail Call\n")); + DEBUG(dbgs() << (CLI.IsTailCall ? "Eligible for Tail Call\n" + : "Argument must be passed on stack. " + "Not eligible for Tail Call\n")); } // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); SmallVector<std::pair<unsigned, SDValue>, 16> RegsToPass; SmallVector<SDValue, 8> MemOpChains; - auto &HRI = *Subtarget.getRegisterInfo(); + const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo(); SDValue StackPtr = DAG.getCopyFromReg(Chain, dl, HRI.getStackRegister(), PtrVT); @@ -804,12 +445,8 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (NeedsArgAlign && Subtarget.hasV60TOps()) { DEBUG(dbgs() << "Function needs byte stack align due to call args\n"); - // V6 vectors passed by value have 64 or 128 byte alignment depending - // on whether we are 64 byte vector mode or 128 byte. - bool UseHVX128B = Subtarget.useHVX128BOps(); - assert(Subtarget.useHVXOps()); - const unsigned ObjAlign = UseHVX128B ? 128 : 64; - LargestAlignSeen = std::max(LargestAlignSeen, ObjAlign); + unsigned VecAlign = HRI.getSpillAlignment(Hexagon::HvxVRRegClass); + LargestAlignSeen = std::max(LargestAlignSeen, VecAlign); MFI.ensureMaxAlignment(LargestAlignSeen); } // Transform all store nodes into one single node because all store @@ -818,7 +455,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); SDValue Glue; - if (!IsTailCall) { + if (!CLI.IsTailCall) { Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); Glue = Chain.getValue(1); } @@ -827,7 +464,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // chain and flag operands which copy the outgoing args into registers. // The Glue is necessary since all emitted instructions must be // stuck together. - if (!IsTailCall) { + if (!CLI.IsTailCall) { for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, Glue); @@ -886,7 +523,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (Glue.getNode()) Ops.push_back(Glue); - if (IsTailCall) { + if (CLI.IsTailCall) { MFI.setHasTailCall(); return DAG.getNode(HexagonISD::TC_RETURN, dl, NodeTys, Ops); } @@ -1090,20 +727,22 @@ HexagonTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, } SDValue HexagonTargetLowering::LowerFormalArguments( - SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); - MachineRegisterInfo &RegInfo = MF.getRegInfo(); - auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>(); + MachineRegisterInfo &MRI = MF.getRegInfo(); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; - CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs, + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext()); - CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon); + if (Subtarget.useHVXOps()) + CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_HVX); + else + CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon); // For LLVM, in the case when returning a struct by value (>8byte), // the first argument is a pointer that points to the location on caller's @@ -1112,110 +751,62 @@ SDValue HexagonTargetLowering::LowerFormalArguments( // equal to) 8 bytes. If not, no address will be passed into callee and // callee return the result direclty through R0/R1. - SmallVector<SDValue, 8> MemOps; + auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>(); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; ISD::ArgFlagsTy Flags = Ins[i].Flags; - unsigned ObjSize; - unsigned StackLocation; - int FI; - - if ( (VA.isRegLoc() && !Flags.isByVal()) - || (VA.isRegLoc() && Flags.isByVal() && Flags.getByValSize() > 8)) { - // Arguments passed in registers - // 1. int, long long, ptr args that get allocated in register. - // 2. Large struct that gets an register to put its address in. - EVT RegVT = VA.getLocVT(); - if (RegVT == MVT::i8 || RegVT == MVT::i16 || - RegVT == MVT::i32 || RegVT == MVT::f32) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::IntRegsRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - if (VA.getLocInfo() == CCValAssign::BCvt) - RegVT = VA.getValVT(); - SDValue Copy = DAG.getCopyFromReg(Chain, dl, VReg, RegVT); - // Treat values of type MVT::i1 specially: they are passed in - // registers of type i32, but they need to remain as values of - // type i1 for consistency of the argument lowering. - if (VA.getValVT() == MVT::i1) { - // Generate a copy into a predicate register and use the value - // of the register as the "InVal". - unsigned PReg = - RegInfo.createVirtualRegister(&Hexagon::PredRegsRegClass); - SDNode *T = DAG.getMachineNode(Hexagon::C2_tfrrp, dl, MVT::i1, - Copy.getValue(0)); - Copy = DAG.getCopyToReg(Copy.getValue(1), dl, PReg, SDValue(T, 0)); - Copy = DAG.getCopyFromReg(Copy, dl, PReg, MVT::i1); - } - InVals.push_back(Copy); - Chain = Copy.getValue(1); - } else if (RegVT == MVT::i64 || RegVT == MVT::f64) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::DoubleRegsRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - if (VA.getLocInfo() == CCValAssign::BCvt) - RegVT = VA.getValVT(); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); - - // Single Vector - } else if ((RegVT == MVT::v16i32 || - RegVT == MVT::v32i16 || RegVT == MVT::v64i8)) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::HvxVRRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); - } else if (Subtarget.useHVX128BOps() && - ((RegVT == MVT::v32i32 || - RegVT == MVT::v64i16 || RegVT == MVT::v128i8))) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::HvxVRRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); - - // Double Vector - } else if ((RegVT == MVT::v32i32 || - RegVT == MVT::v64i16 || RegVT == MVT::v128i8)) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::HvxWRRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); - } else if (Subtarget.useHVX128BOps() && - ((RegVT == MVT::v64i32 || - RegVT == MVT::v128i16 || RegVT == MVT::v256i8))) { - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::HvxWRRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); - } else if (RegVT == MVT::v512i1 || RegVT == MVT::v1024i1) { - assert(0 && "need to support VecPred regs"); - unsigned VReg = - RegInfo.createVirtualRegister(&Hexagon::HvxQRRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT)); + bool ByVal = Flags.isByVal(); + + // Arguments passed in registers: + // 1. 32- and 64-bit values and HVX vectors are passed directly, + // 2. Large structs are passed via an address, and the address is + // passed in a register. + if (VA.isRegLoc() && ByVal && Flags.getByValSize() <= 8) + llvm_unreachable("ByValSize must be bigger than 8 bytes"); + + bool InReg = VA.isRegLoc() && + (!ByVal || (ByVal && Flags.getByValSize() > 8)); + + if (InReg) { + MVT RegVT = VA.getLocVT(); + if (VA.getLocInfo() == CCValAssign::BCvt) + RegVT = VA.getValVT(); + + const TargetRegisterClass *RC = getRegClassFor(RegVT); + unsigned VReg = MRI.createVirtualRegister(RC); + SDValue Copy = DAG.getCopyFromReg(Chain, dl, VReg, RegVT); + + // Treat values of type MVT::i1 specially: they are passed in + // registers of type i32, but they need to remain as values of + // type i1 for consistency of the argument lowering. + if (VA.getValVT() == MVT::i1) { + assert(RegVT.getSizeInBits() <= 32); + SDValue T = DAG.getNode(ISD::AND, dl, RegVT, + Copy, DAG.getConstant(1, dl, RegVT)); + Copy = DAG.getSetCC(dl, MVT::i1, T, DAG.getConstant(0, dl, RegVT), + ISD::SETNE); } else { - assert (0); +#ifndef NDEBUG + unsigned RegSize = RegVT.getSizeInBits(); + assert(RegSize == 32 || RegSize == 64 || + Subtarget.isHVXVectorType(RegVT)); +#endif } - } else if (VA.isRegLoc() && Flags.isByVal() && Flags.getByValSize() <= 8) { - assert (0 && "ByValSize must be bigger than 8 bytes"); + InVals.push_back(Copy); + MRI.addLiveIn(VA.getLocReg(), VReg); } else { - // Sanity check. - assert(VA.isMemLoc()); + assert(VA.isMemLoc() && "Argument should be passed in memory"); - if (Flags.isByVal()) { - // If it's a byval parameter, then we need to compute the - // "real" size, not the size of the pointer. - ObjSize = Flags.getByValSize(); - } else { - ObjSize = VA.getLocVT().getStoreSizeInBits() >> 3; - } - - StackLocation = HEXAGON_LRFP_SIZE + VA.getLocMemOffset(); - // Create the frame index object for this incoming parameter... - FI = MFI.CreateFixedObject(ObjSize, StackLocation, true); + // If it's a byval parameter, then we need to compute the + // "real" size, not the size of the pointer. + unsigned ObjSize = Flags.isByVal() + ? Flags.getByValSize() + : VA.getLocVT().getStoreSizeInBits() / 8; - // Create the SelectionDAG nodes cordl, responding to a load - // from this parameter. + // Create the frame index object for this incoming parameter. + int Offset = HEXAGON_LRFP_SIZE + VA.getLocMemOffset(); + int FI = MFI.CreateFixedObject(ObjSize, Offset, true); SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); if (Flags.isByVal()) { @@ -1224,22 +815,19 @@ SDValue HexagonTargetLowering::LowerFormalArguments( // location. InVals.push_back(FIN); } else { - InVals.push_back( - DAG.getLoad(VA.getValVT(), dl, Chain, FIN, MachinePointerInfo())); + SDValue L = DAG.getLoad(VA.getValVT(), dl, Chain, FIN, + MachinePointerInfo::getFixedStack(MF, FI, 0)); + InVals.push_back(L); } } } - if (!MemOps.empty()) - Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); - if (isVarArg) { + if (IsVarArg) { // This will point to the next argument passed via stack. - int FrameIndex = MFI.CreateFixedObject(Hexagon_PointerSize, - HEXAGON_LRFP_SIZE + - CCInfo.getNextStackOffset(), - true); - FuncInfo.setVarArgsFrameIndex(FrameIndex); + int Offset = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset(); + int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true); + HMFI.setVarArgsFrameIndex(FI); } return Chain; @@ -2293,6 +1881,8 @@ HexagonTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); + const SDLoc &dl(Op); + // If the inputs are not the same as the output, bail. This is not an // error situation, but complicates the handling and the default expansion // (into BUILD_VECTOR) should be adequate. @@ -2340,8 +1930,6 @@ HexagonTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) MaskIdx |= M << S; } - const SDLoc &dl(Op); - if (ByteMask.size() == 4) { // Identity. if (MaskIdx == (0x03020100 | MaskUnd)) diff --git a/llvm/test/CodeGen/Hexagon/vec-vararg-align.ll b/llvm/test/CodeGen/Hexagon/vec-vararg-align.ll index 0101c1ffa8a..90a458db1b7 100644 --- a/llvm/test/CodeGen/Hexagon/vec-vararg-align.ll +++ b/llvm/test/CodeGen/Hexagon/vec-vararg-align.ll @@ -1,7 +1,7 @@ ; RUN: llc -march=hexagon < %s | FileCheck %s ; ; Check that the stack is aligned according to the outgoing function arguments. -; CHECK: r29 = and(r29,#-128) +; CHECK: r29 = and(r29,#-64) target triple = "hexagon-unknown--elf" diff --git a/llvm/test/MC/Hexagon/inst_select.ll b/llvm/test/MC/Hexagon/inst_select.ll index a730419c854..a956b2a031d 100644 --- a/llvm/test/MC/Hexagon/inst_select.ll +++ b/llvm/test/MC/Hexagon/inst_select.ll @@ -7,7 +7,7 @@ define i32 @foo (i1 %a, i32 %b, i32 %c) ret i32 %1 } -; CHECK: 00 40 40 85 85404000 -; CHECK: 00 40 9f 52 529f4000 -; CHECK: 00 60 01 74 74016000 -; CHECK: 00 e0 82 74 7482e000 +; CHECK: 00 40 00 85 85004000 { p0 = tstbit(r0,#0) +; CHECK: 00 40 9f 52 529f4000 jumpr r31 +; CHECK: 00 60 01 74 74016000 if (p0.new) r0 = add(r1,#0) +; CHECK: 00 e0 82 74 7482e000 if (!p0.new) r0 = add(r2,#0) } |

