Split up the ARM so_reg ComplexPattern into so_reg_reg and so_reg_imm, allowing us to distinguish the encodings that use shifted registers from those that use shifted immediates. This is necessary to allow the fixed-length decoder to distinguish things like BICS vs LDRH.

llvm-svn: 135693
This commit is contained in:
Owen Anderson 2011-07-21 18:54:16 +00:00
parent 49bf76bab3
commit b595ed0085
7 changed files with 334 additions and 70 deletions

View File

@ -172,7 +172,7 @@ ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
ARM_AM::ShiftOpc ShOpc = ARM_AM::getAM2ShiftOpc(OffImm);
unsigned SOOpc = ARM_AM::getSORegOpc(ShOpc, Amt);
UpdateMI = BuildMI(MF, MI->getDebugLoc(),
get(isSub ? ARM::SUBrs : ARM::ADDrs), WBReg)
get(isSub ? ARM::SUBrsi : ARM::ADDrsi), WBReg)
.addReg(BaseReg).addReg(OffReg).addReg(0).addImm(SOOpc)
.addImm(Pred).addReg(0).addReg(0);
} else

View File

@ -741,7 +741,8 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
MI.eraseFromParent();
return true;
}
case ARM::MOVCCs: {
case ARM::MOVCCsi:
case ARM::MOVCCsr: {
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVs),
(MI.getOperand(1).getReg()))
.addReg(MI.getOperand(2).getReg(),

View File

@ -90,13 +90,20 @@ public:
bool hasNoVMLxHazardUse(SDNode *N) const;
bool isShifterOpProfitable(const SDValue &Shift,
ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt);
bool SelectShifterOperandReg(SDValue N, SDValue &A,
bool SelectRegShifterOperand(SDValue N, SDValue &A,
SDValue &B, SDValue &C,
bool CheckProfitability = true);
bool SelectImmShifterOperand(SDValue N, SDValue &A,
SDValue &B, SDValue &C,
bool CheckProfitability = true);
bool SelectShiftShifterOperandReg(SDValue N, SDValue &A,
SDValue &B, SDValue &C) {
// Don't apply the profitability check
return SelectShifterOperandReg(N, A, B, C, false);
if (SelectImmShifterOperand(N, A, B, C, false))
return true;
else if (SelectRegShifterOperand(N, A, B, C, false))
return true;
return false;
}
bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
@ -365,7 +372,7 @@ bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
return ShOpcVal == ARM_AM::lsl && ShAmt == 2;
}
bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue N,
bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
SDValue &BaseReg,
SDValue &ShReg,
SDValue &Opc,
@ -381,19 +388,43 @@ bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue N,
BaseReg = N.getOperand(0);
unsigned ShImmVal = 0;
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
ShReg = CurDAG->getRegister(0, MVT::i32);
ShImmVal = RHS->getZExtValue() & 31;
} else {
ShReg = N.getOperand(1);
if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal))
return false;
}
ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
if (!RHS) return false;
ShReg = CurDAG->getRegister(0, MVT::i32);
ShImmVal = RHS->getZExtValue() & 31;
Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
MVT::i32);
return true;
}
bool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N,
SDValue &BaseReg,
SDValue &ShReg,
SDValue &Opc,
bool CheckProfitability) {
if (DisableShifterOp)
return false;
ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
// Don't match base register only case. That is matched to a separate
// lower complexity pattern with explicit register operand.
if (ShOpcVal == ARM_AM::no_shift) return false;
BaseReg = N.getOperand(0);
unsigned ShImmVal = 0;
ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
if (RHS) return false;
ShReg = N.getOperand(1);
if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal))
return false;
Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
MVT::i32);
return true;
}
bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N,
SDValue &Base,
SDValue &OffImm) {
@ -2036,10 +2067,16 @@ SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
SDValue CPTmp0;
SDValue CPTmp1;
SDValue CPTmp2;
if (SelectShifterOperandReg(TrueVal, CPTmp0, CPTmp1, CPTmp2)) {
if (SelectImmShifterOperand(TrueVal, CPTmp0, CPTmp1, CPTmp2)) {
SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag };
return CurDAG->SelectNodeTo(N, ARM::MOVCCs, MVT::i32, Ops, 7);
return CurDAG->SelectNodeTo(N, ARM::MOVCCsi, MVT::i32, Ops, 7);
}
if (SelectRegShifterOperand(TrueVal, CPTmp0, CPTmp1, CPTmp2)) {
SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag };
return CurDAG->SelectNodeTo(N, ARM::MOVCCsr, MVT::i32, Ops, 7);
}
return 0;
}
@ -2309,7 +2346,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
return CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops, 6);
} else {
SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 };
return CurDAG->SelectNodeTo(N, ARM::ADDrs, MVT::i32, Ops, 7);
return CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops, 7);
}
}
if (isPowerOf2_32(RHSV+1)) { // 2^n-1?
@ -2325,7 +2362,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
return CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops, 6);
} else {
SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 };
return CurDAG->SelectNodeTo(N, ARM::RSBrs, MVT::i32, Ops, 7);
return CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops, 7);
}
}
}

View File

@ -5224,15 +5224,19 @@ struct AddSubFlagsOpcodePair {
static AddSubFlagsOpcodePair AddSubFlagsOpcodeMap[] = {
{ARM::ADCSri, ARM::ADCri},
{ARM::ADCSrr, ARM::ADCrr},
{ARM::ADCSrs, ARM::ADCrs},
{ARM::ADCSrsi, ARM::ADCrsi},
{ARM::ADCSrsr, ARM::ADCrsr},
{ARM::SBCSri, ARM::SBCri},
{ARM::SBCSrr, ARM::SBCrr},
{ARM::SBCSrs, ARM::SBCrs},
{ARM::SBCSrsi, ARM::SBCrsi},
{ARM::SBCSrsr, ARM::SBCrsr},
{ARM::RSBSri, ARM::RSBri},
{ARM::RSBSrr, ARM::RSBrr},
{ARM::RSBSrs, ARM::RSBrs},
{ARM::RSBSrsi, ARM::RSBrsi},
{ARM::RSBSrsr, ARM::RSBrsr},
{ARM::RSCSri, ARM::RSCri},
{ARM::RSCSrs, ARM::RSCrs},
{ARM::RSCSrsi, ARM::RSCrsi},
{ARM::RSCSrsr, ARM::RSCrsr},
{ARM::t2ADCSri, ARM::t2ADCri},
{ARM::t2ADCSrr, ARM::t2ADCrr},
{ARM::t2ADCSrs, ARM::t2ADCrs},

View File

@ -423,15 +423,29 @@ def ShiftedRegAsmOperand : AsmOperandClass {
let Name = "ShiftedReg";
}
// shifter_operand operands: so_reg and so_imm.
def so_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectShifterOperandReg",
[shl,srl,sra,rotr]> {
def ShiftedImmAsmOperand : AsmOperandClass {
let Name = "ShiftedImm";
}
// shifter_operand operands: so_reg_reg, so_reg_imm, and so_imm.
def so_reg_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectRegShifterOperand",
[shl, srl, sra, rotr]> {
let EncoderMethod = "getSORegOpValue";
let PrintMethod = "printSORegOperand";
let ParserMatchClass = ShiftedRegAsmOperand;
let MIOperandInfo = (ops GPR, GPR, shift_imm);
}
def so_reg_imm : Operand<i32>, // reg imm
ComplexPattern<i32, 3, "SelectImmShifterOperand",
[shl, srl, sra, rotr]> {
let EncoderMethod = "getSORegOpValue";
let PrintMethod = "printSORegOperand";
let ParserMatchClass = ShiftedImmAsmOperand;
let MIOperandInfo = (ops GPR, GPR, shift_imm);
}
// FIXME: Does this need to be distinct from so_reg?
def shift_so_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectShiftShifterOperandReg",
@ -755,16 +769,37 @@ multiclass AsI1_bin_irs<bits<4> opcod, string opc,
let Inst{11-4} = 0b00000000;
let Inst{3-0} = Rm;
}
def rs : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), DPSoRegFrm,
def rsi : AsI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegFrm,
iis, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg:$shift))]> {
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-0} = shift;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def rsr : AsI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegFrm,
iis, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
// Assembly aliases for optional destination operand when it's the same
@ -780,10 +815,16 @@ multiclass AsI1_bin_irs<bits<4> opcod, string opc,
cc_out:$s)>,
Requires<[IsARM]>;
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
(!cast<Instruction>(!strconcat(baseOpc, "rs")) GPR:$Rdn, GPR:$Rdn,
so_reg:$shift, pred:$p,
(!cast<Instruction>(!strconcat(baseOpc, "rsi")) GPR:$Rdn, GPR:$Rdn,
so_reg_imm:$shift, pred:$p,
cc_out:$s)>,
Requires<[IsARM]>;
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
(!cast<Instruction>(!strconcat(baseOpc, "rsr")) GPR:$Rdn, GPR:$Rdn,
so_reg_reg:$shift, pred:$p,
cc_out:$s)>,
Requires<[IsARM]>;
}
/// AI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the
@ -818,9 +859,10 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
let Inst{11-4} = 0b00000000;
let Inst{3-0} = Rm;
}
def rs : AI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), DPSoRegFrm,
def rsi : AI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegFrm,
iis, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg:$shift))]> {
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
@ -828,7 +870,27 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
let Inst{20} = 1;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-0} = shift;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def rsr : AI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegFrm,
iis, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{20} = 1;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
}
}
@ -864,17 +926,37 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc,
let Inst{11-4} = 0b00000000;
let Inst{3-0} = Rm;
}
def rs : AI1<opcod, (outs), (ins GPR:$Rn, so_reg:$shift), DPSoRegFrm, iis,
def rsi : AI1<opcod, (outs),
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegFrm, iis,
opc, "\t$Rn, $shift",
[(opnode GPR:$Rn, so_reg:$shift)]> {
[(opnode GPR:$Rn, so_reg_imm:$shift)]> {
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{20} = 1;
let Inst{19-16} = Rn;
let Inst{15-12} = 0b0000;
let Inst{11-0} = shift;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def rsr : AI1<opcod, (outs),
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegFrm, iis,
opc, "\t$Rn, $shift",
[(opnode GPR:$Rn, so_reg_reg:$shift)]> {
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{20} = 1;
let Inst{19-16} = Rn;
let Inst{15-12} = 0b0000;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
}
}
@ -1009,17 +1091,37 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
let Inst{15-12} = Rd;
let Inst{19-16} = Rn;
}
def rs : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def rsi : AsI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_imm:$shift),
DPSoRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg:$shift))]>,
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]>,
Requires<[IsARM]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{11-0} = shift;
let Inst{15-12} = Rd;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def rsr : AsI1<opcod, (outs GPR:$Rd),
(ins GPR:$Rn, so_reg_reg:$shift),
DPSoRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]>,
Requires<[IsARM]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
}
// Assembly aliases for optional destination operand when it's the same
@ -1035,8 +1137,13 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
cc_out:$s)>,
Requires<[IsARM]>;
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
(!cast<Instruction>(!strconcat(baseOpc, "rs")) GPR:$Rdn, GPR:$Rdn,
so_reg:$shift, pred:$p,
(!cast<Instruction>(!strconcat(baseOpc, "rsi")) GPR:$Rdn, GPR:$Rdn,
so_reg_imm:$shift, pred:$p,
cc_out:$s)>,
Requires<[IsARM]>;
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
(!cast<Instruction>(!strconcat(baseOpc, "rsr")) GPR:$Rdn, GPR:$Rdn,
so_reg_reg:$shift, pred:$p,
cc_out:$s)>,
Requires<[IsARM]>;
}
@ -1053,9 +1160,12 @@ multiclass AI1_adde_sube_s_irs<PatFrag opnode, bit Commutable = 0> {
[(set GPR:$Rd, (opnode GPR:$Rn, GPR:$Rm))]> {
let isCommutable = Commutable;
}
def rs : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def rsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg:$shift))]>;
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]>;
def rsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]>;
}
}
@ -2338,16 +2448,34 @@ def RSBrr : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
let Inst{19-16} = Rn;
}
def RSBrs : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def RSBrsi : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
DPSoRegFrm, IIC_iALUsr, "rsb", "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (sub so_reg:$shift, GPR:$Rn))]> {
[(set GPR:$Rd, (sub so_reg_imm:$shift, GPR:$Rn))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{11-0} = shift;
let Inst{15-12} = Rd;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def RSBrsr : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
DPSoRegFrm, IIC_iALUsr, "rsb", "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (sub so_reg_reg:$shift, GPR:$Rn))]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
// RSB with 's' bit set.
@ -2359,9 +2487,12 @@ def RSBSri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
def RSBSrr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
4, IIC_iALUr,
[/* For disassembly only; pattern left blank */]>;
def RSBSrs : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def RSBSrsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (subc so_reg:$shift, GPR:$Rn))]>;
[(set GPR:$Rd, (subc so_reg_imm:$shift, GPR:$Rn))]>;
def RSBSrsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (subc so_reg_reg:$shift, GPR:$Rn))]>;
}
let Uses = [CPSR] in {
@ -2391,28 +2522,50 @@ def RSCrr : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
let Inst{15-12} = Rd;
let Inst{19-16} = Rn;
}
def RSCrs : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def RSCrsi : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
DPSoRegFrm, IIC_iALUsr, "rsc", "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (sube_dead_carry so_reg:$shift, GPR:$Rn))]>,
[(set GPR:$Rd, (sube_dead_carry so_reg_imm:$shift, GPR:$Rn))]>,
Requires<[IsARM]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{11-0} = shift;
let Inst{15-12} = Rd;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def RSCrsr : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
DPSoRegFrm, IIC_iALUsr, "rsc", "\t$Rd, $Rn, $shift",
[(set GPR:$Rd, (sube_dead_carry so_reg_reg:$shift, GPR:$Rn))]>,
Requires<[IsARM]> {
bits<4> Rd;
bits<4> Rn;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = Rn;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
}
// NOTE: CPSR def omitted because it will be handled by the custom inserter.
let usesCustomInserter = 1, Uses = [CPSR] in {
def RSCSri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
4, IIC_iALUi,
[(set GPR:$Rd, (sube_dead_carry so_imm:$imm, GPR:$Rn))]>;
def RSCSrs : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift),
def RSCSrsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (sube_dead_carry so_reg:$shift, GPR:$Rn))]>;
[(set GPR:$Rd, (sube_dead_carry so_reg_imm:$shift, GPR:$Rn))]>;
def RSCSrsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
4, IIC_iALUsr,
[(set GPR:$Rd, (sube_dead_carry so_reg_reg:$shift, GPR:$Rn))]>;
}
// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
@ -2684,15 +2837,31 @@ def MVNr : AsI1<0b1111, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMVNr,
let Inst{15-12} = Rd;
let Inst{3-0} = Rm;
}
def MVNs : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg:$shift), DPSoRegFrm,
def MVNsi : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_imm:$shift), DPSoRegFrm,
IIC_iMVNsr, "mvn", "\t$Rd, $shift",
[(set GPR:$Rd, (not so_reg:$shift))]>, UnaryDP {
[(set GPR:$Rd, (not so_reg_imm:$shift))]>, UnaryDP {
bits<4> Rd;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = 0b0000;
let Inst{15-12} = Rd;
let Inst{11-0} = shift;
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
}
def MVNsr : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_reg:$shift), DPSoRegFrm,
IIC_iMVNsr, "mvn", "\t$Rd, $shift",
[(set GPR:$Rd, (not so_reg_reg:$shift))]>, UnaryDP {
bits<4> Rd;
bits<12> shift;
let Inst{25} = 0;
let Inst{19-16} = 0b0000;
let Inst{15-12} = Rd;
let Inst{11-8} = shift{11-8};
let Inst{7} = 0;
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
}
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
def MVNi : AsI1<0b1111, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm,
@ -3156,8 +3325,10 @@ def : ARMPat<(ARMcmpZ GPR:$src, so_imm:$imm),
(CMPri GPR:$src, so_imm:$imm)>;
def : ARMPat<(ARMcmpZ GPR:$src, GPR:$rhs),
(CMPrr GPR:$src, GPR:$rhs)>;
def : ARMPat<(ARMcmpZ GPR:$src, so_reg:$rhs),
(CMPrs GPR:$src, so_reg:$rhs)>;
def : ARMPat<(ARMcmpZ GPR:$src, so_reg_imm:$rhs),
(CMPrsi GPR:$src, so_reg_imm:$rhs)>;
def : ARMPat<(ARMcmpZ GPR:$src, so_reg_reg:$rhs),
(CMPrsr GPR:$src, so_reg_reg:$rhs)>;
// FIXME: We have to be careful when using the CMN instruction and comparison
// with 0. One would expect these two pieces of code should give identical
@ -3243,11 +3414,17 @@ def MOVCCr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$false, GPR:$Rm, pred:$p),
4, IIC_iCMOVr,
[/*(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm, imm:$cc, CCR:$ccr))*/]>,
RegConstraint<"$false = $Rd">;
def MOVCCs : ARMPseudoInst<(outs GPR:$Rd),
(ins GPR:$false, so_reg:$shift, pred:$p),
def MOVCCsi : ARMPseudoInst<(outs GPR:$Rd),
(ins GPR:$false, so_reg_imm:$shift, pred:$p),
4, IIC_iCMOVsr,
[/*(set GPR:$Rd, (ARMcmov GPR:$false, so_reg:$shift, imm:$cc, CCR:$ccr))*/]>,
[/*(set GPR:$Rd, (ARMcmov GPR:$false, so_reg_imm:$shift, imm:$cc, CCR:$ccr))*/]>,
RegConstraint<"$false = $Rd">;
def MOVCCsr : ARMPseudoInst<(outs GPR:$Rd),
(ins GPR:$false, so_reg_reg:$shift, pred:$p),
4, IIC_iCMOVsr,
[/*(set GPR:$Rd, (ARMcmov GPR:$false, so_reg_reg:$shift, imm:$cc, CCR:$ccr))*/]>,
RegConstraint<"$false = $Rd">;
let isMoveImm = 1 in
def MOVCCi16 : ARMPseudoInst<(outs GPR:$Rd),

View File

@ -172,6 +172,7 @@ class ARMOperand : public MCParsedAsmOperand {
DPRRegisterList,
SPRRegisterList,
ShiftedRegister,
ShiftedImmediate,
Shifter,
Token
} Kind;
@ -241,6 +242,11 @@ class ARMOperand : public MCParsedAsmOperand {
unsigned ShiftReg;
unsigned ShiftImm;
} ShiftedReg;
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned SrcReg;
unsigned ShiftImm;
} ShiftedImm;
};
ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
@ -290,6 +296,9 @@ public:
case ShiftedRegister:
ShiftedReg = o.ShiftedReg;
break;
case ShiftedImmediate:
ShiftedImm = o.ShiftedImm;
break;
}
}
@ -468,6 +477,7 @@ public:
bool isMemory() const { return Kind == Memory; }
bool isShifter() const { return Kind == Shifter; }
bool isShiftedReg() const { return Kind == ShiftedRegister; }
bool isShiftedImm() const { return Kind == ShiftedImmediate; }
bool isMemMode2() const {
if (getMemAddrMode() != ARMII::AddrMode2)
return false;
@ -601,15 +611,25 @@ public:
void addShiftedRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
assert(isShiftedReg() && "addShiftedRegOperands() on non ShiftedReg!");
assert((ShiftedReg.ShiftReg == 0 ||
ARM_AM::getSORegOffset(ShiftedReg.ShiftImm) == 0) &&
"Invalid shifted register operand!");
Inst.addOperand(MCOperand::CreateReg(ShiftedReg.SrcReg));
Inst.addOperand(MCOperand::CreateReg(ShiftedReg.ShiftReg));
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(ShiftedReg.ShiftTy, ShiftedReg.ShiftImm)));
}
void addShiftedImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
assert(isShiftedImm() && "addShiftedImmOperands() on non ShiftedImm!");
Inst.addOperand(MCOperand::CreateReg(ShiftedImm.SrcReg));
if (ShiftedImm.ShiftTy == ARM_AM::rrx)
Inst.addOperand(MCOperand::CreateReg(ShiftedImm.SrcReg));
else
Inst.addOperand(MCOperand::CreateReg(0));
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(ShiftedImm.ShiftTy, ShiftedImm.ShiftImm)));
}
void addShifterOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(
@ -885,6 +905,19 @@ public:
return Op;
}
static ARMOperand *CreateShiftedImmediate(ARM_AM::ShiftOpc ShTy,
unsigned SrcReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(ShiftedImmediate);
Op->ShiftedImm.ShiftTy = ShTy;
Op->ShiftedImm.SrcReg = SrcReg;
Op->ShiftedImm.ShiftImm = ShiftImm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(Shifter);
@ -1052,13 +1085,20 @@ void ARMOperand::print(raw_ostream &OS) const {
OS << "<shifter " << ARM_AM::getShiftOpcStr(Shift.ShiftTy) << ">";
break;
case ShiftedRegister:
OS << "<so_reg"
OS << "<so_reg_reg "
<< ShiftedReg.SrcReg
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(ShiftedReg.ShiftImm))
<< ", " << ShiftedReg.ShiftReg << ", "
<< ARM_AM::getSORegOffset(ShiftedReg.ShiftImm)
<< ">";
break;
case ShiftedImmediate:
OS << "<so_reg_imm "
<< ShiftedImm.SrcReg
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(ShiftedImm.ShiftImm))
<< ", " << ARM_AM::getSORegOffset(ShiftedImm.ShiftImm)
<< ">";
break;
case RegisterList:
case DPRRegisterList:
case SPRRegisterList: {
@ -1201,9 +1241,13 @@ int ARMAsmParser::TryParseShiftRegister(
}
}
Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
if (ShiftReg && ShiftTy != ARM_AM::rrx)
Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
ShiftReg, Imm,
S, Parser.getTok().getLoc()));
else
Operands.push_back(ARMOperand::CreateShiftedImmediate(ShiftTy, SrcReg, Imm,
S, Parser.getTok().getLoc()));
return 0;
}

View File

@ -623,7 +623,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ?
MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ?
MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I
MISC("so_reg_imm", "kOperandTypeARMSoReg"); // R, R, I
MISC("so_reg_reg", "kOperandTypeARMSoReg"); // R, R, I
MISC("shift_so_reg", "kOperandTypeARMSoReg"); // R, R, I
MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I
MISC("so_imm", "kOperandTypeARMSoImm"); // I