mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-18 09:09:12 +00:00
Remove hard coded registers in ARM ldrexd and strexd instructions
This patch replaces the hard coded GPR pair [R0, R1] of Intrinsic:arm_ldrexd and [R2, R3] of Intrinsic:arm_strexd with even/odd GPRPair reg class. Similar to the lowering of atomic_64 operation. llvm-svn: 168207
This commit is contained in:
parent
a66c9f2861
commit
85dce59506
@ -266,6 +266,7 @@ private:
|
||||
std::vector<SDValue> &OutOps);
|
||||
|
||||
// Form pairs of consecutive S, D, or Q registers.
|
||||
SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
|
||||
SDNode *PairSRegs(EVT VT, SDValue V0, SDValue V1);
|
||||
SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1);
|
||||
SDNode *PairQRegs(EVT VT, SDValue V0, SDValue V1);
|
||||
@ -1444,6 +1445,17 @@ SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDNode *N) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// \brief Form a GPRPair pseudo register from a pair of GPR regs.
|
||||
SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
|
||||
DebugLoc dl = V0.getNode()->getDebugLoc();
|
||||
SDValue RegClass =
|
||||
CurDAG->getTargetConstant(ARM::GPRPairRegClassID, MVT::i32);
|
||||
SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
|
||||
SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
|
||||
const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
|
||||
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5);
|
||||
}
|
||||
|
||||
/// PairSRegs - Form a D register from a pair of S registers.
|
||||
///
|
||||
SDNode *ARMDAGToDAGISel::PairSRegs(EVT VT, SDValue V0, SDValue V1) {
|
||||
@ -3009,17 +3021,19 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
|
||||
DebugLoc dl = N->getDebugLoc();
|
||||
SDValue Chain = N->getOperand(0);
|
||||
|
||||
unsigned NewOpc = ARM::LDREXD;
|
||||
if (Subtarget->isThumb() && Subtarget->hasThumb2())
|
||||
NewOpc = ARM::t2LDREXD;
|
||||
bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
|
||||
unsigned NewOpc = isThumb ? ARM::t2LDREXD :ARM::LDREXD;
|
||||
|
||||
// arm_ldrexd returns a i64 value in {i32, i32}
|
||||
std::vector<EVT> ResTys;
|
||||
ResTys.push_back(MVT::i32);
|
||||
ResTys.push_back(MVT::i32);
|
||||
if (isThumb) {
|
||||
ResTys.push_back(MVT::i32);
|
||||
ResTys.push_back(MVT::i32);
|
||||
} else
|
||||
ResTys.push_back(MVT::Untyped);
|
||||
ResTys.push_back(MVT::Other);
|
||||
|
||||
// place arguments in the right order
|
||||
// Place arguments in the right order.
|
||||
SmallVector<SDValue, 7> Ops;
|
||||
Ops.push_back(MemAddr);
|
||||
Ops.push_back(getAL(CurDAG));
|
||||
@ -3032,30 +3046,35 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
|
||||
MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
|
||||
cast<MachineSDNode>(Ld)->setMemRefs(MemOp, MemOp + 1);
|
||||
|
||||
// Until there's support for specifing explicit register constraints
|
||||
// like the use of even/odd register pair, hardcode ldrexd to always
|
||||
// use the pair [R0, R1] to hold the load result.
|
||||
Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R0,
|
||||
SDValue(Ld, 0), SDValue(0,0));
|
||||
Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R1,
|
||||
SDValue(Ld, 1), Chain.getValue(1));
|
||||
|
||||
// Remap uses.
|
||||
SDValue Glue = Chain.getValue(1);
|
||||
SDValue Glue = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
|
||||
if (!SDValue(N, 0).use_empty()) {
|
||||
SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||
ARM::R0, MVT::i32, Glue);
|
||||
Glue = Result.getValue(2);
|
||||
SDValue Result;
|
||||
if (isThumb)
|
||||
Result = SDValue(Ld, 0);
|
||||
else {
|
||||
SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
|
||||
SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
||||
dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
|
||||
Result = SDValue(ResNode,0);
|
||||
Glue = Result.getValue(1);
|
||||
}
|
||||
ReplaceUses(SDValue(N, 0), Result);
|
||||
}
|
||||
if (!SDValue(N, 1).use_empty()) {
|
||||
SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||
ARM::R1, MVT::i32, Glue);
|
||||
Glue = Result.getValue(2);
|
||||
SDValue Result;
|
||||
if (isThumb)
|
||||
Result = SDValue(Ld, 1);
|
||||
else {
|
||||
SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
|
||||
SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
|
||||
dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
|
||||
Result = SDValue(ResNode,0);
|
||||
Glue = Result.getValue(1);
|
||||
}
|
||||
ReplaceUses(SDValue(N, 1), Result);
|
||||
}
|
||||
|
||||
ReplaceUses(SDValue(N, 2), SDValue(Ld, 2));
|
||||
ReplaceUses(SDValue(N, 2), Glue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3066,38 +3085,27 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
|
||||
SDValue Val1 = N->getOperand(3);
|
||||
SDValue MemAddr = N->getOperand(4);
|
||||
|
||||
// Until there's support for specifing explicit register constraints
|
||||
// like the use of even/odd register pair, hardcode strexd to always
|
||||
// use the pair [R2, R3] to hold the i64 (i32, i32) value to be stored.
|
||||
Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R2, Val0,
|
||||
SDValue(0, 0));
|
||||
Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R3, Val1, Chain.getValue(1));
|
||||
|
||||
SDValue Glue = Chain.getValue(1);
|
||||
Val0 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||
ARM::R2, MVT::i32, Glue);
|
||||
Glue = Val0.getValue(1);
|
||||
Val1 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||
ARM::R3, MVT::i32, Glue);
|
||||
|
||||
// Store exclusive double return a i32 value which is the return status
|
||||
// of the issued store.
|
||||
std::vector<EVT> ResTys;
|
||||
ResTys.push_back(MVT::i32);
|
||||
ResTys.push_back(MVT::Other);
|
||||
|
||||
// place arguments in the right order
|
||||
bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
|
||||
// Place arguments in the right order.
|
||||
SmallVector<SDValue, 7> Ops;
|
||||
Ops.push_back(Val0);
|
||||
Ops.push_back(Val1);
|
||||
if (isThumb) {
|
||||
Ops.push_back(Val0);
|
||||
Ops.push_back(Val1);
|
||||
} else
|
||||
// arm_strexd uses GPRPair.
|
||||
Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
|
||||
Ops.push_back(MemAddr);
|
||||
Ops.push_back(getAL(CurDAG));
|
||||
Ops.push_back(CurDAG->getRegister(0, MVT::i32));
|
||||
Ops.push_back(Chain);
|
||||
|
||||
unsigned NewOpc = ARM::STREXD;
|
||||
if (Subtarget->isThumb() && Subtarget->hasThumb2())
|
||||
NewOpc = ARM::t2STREXD;
|
||||
unsigned NewOpc = isThumb ? ARM::t2STREXD : ARM::STREXD;
|
||||
|
||||
SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops.data(),
|
||||
Ops.size());
|
||||
|
@ -5807,12 +5807,16 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
|
||||
// for ldrexd must be different.
|
||||
BB = loopMBB;
|
||||
// Load
|
||||
unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
unsigned GPRPair1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc))
|
||||
.addReg(ARM::R2, RegState::Define)
|
||||
.addReg(ARM::R3, RegState::Define).addReg(ptr));
|
||||
.addReg(GPRPair0, RegState::Define).addReg(ptr));
|
||||
// Copy r2/r3 into dest. (This copy will normally be coalesced.)
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo).addReg(ARM::R2);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi).addReg(ARM::R3);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo)
|
||||
.addReg(GPRPair0, 0, ARM::gsub_0);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi)
|
||||
.addReg(GPRPair0, 0, ARM::gsub_1);
|
||||
|
||||
if (IsCmpxchg) {
|
||||
// Add early exit
|
||||
@ -5831,24 +5835,56 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
|
||||
// Copy to physregs for strexd
|
||||
unsigned setlo = MI->getOperand(5).getReg();
|
||||
unsigned sethi = MI->getOperand(6).getReg();
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(setlo);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(sethi);
|
||||
unsigned undef = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), undef);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
|
||||
.addReg(undef)
|
||||
.addReg(setlo)
|
||||
.addImm(ARM::gsub_0);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
|
||||
.addReg(r1)
|
||||
.addReg(sethi)
|
||||
.addImm(ARM::gsub_1);
|
||||
} else if (Op1) {
|
||||
// Perform binary operation
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), ARM::R0)
|
||||
unsigned tmpRegLo = MRI.createVirtualRegister(TRC);
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), tmpRegLo)
|
||||
.addReg(destlo).addReg(vallo))
|
||||
.addReg(NeedsCarry ? ARM::CPSR : 0, getDefRegState(NeedsCarry));
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), ARM::R1)
|
||||
unsigned tmpRegHi = MRI.createVirtualRegister(TRC);
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), tmpRegHi)
|
||||
.addReg(desthi).addReg(valhi)).addReg(0);
|
||||
|
||||
unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
|
||||
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
|
||||
.addReg(UndefPair)
|
||||
.addReg(tmpRegLo)
|
||||
.addImm(ARM::gsub_0);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
|
||||
.addReg(r1)
|
||||
.addReg(tmpRegHi)
|
||||
.addImm(ARM::gsub_1);
|
||||
} else {
|
||||
// Copy to physregs for strexd
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(vallo);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(valhi);
|
||||
unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
|
||||
.addReg(UndefPair)
|
||||
.addReg(vallo)
|
||||
.addImm(ARM::gsub_0);
|
||||
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
|
||||
.addReg(r1)
|
||||
.addReg(valhi)
|
||||
.addImm(ARM::gsub_1);
|
||||
}
|
||||
|
||||
// Store
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess)
|
||||
.addReg(ARM::R0).addReg(ARM::R1).addReg(ptr));
|
||||
.addReg(GPRPair1).addReg(ptr));
|
||||
// Cmp+jump
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri))
|
||||
.addReg(storesuccess).addImm(0));
|
||||
|
@ -417,6 +417,8 @@ def reglist : Operand<i32> {
|
||||
let DecoderMethod = "DecodeRegListOperand";
|
||||
}
|
||||
|
||||
def GPRPairOp : RegisterOperand<GPRPair, "printGPRPairOperand">;
|
||||
|
||||
def DPRRegListAsmOperand : AsmOperandClass { let Name = "DPRRegList"; }
|
||||
def dpr_reglist : Operand<i32> {
|
||||
let EncoderMethod = "getRegisterListOpValue";
|
||||
@ -4229,8 +4231,8 @@ def LDREXH : AIldrex<0b11, (outs GPR:$Rt), (ins addr_offset_none:$addr),
|
||||
def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr),
|
||||
NoItinerary, "ldrex", "\t$Rt, $addr", []>;
|
||||
let hasExtraDefRegAllocReq = 1 in
|
||||
def LDREXD: AIldrex<0b01, (outs GPR:$Rt, GPR:$Rt2),(ins addr_offset_none:$addr),
|
||||
NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", []> {
|
||||
def LDREXD: AIldrex<0b01, (outs GPRPairOp:$Rt),(ins addr_offset_none:$addr),
|
||||
NoItinerary, "ldrexd", "\t$Rt, $addr", []> {
|
||||
let DecoderMethod = "DecodeDoubleRegLoad";
|
||||
}
|
||||
}
|
||||
@ -4244,8 +4246,8 @@ def STREX : AIstrex<0b00, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
|
||||
NoItinerary, "strex", "\t$Rd, $Rt, $addr", []>;
|
||||
let hasExtraSrcRegAllocReq = 1 in
|
||||
def STREXD : AIstrex<0b01, (outs GPR:$Rd),
|
||||
(ins GPR:$Rt, GPR:$Rt2, addr_offset_none:$addr),
|
||||
NoItinerary, "strexd", "\t$Rd, $Rt, $Rt2, $addr", []> {
|
||||
(ins GPRPairOp:$Rt, addr_offset_none:$addr),
|
||||
NoItinerary, "strexd", "\t$Rd, $Rt, $addr", []> {
|
||||
let DecoderMethod = "DecodeDoubleRegStore";
|
||||
}
|
||||
}
|
||||
|
@ -5187,6 +5187,45 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust operands of ldrexd/strexd to MCK_GPRPair.
|
||||
// ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
|
||||
// a single GPRPair reg operand is used in the .td file to replace the two
|
||||
// GPRs. However, when parsing from asm, the two GRPs cannot be automatically
|
||||
// expressed as a GPRPair, so we have to manually merge them.
|
||||
// FIXME: We would really like to be able to tablegen'erate this.
|
||||
if (!isThumb() && Operands.size() > 4 &&
|
||||
(Mnemonic == "ldrexd" || Mnemonic == "strexd")) {
|
||||
bool isLoad = (Mnemonic == "ldrexd");
|
||||
unsigned Idx = isLoad ? 2 : 3;
|
||||
ARMOperand* Op1 = static_cast<ARMOperand*>(Operands[Idx]);
|
||||
ARMOperand* Op2 = static_cast<ARMOperand*>(Operands[Idx+1]);
|
||||
|
||||
const MCRegisterClass& MRC = MRI->getRegClass(ARM::GPRRegClassID);
|
||||
// Adjust only if Op1 and Op2 are GPRs.
|
||||
if (Op1->isReg() && Op2->isReg() && MRC.contains(Op1->getReg()) &&
|
||||
MRC.contains(Op2->getReg())) {
|
||||
unsigned Reg1 = Op1->getReg();
|
||||
unsigned Reg2 = Op2->getReg();
|
||||
unsigned Rt = MRI->getEncodingValue(Reg1);
|
||||
unsigned Rt2 = MRI->getEncodingValue(Reg2);
|
||||
|
||||
// Rt2 must be Rt + 1 and Rt must be even.
|
||||
if (Rt + 1 != Rt2 || (Rt & 1)) {
|
||||
Error(Op2->getStartLoc(), isLoad ?
|
||||
"destination operands must be sequential" :
|
||||
"source operands must be sequential");
|
||||
return true;
|
||||
}
|
||||
unsigned NewReg = MRI->getMatchingSuperReg(Reg1, ARM::gsub_0,
|
||||
&(MRI->getRegClass(ARM::GPRPairRegClassID)));
|
||||
Operands.erase(Operands.begin() + Idx, Operands.begin() + Idx + 2);
|
||||
Operands.insert(Operands.begin() + Idx, ARMOperand::CreateReg(
|
||||
NewReg, Op1->getStartLoc(), Op2->getEndLoc()));
|
||||
delete Op1;
|
||||
delete Op2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5274,8 +5313,7 @@ validateInstruction(MCInst &Inst,
|
||||
switch (Inst.getOpcode()) {
|
||||
case ARM::LDRD:
|
||||
case ARM::LDRD_PRE:
|
||||
case ARM::LDRD_POST:
|
||||
case ARM::LDREXD: {
|
||||
case ARM::LDRD_POST: {
|
||||
// Rt2 must be Rt + 1.
|
||||
unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
|
||||
unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
|
||||
@ -5294,8 +5332,7 @@ validateInstruction(MCInst &Inst,
|
||||
return false;
|
||||
}
|
||||
case ARM::STRD_PRE:
|
||||
case ARM::STRD_POST:
|
||||
case ARM::STREXD: {
|
||||
case ARM::STRD_POST: {
|
||||
// Rt2 must be Rt + 1.
|
||||
unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
|
||||
unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(2).getReg());
|
||||
@ -7483,6 +7520,7 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
bool MatchingInlineAsm) {
|
||||
MCInst Inst;
|
||||
unsigned MatchResult;
|
||||
|
||||
MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
||||
MatchingInlineAsm);
|
||||
switch (MatchResult) {
|
||||
|
@ -252,6 +252,35 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
|
||||
return;
|
||||
}
|
||||
|
||||
// Combine 2 GPRs from disassember into a GPRPair to match with instr def.
|
||||
// ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
|
||||
// a single GPRPair reg operand is used in the .td file to replace the two
|
||||
// GPRs. However, when decoding them, the two GRPs cannot be automatically
|
||||
// expressed as a GPRPair, so we have to manually merge them.
|
||||
// FIXME: We would really like to be able to tablegen'erate this.
|
||||
if (Opcode == ARM::LDREXD || Opcode == ARM::STREXD) {
|
||||
const MCRegisterClass& MRC = MRI.getRegClass(ARM::GPRRegClassID);
|
||||
bool isStore = Opcode == ARM::STREXD;
|
||||
unsigned Reg = MI->getOperand(isStore ? 1 : 0).getReg();
|
||||
if (MRC.contains(Reg)) {
|
||||
MCInst NewMI;
|
||||
MCOperand NewReg;
|
||||
NewMI.setOpcode(Opcode);
|
||||
|
||||
if (isStore)
|
||||
NewMI.addOperand(MI->getOperand(0));
|
||||
NewReg = MCOperand::CreateReg(MRI.getMatchingSuperReg(Reg, ARM::gsub_0,
|
||||
&MRI.getRegClass(ARM::GPRPairRegClassID)));
|
||||
NewMI.addOperand(NewReg);
|
||||
|
||||
// Copy the rest operands into NewMI.
|
||||
for(unsigned i= isStore ? 3 : 2; i < MI->getNumOperands(); ++i)
|
||||
NewMI.addOperand(MI->getOperand(i));
|
||||
printInstruction(&NewMI, O);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printInstruction(MI, O);
|
||||
printAnnotation(O, Annot);
|
||||
}
|
||||
@ -691,6 +720,15 @@ void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum,
|
||||
O << "}";
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printGPRPairOperand(const MCInst *MI, unsigned OpNum,
|
||||
raw_ostream &O) {
|
||||
unsigned Reg = MI->getOperand(OpNum).getReg();
|
||||
printRegName(O, MRI.getSubReg(Reg, ARM::gsub_0));
|
||||
O << ", ";
|
||||
printRegName(O, MRI.getSubReg(Reg, ARM::gsub_1));
|
||||
}
|
||||
|
||||
|
||||
void ARMInstPrinter::printSetendOperand(const MCInst *MI, unsigned OpNum,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
|
@ -124,6 +124,7 @@ public:
|
||||
void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printRotImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printGPRPairOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
|
||||
void printPCLabel(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum,
|
||||
|
@ -1,12 +1,12 @@
|
||||
; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
|
||||
|
||||
define i64 @test1(i64* %ptr, i64 %val) {
|
||||
; CHECK: test1
|
||||
; CHECK: test1:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: adds r0, r2
|
||||
; CHECK: adc r1, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: adds [[REG3:(r[0-9]?[02468])]], [[REG1]]
|
||||
; CHECK: adc [[REG4:(r[0-9]?[13579])]], [[REG2]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -15,12 +15,12 @@ define i64 @test1(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test2(i64* %ptr, i64 %val) {
|
||||
; CHECK: test2
|
||||
; CHECK: test2:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: subs r0, r2
|
||||
; CHECK: sbc r1, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: subs [[REG3:(r[0-9]?[02468])]], [[REG1]]
|
||||
; CHECK: sbc [[REG4:(r[0-9]?[13579])]], [[REG2]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -29,12 +29,12 @@ define i64 @test2(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test3(i64* %ptr, i64 %val) {
|
||||
; CHECK: test3
|
||||
; CHECK: test3:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: and r0, r2
|
||||
; CHECK: and r1, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: and [[REG3:(r[0-9]?[02468])]], [[REG1]]
|
||||
; CHECK: and [[REG4:(r[0-9]?[13579])]], [[REG2]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -43,12 +43,12 @@ define i64 @test3(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test4(i64* %ptr, i64 %val) {
|
||||
; CHECK: test4
|
||||
; CHECK: test4:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: orr r0, r2
|
||||
; CHECK: orr r1, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: orr [[REG3:(r[0-9]?[02468])]], [[REG1]]
|
||||
; CHECK: orr [[REG4:(r[0-9]?[13579])]], [[REG2]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -57,12 +57,12 @@ define i64 @test4(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test5(i64* %ptr, i64 %val) {
|
||||
; CHECK: test5
|
||||
; CHECK: test5:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: eor r0, r2
|
||||
; CHECK: eor r1, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: eor [[REG3:(r[0-9]?[02468])]], [[REG1]]
|
||||
; CHECK: eor [[REG4:(r[0-9]?[13579])]], [[REG2]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -71,10 +71,10 @@ define i64 @test5(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test6(i64* %ptr, i64 %val) {
|
||||
; CHECK: test6
|
||||
; CHECK: test6:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -83,13 +83,13 @@ define i64 @test6(i64* %ptr, i64 %val) {
|
||||
}
|
||||
|
||||
define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
|
||||
; CHECK: test7
|
||||
; CHECK: test7:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: cmp r2
|
||||
; CHECK: cmpeq r3
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: cmp [[REG1]]
|
||||
; CHECK: cmpeq [[REG2]]
|
||||
; CHECK: bne
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -100,12 +100,12 @@ define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
|
||||
; Compiles down to cmpxchg
|
||||
; FIXME: Should compile to a single ldrexd
|
||||
define i64 @test8(i64* %ptr) {
|
||||
; CHECK: test8
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: cmp r2
|
||||
; CHECK: cmpeq r3
|
||||
; CHECK: test8:
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: cmp [[REG1]]
|
||||
; CHECK: cmpeq [[REG2]]
|
||||
; CHECK: bne
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
@ -116,10 +116,10 @@ define i64 @test8(i64* %ptr) {
|
||||
; Compiles down to atomicrmw xchg; there really isn't any more efficient
|
||||
; way to write it.
|
||||
define void @test9(i64* %ptr, i64 %val) {
|
||||
; CHECK: test9
|
||||
; CHECK: test9:
|
||||
; CHECK: dmb ish
|
||||
; CHECK: ldrexd r2, r3
|
||||
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
|
||||
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
|
||||
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
|
||||
; CHECK: cmp
|
||||
; CHECK: bne
|
||||
; CHECK: dmb ish
|
||||
|
@ -581,6 +581,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
|
||||
REG("cc_out");
|
||||
REG("s_cc_out");
|
||||
REG("tGPR");
|
||||
REG("GPRPairOp");
|
||||
REG("DPR");
|
||||
REG("DPR_VFP2");
|
||||
REG("DPR_8");
|
||||
|
Loading…
Reference in New Issue
Block a user