[llvm] r175088 - Bug fix 13622: Add paired register support for inline asm with 64-bit data on ARM
NAKAMURA Takumi
geek4civic at gmail.com
Wed Feb 13 15:11:17 PST 2013
It causes an assertion failure...
Assertion failed: isReg() && "This is not a register operand!", file
llvm/include/llvm/CodeGen/MachineOperand.h, line 260
http://bb.pgr.jp/builders/cmake-clang-i686-mingw32/builds/3121
2013/2/14 Weiming Zhao <weimingz at codeaurora.org>:
> Author: weimingz
> Date: Wed Feb 13 15:43:02 2013
> New Revision: 175088
>
> URL: http://llvm.org/viewvc/llvm-project?rev=175088&view=rev
> Log:
> Bug fix 13622: Add paired register support for inline asm with 64-bit data on ARM
>
> Added:
> llvm/trunk/test/CodeGen/ARM/inlineasm-64bit.ll
> Modified:
> llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp
> llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
> llvm/trunk/test/CodeGen/ARM/arm-modifier.ll
>
> Modified: llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp?rev=175088&r1=175087&r2=175088&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMAsmPrinter.cpp Wed Feb 13 15:43:02 2013
> @@ -342,6 +342,11 @@ void ARMAsmPrinter::printOperand(const M
> unsigned Reg = MO.getReg();
> assert(TargetRegisterInfo::isPhysicalRegister(Reg));
> assert(!MO.getSubReg() && "Subregs should be eliminated!");
> + if(ARM::GPRPairRegClass.contains(Reg)) {
> + const MachineFunction &MF = *MI->getParent()->getParent();
> + const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
> + Reg = TRI->getSubReg(Reg, ARM::gsub_0);
> + }
> O << ARMInstPrinter::getRegisterName(Reg);
> break;
> }
> @@ -530,14 +535,12 @@ bool ARMAsmPrinter::PrintAsmOperand(cons
> const MachineOperand &MO = MI->getOperand(OpNum);
> if (!MO.isReg())
> return true;
> - const TargetRegisterClass &RC = ARM::GPRRegClass;
> const MachineFunction &MF = *MI->getParent()->getParent();
> const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
> -
> - unsigned RegIdx = TRI->getEncodingValue(MO.getReg());
> - RegIdx |= 1; //The odd register is also the higher-numbered one of a pair.
> -
> - unsigned Reg = RC.getRegister(RegIdx);
> + unsigned Reg = MO.getReg();
> + if(!ARM::GPRPairRegClass.contains(Reg))
> + return false;
> + Reg = TRI->getSubReg(Reg, ARM::gsub_1);
> O << ARMInstPrinter::getRegisterName(Reg);
> return false;
> }
>
> Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=175088&r1=175087&r2=175088&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Wed Feb 13 15:43:02 2013
> @@ -19,6 +19,7 @@
> #include "llvm/CodeGen/MachineFrameInfo.h"
> #include "llvm/CodeGen/MachineFunction.h"
> #include "llvm/CodeGen/MachineInstrBuilder.h"
> +#include "llvm/CodeGen/MachineRegisterInfo.h"
> #include "llvm/CodeGen/SelectionDAG.h"
> #include "llvm/CodeGen/SelectionDAGISel.h"
> #include "llvm/IR/CallingConv.h"
> @@ -257,6 +258,8 @@ private:
> // Select special operations if node forms integer ABS pattern
> SDNode *SelectABSOp(SDNode *N);
>
> + SDNode *SelectInlineAsm(SDNode *N);
> +
> SDNode *SelectConcatVector(SDNode *N);
>
> SDNode *SelectAtomic64(SDNode *Node, unsigned Opc);
> @@ -2552,6 +2555,12 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *
>
> switch (N->getOpcode()) {
> default: break;
> + case ISD::INLINEASM: {
> + SDNode *ResNode = SelectInlineAsm(N);
> + if (ResNode)
> + return ResNode;
> + break;
> + }
> case ISD::XOR: {
> // Select special operations if XOR node forms integer ABS pattern
> SDNode *ResNode = SelectABSOp(N);
> @@ -3446,6 +3455,138 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *
> return SelectCode(N);
> }
>
> +SDNode *ARMDAGToDAGISel::SelectInlineAsm(SDNode *N){
> + std::vector<SDValue> AsmNodeOperands;
> + unsigned Flag, Kind;
> + bool Changed = false;
> + unsigned NumOps = N->getNumOperands();
> +
> + ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(
> + N->getOperand(InlineAsm::Op_AsmString));
> + StringRef AsmString = StringRef(S->getSymbol());
> +
> + // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
> + // However, some instrstions (e.g. ldrexd/strexd in ARM mode) require
> + // (even/even+1) GPRs and use %n and %Hn to refer to the individual regs
> + // respectively. Since there is no constraint to explicitly specify a
> + // reg pair, we search %H operand inside the asm string. If it is found, the
> + // transformation below enforces a GPRPair reg class for "%r" for 64-bit data.
> + if (AsmString.find(":H}") == StringRef::npos)
> + return NULL;
> +
> + DebugLoc dl = N->getDebugLoc();
> + SDValue Glue = N->getOperand(NumOps-1);
> +
> + // Glue node will be appended late.
> + for(unsigned i = 0; i < NumOps -1; ++i) {
> + SDValue op = N->getOperand(i);
> + AsmNodeOperands.push_back(op);
> +
> + if (i < InlineAsm::Op_FirstOperand)
> + continue;
> +
> + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
> + Flag = C->getZExtValue();
> + Kind = InlineAsm::getKind(Flag);
> + }
> + else
> + continue;
> +
> + if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
> + && Kind != InlineAsm::Kind_RegDefEarlyClobber)
> + continue;
> +
> + unsigned RegNum = InlineAsm::getNumOperandRegisters(Flag);
> + unsigned RC;
> + bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
> + if (!HasRC || RC != ARM::GPRRegClassID || RegNum != 2)
> + continue;
> +
> + assert((i+2 < NumOps-1) && "Invalid number of operands in inline asm");
> + SDValue V0 = N->getOperand(i+1);
> + SDValue V1 = N->getOperand(i+2);
> + unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
> + unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
> + SDValue PairedReg;
> + MachineRegisterInfo &MRI = MF->getRegInfo();
> +
> + if (Kind == InlineAsm::Kind_RegDef ||
> + Kind == InlineAsm::Kind_RegDefEarlyClobber) {
> + // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
> + // the original GPRs.
> +
> + unsigned GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
> + PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
> + SDValue Chain = SDValue(N,0);
> +
> + SDNode *GU = N->getGluedUser();
> + SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::Untyped,
> + Chain.getValue(1));
> +
> + // Extract values from a GPRPair reg and copy to the original GPR reg.
> + SDValue Sub0 = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
> + RegCopy);
> + SDValue Sub1 = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
> + RegCopy);
> + SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
> + RegCopy.getValue(1));
> + SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
> +
> + // Update the original glue user.
> + std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
> + Ops.push_back(T1.getValue(1));
> + CurDAG->UpdateNodeOperands(GU, &Ops[0], Ops.size());
> + GU = T1.getNode();
> + }
> + else {
> + // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
> + // GPRPair and then pass the GPRPair to the inline asm.
> + SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
> +
> + // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
> + SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
> + Chain.getValue(1));
> + SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
> + T0.getValue(1));
> + SDValue Pair = SDValue(createGPRPairNode(MVT::Untyped, T0, T1), 0);
> +
> + // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
> + // i32 VRs of inline asm with it.
> + unsigned GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
> + PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
> + Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
> +
> + AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
> + Glue = Chain.getValue(1);
> + }
> +
> + Changed = true;
> +
> + if(PairedReg.getNode()) {
> + Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
> + Flag = InlineAsm::getFlagWordForRegClass(Flag, ARM::GPRPairRegClassID);
> + // Replace the current flag.
> + AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
> + Flag, MVT::i32);
> + // Add the new register node and skip the original two GPRs.
> + AsmNodeOperands.push_back(PairedReg);
> + // Skip the next two GPRs.
> + i += 2;
> + }
> + }
> +
> + AsmNodeOperands.push_back(Glue);
> + if (!Changed)
> + return NULL;
> +
> + SDValue New = CurDAG->getNode(ISD::INLINEASM, N->getDebugLoc(),
> + CurDAG->getVTList(MVT::Other, MVT::Glue), &AsmNodeOperands[0],
> + AsmNodeOperands.size());
> + New->setNodeId(-1);
> + return New.getNode();
> +}
> +
> +
> bool ARMDAGToDAGISel::
> SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
> std::vector<SDValue> &OutOps) {
>
> Modified: llvm/trunk/test/CodeGen/ARM/arm-modifier.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-modifier.ll?rev=175088&r1=175087&r2=175088&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/arm-modifier.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/arm-modifier.ll Wed Feb 13 15:43:02 2013
> @@ -61,8 +61,7 @@ ret void
> define i64 @f4(i64* %val) nounwind {
> entry:
> ;CHECK: f4
> - ;CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], {{r[0-9]?[13579]}}, [r0]
> - ;CHECK: mov r0, [[REG1]]
> + ;CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> %0 = tail call i64 asm sideeffect "ldrexd $0, ${0:H}, [$1]", "=&r,r,*Qo"(i64* %val, i64* %val) nounwind
> ret i64 %0
> }
>
> Added: llvm/trunk/test/CodeGen/ARM/inlineasm-64bit.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/inlineasm-64bit.ll?rev=175088&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/inlineasm-64bit.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/inlineasm-64bit.ll Wed Feb 13 15:43:02 2013
> @@ -0,0 +1,54 @@
> +; RUN: llc < %s -O3 -march=arm | FileCheck %s
> +
> +; check if regs are passing correctly
> +define void @i64_write(i64* %p, i64 %val) nounwind {
> +; CHECK: i64_write:
> +; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; CHECK: strexd [[REG1]], {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
> + %1 = tail call i64 asm sideeffect "1: ldrexd $0, ${0:H}, [$2]\0A strexd $0, $3, ${3:H}, [$2]\0A teq $0, #0\0A bne 1b", "=&r,=*Qo,r,r,~{cc}"(i64* %p, i64* %p, i64 %val) nounwind
> + ret void
> +}
> +
> +; check if register allocation can reuse the registers
> +define void @multi_writes(i64* %p, i64 %val1, i64 %val2, i64 %val3, i64 %val4, i64 %val5, i64 %val6) nounwind {
> +entry:
> +; CHECK: multi_writes:
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; check: strexd {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +
> + tail call void asm sideeffect " strexd $1, ${1:H}, [$0]\0A strexd $2, ${2:H}, [$0]\0A strexd $3, ${3:H}, [$0]\0A strexd $4, ${4:H}, [$0]\0A strexd $5, ${5:H}, [$0]\0A strexd $6, ${6:H}, [$0]\0A", "r,r,r,r,r,r,r"(i64* %p, i64 %val1, i64 %val2, i64 %val3, i64 %val4, i64 %val5, i64 %val6) nounwind
> + %incdec.ptr = getelementptr inbounds i64* %p, i32 1
> + tail call void asm sideeffect " strexd $1, ${1:H}, [$0]\0A strexd $2, ${2:H}, [$0]\0A strexd $3, ${3:H}, [$0]\0A strexd $4, ${4:H}, [$0]\0A strexd $5, ${5:H}, [$0]\0A strexd $6, ${6:H}, [$0]\0A", "r,r,r,r,r,r,r"(i64* %incdec.ptr, i64 %val1, i64 %val2, i64 %val3, i64 %val4, i64 %val5, i64 %val6) nounwind
> + tail call void asm sideeffect " strexd $1, ${1:H}, [$0]\0A strexd $2, ${2:H}, [$0]\0A strexd $3, ${3:H}, [$0]\0A strexd $4, ${4:H}, [$0]\0A strexd $5, ${5:H}, [$0]\0A strexd $6, ${6:H}, [$0]\0A", "r,r,r,r,r,r,r"(i64* %incdec.ptr, i64 %val1, i64 %val2, i64 %val3, i64 %val4, i64 %val5, i64 %val6) nounwind
> + ret void
> +}
> +
> +
> +; check if callee-saved registers used by inline asm are saved/restored
> +define void @foo(i64* %p, i64 %i) nounwind {
> +; CHECK:foo:
> +; CHECK: push {{{r[4-9]|r10|r11}}
> +; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], {{r[0-9]?[13579]}}, [r{{[0-9]+}}]
> +; CHECK: strexd [[REG1]], {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
> +; CHECK: pop {{{r[4-9]|r10|r11}}
> + %1 = tail call { i64, i64 } asm sideeffect "@ atomic64_set\0A1: ldrexd $0, ${0:H}, [$3]\0Aldrexd $1, ${1:H}, [$3]\0A strexd $0, $4, ${4:H}, [$3]\0A teq $0, #0\0A bne 1b", "=&r,=&r,=*Qo,r,r,~{cc}"(i64* %p, i64* %p, i64 %i) nounwind
> + ret void
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list