mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary: This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80". The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable. To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP). Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations. When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant ) It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt). Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb Reviewed By: efriedma Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D70680
This commit is contained in:
parent
d7e322da8d
commit
69646a28e6
@ -1171,11 +1171,15 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
|
||||
case ARM::ADDri:
|
||||
case ARM::t2ADDri:
|
||||
case ARM::t2ADDri12:
|
||||
case ARM::t2ADDspImm:
|
||||
case ARM::t2ADDspImm12:
|
||||
Offset = -MI->getOperand(2).getImm();
|
||||
break;
|
||||
case ARM::SUBri:
|
||||
case ARM::t2SUBri:
|
||||
case ARM::t2SUBri12:
|
||||
case ARM::t2SUBspImm:
|
||||
case ARM::t2SUBspImm12:
|
||||
Offset = MI->getOperand(2).getImm();
|
||||
break;
|
||||
case ARM::tSUBspi:
|
||||
|
@ -3257,22 +3257,26 @@ bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
|
||||
}
|
||||
break;
|
||||
case ARM::t2ADDrr:
|
||||
case ARM::t2SUBrr:
|
||||
case ARM::t2SUBrr: {
|
||||
if (UseOpc == ARM::t2SUBrr && Commute)
|
||||
return false;
|
||||
|
||||
// ADD/SUB are special because they're essentially the same operation, so
|
||||
// we can handle a larger range of immediates.
|
||||
const bool ToSP = DefMI.getOperand(0).getReg() == ARM::SP;
|
||||
const unsigned t2ADD = ToSP ? ARM::t2ADDspImm : ARM::t2ADDri;
|
||||
const unsigned t2SUB = ToSP ? ARM::t2SUBspImm : ARM::t2SUBri;
|
||||
if (ARM_AM::isT2SOImmTwoPartVal(ImmVal))
|
||||
NewUseOpc = UseOpc == ARM::t2ADDrr ? ARM::t2ADDri : ARM::t2SUBri;
|
||||
NewUseOpc = UseOpc == ARM::t2ADDrr ? t2ADD : t2SUB;
|
||||
else if (ARM_AM::isT2SOImmTwoPartVal(-ImmVal)) {
|
||||
ImmVal = -ImmVal;
|
||||
NewUseOpc = UseOpc == ARM::t2ADDrr ? ARM::t2SUBri : ARM::t2ADDri;
|
||||
NewUseOpc = UseOpc == ARM::t2ADDrr ? t2SUB : t2ADD;
|
||||
} else
|
||||
return false;
|
||||
SOImmValV1 = (uint32_t)ARM_AM::getT2SOImmTwoPartFirst(ImmVal);
|
||||
SOImmValV2 = (uint32_t)ARM_AM::getT2SOImmTwoPartSecond(ImmVal);
|
||||
break;
|
||||
}
|
||||
case ARM::t2ORRrr:
|
||||
case ARM::t2EORrr:
|
||||
if (!ARM_AM::isT2SOImmTwoPartVal(ImmVal))
|
||||
@ -3292,7 +3296,8 @@ bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
|
||||
unsigned OpIdx = Commute ? 2 : 1;
|
||||
Register Reg1 = UseMI.getOperand(OpIdx).getReg();
|
||||
bool isKill = UseMI.getOperand(OpIdx).isKill();
|
||||
Register NewReg = MRI->createVirtualRegister(MRI->getRegClass(Reg));
|
||||
const TargetRegisterClass *TRC = MRI->getRegClass(Reg);
|
||||
Register NewReg = MRI->createVirtualRegister(TRC);
|
||||
BuildMI(*UseMI.getParent(), UseMI, UseMI.getDebugLoc(), get(NewUseOpc),
|
||||
NewReg)
|
||||
.addReg(Reg1, getKillRegState(isKill))
|
||||
@ -3304,6 +3309,18 @@ bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
|
||||
UseMI.getOperand(1).setIsKill();
|
||||
UseMI.getOperand(2).ChangeToImmediate(SOImmValV2);
|
||||
DefMI.eraseFromParent();
|
||||
// FIXME: t2ADDrr should be split, as different rulles apply when writing to SP.
|
||||
// Just as t2ADDri, that was split to [t2ADDri, t2ADDspImm].
|
||||
// Then the below code will not be needed, as the input/output register
|
||||
// classes will be rgpr or gprSP.
|
||||
// For now, we fix the UseMI operand explicitly here:
|
||||
switch(NewUseOpc){
|
||||
case ARM::t2ADDspImm:
|
||||
case ARM::t2SUBspImm:
|
||||
case ARM::t2ADDri:
|
||||
case ARM::t2SUBri:
|
||||
MRI->setRegClass(UseMI.getOperand(0).getReg(), TRC);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -918,10 +918,26 @@ multiclass T2I_bin_ii12rs<bits<3> op23_21, string opc, SDNode opnode,
|
||||
// The register-immediate version is re-materializable. This is useful
|
||||
// in particular for taking the address of a local.
|
||||
let isReMaterializable = 1 in {
|
||||
def spImm : T2sTwoRegImm<
|
||||
(outs GPRsp:$Rd), (ins GPRsp:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
||||
opc, ".w\t$Rd, $Rn, $imm",
|
||||
[]>,
|
||||
Sched<[WriteALU, ReadALU]> {
|
||||
let Rn = 13;
|
||||
let Rd = 13;
|
||||
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{25-24} = 0b01;
|
||||
let Inst{23-21} = op23_21;
|
||||
let Inst{15} = 0;
|
||||
|
||||
let DecoderMethod = "DecodeT2AddSubSPImm";
|
||||
}
|
||||
|
||||
def ri : T2sTwoRegImm<
|
||||
(outs GPRnopc:$Rd), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
||||
(outs rGPR:$Rd), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
||||
opc, ".w\t$Rd, $Rn, $imm",
|
||||
[(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, t2_so_imm:$imm))]>,
|
||||
[(set rGPR:$Rd, (opnode GPRnopc:$Rn, t2_so_imm:$imm))]>,
|
||||
Sched<[WriteALU, ReadALU]> {
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{25} = 0;
|
||||
@ -932,9 +948,9 @@ multiclass T2I_bin_ii12rs<bits<3> op23_21, string opc, SDNode opnode,
|
||||
}
|
||||
// 12-bit imm
|
||||
def ri12 : T2I<
|
||||
(outs GPRnopc:$Rd), (ins GPR:$Rn, imm0_4095:$imm), IIC_iALUi,
|
||||
(outs rGPR:$Rd), (ins GPR:$Rn, imm0_4095:$imm), IIC_iALUi,
|
||||
!strconcat(opc, "w"), "\t$Rd, $Rn, $imm",
|
||||
[(set GPRnopc:$Rd, (opnode GPR:$Rn, imm0_4095:$imm))]>,
|
||||
[(set rGPR:$Rd, (opnode GPR:$Rn, imm0_4095:$imm))]>,
|
||||
Sched<[WriteALU, ReadALU]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
@ -950,6 +966,26 @@ multiclass T2I_bin_ii12rs<bits<3> op23_21, string opc, SDNode opnode,
|
||||
let Inst{11-8} = Rd;
|
||||
let Inst{7-0} = imm{7-0};
|
||||
}
|
||||
def spImm12 : T2I<
|
||||
(outs GPRsp:$Rd), (ins GPRsp:$Rn, imm0_4095:$imm), IIC_iALUi,
|
||||
!strconcat(opc, "w"), "\t$Rd, $Rn, $imm",
|
||||
[]>,
|
||||
Sched<[WriteALU, ReadALU]> {
|
||||
bits<4> Rd = 13;
|
||||
bits<4> Rn = 13;
|
||||
bits<12> imm;
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{26} = imm{11};
|
||||
let Inst{25-24} = 0b10;
|
||||
let Inst{23-21} = op23_21;
|
||||
let Inst{20} = 0; // The S bit.
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15} = 0;
|
||||
let Inst{14-12} = imm{10-8};
|
||||
let Inst{11-8} = Rd;
|
||||
let Inst{7-0} = imm{7-0};
|
||||
let DecoderMethod = "DecodeT2AddSubSPImm";
|
||||
}
|
||||
// register
|
||||
def rr : T2sThreeReg<(outs GPRnopc:$Rd), (ins GPRnopc:$Rn, rGPR:$Rm),
|
||||
IIC_iALUr, opc, ".w\t$Rd, $Rn, $Rm",
|
||||
@ -2267,19 +2303,29 @@ def : t2InstSubst<"sbc${s}${p} $rd, $rn, $imm",
|
||||
(t2ADCri rGPR:$rd, rGPR:$rn, t2_so_imm_not:$imm, pred:$p, s_cc_out:$s)>;
|
||||
|
||||
def : t2InstSubst<"add${s}${p}.w $rd, $rn, $imm",
|
||||
(t2SUBri GPRnopc:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"addw${p} $rd, $rn, $imm",
|
||||
(t2SUBri12 GPRnopc:$rd, GPR:$rn, t2_so_imm_neg:$imm, pred:$p)>;
|
||||
(t2SUBri rGPR:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"sub${s}${p}.w $rd, $rn, $imm",
|
||||
(t2ADDri GPRnopc:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"subw${p} $rd, $rn, $imm",
|
||||
(t2ADDri12 GPRnopc:$rd, GPR:$rn, t2_so_imm_neg:$imm, pred:$p)>;
|
||||
(t2ADDri rGPR:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"subw${p} $Rd, $Rn, $imm",
|
||||
(t2ADDri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
(t2ADDri12 rGPR:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"sub${s}${p} $rd, $rn, $imm",
|
||||
(t2ADDri GPRnopc:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
(t2ADDri rGPR:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"sub${p} $rd, $rn, $imm",
|
||||
(t2ADDri12 GPRnopc:$rd, GPR:$rn, t2_so_imm_neg:$imm, pred:$p)>;
|
||||
(t2ADDri12 rGPR:$rd, GPR:$rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
// SP to SP alike
|
||||
def : t2InstSubst<"add${s}${p}.w $rd, $rn, $imm",
|
||||
(t2SUBspImm GPRsp:$rd, GPRsp:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"sub${s}${p}.w $rd, $rn, $imm",
|
||||
(t2ADDspImm GPRsp:$rd, GPRsp:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"subw${p} $Rd, $Rn, $imm",
|
||||
(t2ADDspImm12 GPRsp:$Rd, GPRsp:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"sub${s}${p} $rd, $rn, $imm",
|
||||
(t2ADDspImm GPRsp:$rd, GPRsp:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
|
||||
def : t2InstSubst<"sub${p} $rd, $rn, $imm",
|
||||
(t2ADDspImm12 GPRsp:$rd, GPRsp:$rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
|
||||
// RSB
|
||||
defm t2RSB : T2I_rbin_irs <0b1110, "rsb", sub>;
|
||||
|
||||
@ -2295,12 +2341,12 @@ defm t2RSBS : T2I_rbin_s_is <ARMsubc>;
|
||||
// The AddedComplexity preferences the first variant over the others since
|
||||
// it can be shrunk to a 16-bit wide encoding, while the others cannot.
|
||||
let AddedComplexity = 1 in
|
||||
def : T2Pat<(add GPR:$src, imm1_255_neg:$imm),
|
||||
(t2SUBri GPR:$src, imm1_255_neg:$imm)>;
|
||||
def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm),
|
||||
(t2SUBri GPR:$src, t2_so_imm_neg:$imm)>;
|
||||
def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm),
|
||||
(t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>;
|
||||
def : T2Pat<(add rGPR:$src, imm1_255_neg:$imm),
|
||||
(t2SUBri rGPR:$src, imm1_255_neg:$imm)>;
|
||||
def : T2Pat<(add rGPR:$src, t2_so_imm_neg:$imm),
|
||||
(t2SUBri rGPR:$src, t2_so_imm_neg:$imm)>;
|
||||
def : T2Pat<(add rGPR:$src, imm0_4095_neg:$imm),
|
||||
(t2SUBri12 rGPR:$src, imm0_4095_neg:$imm)>;
|
||||
def : T2Pat<(add GPR:$src, imm0_65535_neg:$imm),
|
||||
(t2SUBrr GPR:$src, (t2MOVi16 (imm_neg_XFORM imm:$imm)))>;
|
||||
|
||||
@ -2799,10 +2845,10 @@ def : T2Pat<(t2_so_imm_not:$src),
|
||||
// Thumb2SizeReduction's chances later on we select a t2ADD for an or where
|
||||
// possible.
|
||||
def : T2Pat<(or AddLikeOrOp:$Rn, t2_so_imm:$imm),
|
||||
(t2ADDri $Rn, t2_so_imm:$imm)>;
|
||||
(t2ADDri rGPR:$Rn, t2_so_imm:$imm)>;
|
||||
|
||||
def : T2Pat<(or AddLikeOrOp:$Rn, imm0_4095:$Rm),
|
||||
(t2ADDri12 $Rn, imm0_4095:$Rm)>;
|
||||
(t2ADDri12 rGPR:$Rn, imm0_4095:$Rm)>;
|
||||
|
||||
def : T2Pat<(or AddLikeOrOp:$Rn, non_imm32:$Rm),
|
||||
(t2ADDrr $Rn, $Rm)>;
|
||||
@ -4666,10 +4712,10 @@ def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $ShiftedRm",
|
||||
|
||||
// Aliases for ADD without the ".w" optional width specifier.
|
||||
def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2ADDri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p,
|
||||
(t2ADDri rGPR:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstAlias<"add${p} $Rd, $Rn, $imm",
|
||||
(t2ADDri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
(t2ADDri12 rGPR:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"add${s}${p} $Rd, $Rn, $Rm",
|
||||
(t2ADDrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"add${s}${p} $Rd, $Rn, $ShiftedRm",
|
||||
@ -4677,9 +4723,11 @@ def : t2InstAlias<"add${s}${p} $Rd, $Rn, $ShiftedRm",
|
||||
pred:$p, cc_out:$s)>;
|
||||
// ... and with the destination and source register combined.
|
||||
def : t2InstAlias<"add${s}${p} $Rdn, $imm",
|
||||
(t2ADDri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
(t2ADDri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"add${p} $Rdn, $imm",
|
||||
(t2ADDri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
(t2ADDri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"addw${p} $Rdn, $imm",
|
||||
(t2ADDri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"add${s}${p} $Rdn, $Rm",
|
||||
(t2ADDrr GPRnopc:$Rdn, GPRnopc:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"add${s}${p} $Rdn, $ShiftedRm",
|
||||
@ -4688,33 +4736,33 @@ def : t2InstAlias<"add${s}${p} $Rdn, $ShiftedRm",
|
||||
|
||||
// add w/ negative immediates is just a sub.
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
(t2SUBri rGPR:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"add${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"add${s}${p} $Rdn, $imm",
|
||||
(t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
(t2SUBri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"add${p} $Rdn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
def : t2InstSubst<"add${s}${p}.w $Rd, $Rn, $imm",
|
||||
(t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
(t2SUBri rGPR:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"addw${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rd, rGPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"add${s}${p}.w $Rdn, $imm",
|
||||
(t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
(t2SUBri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"addw${p} $Rdn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
|
||||
// Aliases for SUB without the ".w" optional width specifier.
|
||||
def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
(t2SUBri rGPR:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $Rm",
|
||||
(t2SUBrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $ShiftedRm",
|
||||
@ -4722,9 +4770,11 @@ def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $ShiftedRm",
|
||||
pred:$p, cc_out:$s)>;
|
||||
// ... and with the destination and source register combined.
|
||||
def : t2InstAlias<"sub${s}${p} $Rdn, $imm",
|
||||
(t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
(t2SUBri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${p} $Rdn, $imm",
|
||||
(t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
(t2SUBri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"subw${p} $Rdn, $imm",
|
||||
(t2SUBri12 rGPR:$Rdn, rGPR:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"sub${s}${p}.w $Rdn, $Rm",
|
||||
(t2SUBrr GPRnopc:$Rdn, GPRnopc:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${s}${p} $Rdn, $Rm",
|
||||
@ -4733,6 +4783,65 @@ def : t2InstAlias<"sub${s}${p} $Rdn, $ShiftedRm",
|
||||
(t2SUBrs GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_reg:$ShiftedRm,
|
||||
pred:$p, cc_out:$s)>;
|
||||
|
||||
// SP to SP alike aliases
|
||||
// Aliases for ADD without the ".w" optional width specifier.
|
||||
def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2ADDspImm GPRsp:$Rd, GPRsp:$Rn, t2_so_imm:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstAlias<"add${p} $Rd, $Rn, $imm",
|
||||
(t2ADDspImm12 GPRsp:$Rd, GPRsp:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
// ... and with the destination and source register combined.
|
||||
def : t2InstAlias<"add${s}${p} $Rdn, $imm",
|
||||
(t2ADDspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
|
||||
def : t2InstAlias<"add${s}${p}.w $Rdn, $imm",
|
||||
(t2ADDspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
|
||||
def : t2InstAlias<"add${p} $Rdn, $imm",
|
||||
(t2ADDspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
|
||||
def : t2InstAlias<"addw${p} $Rdn, $imm",
|
||||
(t2ADDspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
|
||||
// add w/ negative immediates is just a sub.
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rd, GPRsp:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"add${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rd, GPRsp:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"add${s}${p} $Rdn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"add${p} $Rdn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
def : t2InstSubst<"add${s}${p}.w $Rd, $Rn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rd, GPRsp:$Rn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"addw${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rd, GPRsp:$Rn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
def : t2InstSubst<"add${s}${p}.w $Rdn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm_neg:$imm, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : t2InstSubst<"addw${p} $Rdn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095_neg:$imm, pred:$p)>;
|
||||
|
||||
|
||||
// Aliases for SUB without the ".w" optional width specifier.
|
||||
def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rd, GPRsp:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rd, GPRsp:$Rn, imm0_4095:$imm, pred:$p)>;
|
||||
// ... and with the destination and source register combined.
|
||||
def : t2InstAlias<"sub${s}${p} $Rdn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${s}${p}.w $Rdn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rdn, GPRsp:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : t2InstAlias<"sub${p} $Rdn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
def : t2InstAlias<"subw${p} $Rdn, $imm",
|
||||
(t2SUBspImm12 GPRsp:$Rdn, GPRsp:$Rdn, imm0_4095:$imm, pred:$p)>;
|
||||
|
||||
// Alias for compares without the ".w" optional width specifier.
|
||||
def : t2InstAlias<"cmn${p} $Rn, $Rm",
|
||||
(t2CMNzrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>;
|
||||
@ -4989,10 +5098,16 @@ def : t2InstSubst<"orr${s}${p} $Rdn, $imm",
|
||||
pred:$p, cc_out:$s)>;
|
||||
// Likewise, "add Rd, t2_so_imm_neg" -> sub
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm,
|
||||
(t2SUBri rGPR:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm,
|
||||
pred:$p, cc_out:$s)>;
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $Rn, $imm",
|
||||
(t2SUBspImm GPRsp:$Rd, GPRsp:$Rn, t2_so_imm_neg:$imm,
|
||||
pred:$p, cc_out:$s)>;
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $imm",
|
||||
(t2SUBri GPRnopc:$Rd, GPRnopc:$Rd, t2_so_imm_neg:$imm,
|
||||
(t2SUBri rGPR:$Rd, rGPR:$Rd, t2_so_imm_neg:$imm,
|
||||
pred:$p, cc_out:$s)>;
|
||||
def : t2InstSubst<"add${s}${p} $Rd, $imm",
|
||||
(t2SUBspImm GPRsp:$Rd, GPRsp:$Rd, t2_so_imm_neg:$imm,
|
||||
pred:$p, cc_out:$s)>;
|
||||
// Same for CMP <--> CMN via t2_so_imm_neg
|
||||
def : t2InstSubst<"cmp${p} $Rd, $imm",
|
||||
|
@ -696,18 +696,23 @@ MachineInstr *ARMLoadStoreOpt::CreateLoadStoreMulti(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int BaseOpc =
|
||||
isThumb2 ? ARM::t2ADDri :
|
||||
(isThumb1 && Base == ARM::SP) ? ARM::tADDrSPi :
|
||||
(isThumb1 && Offset < 8) ? ARM::tADDi3 :
|
||||
isThumb1 ? ARM::tADDi8 : ARM::ADDri;
|
||||
int BaseOpc = isThumb2 ? (BaseKill && Base == ARM::SP ? ARM::t2ADDspImm
|
||||
: ARM::t2ADDri)
|
||||
: (isThumb1 && Base == ARM::SP)
|
||||
? ARM::tADDrSPi
|
||||
: (isThumb1 && Offset < 8)
|
||||
? ARM::tADDi3
|
||||
: isThumb1 ? ARM::tADDi8 : ARM::ADDri;
|
||||
|
||||
if (Offset < 0) {
|
||||
Offset = - Offset;
|
||||
BaseOpc =
|
||||
isThumb2 ? ARM::t2SUBri :
|
||||
(isThumb1 && Offset < 8 && Base != ARM::SP) ? ARM::tSUBi3 :
|
||||
isThumb1 ? ARM::tSUBi8 : ARM::SUBri;
|
||||
// FIXME: There are no Thumb1 load/store instructions with negative
|
||||
// offsets. So the Base != ARM::SP might be unnecessary.
|
||||
Offset = -Offset;
|
||||
BaseOpc = isThumb2 ? (BaseKill && Base == ARM::SP ? ARM::t2SUBspImm
|
||||
: ARM::t2SUBri)
|
||||
: (isThumb1 && Offset < 8 && Base != ARM::SP)
|
||||
? ARM::tSUBi3
|
||||
: isThumb1 ? ARM::tSUBi8 : ARM::SUBri;
|
||||
}
|
||||
|
||||
if (!TL->isLegalAddImmediate(Offset))
|
||||
@ -1186,8 +1191,10 @@ static int isIncrementOrDecrement(const MachineInstr &MI, unsigned Reg,
|
||||
case ARM::tADDi8: Scale = 4; CheckCPSRDef = true; break;
|
||||
case ARM::tSUBi8: Scale = -4; CheckCPSRDef = true; break;
|
||||
case ARM::t2SUBri:
|
||||
case ARM::t2SUBspImm:
|
||||
case ARM::SUBri: Scale = -1; CheckCPSRDef = true; break;
|
||||
case ARM::t2ADDri:
|
||||
case ARM::t2ADDspImm:
|
||||
case ARM::ADDri: Scale = 1; CheckCPSRDef = true; break;
|
||||
case ARM::tADDspi: Scale = 4; CheckCPSRDef = false; break;
|
||||
case ARM::tSUBspi: Scale = -4; CheckCPSRDef = false; break;
|
||||
|
@ -6554,7 +6554,8 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
|
||||
// Check against T3. If the second register is the PC, this is an
|
||||
// alternate form of ADR, which uses encoding T4, so check for that too.
|
||||
if (static_cast<ARMOperand &>(*Operands[4]).getReg() != ARM::PC &&
|
||||
static_cast<ARMOperand &>(*Operands[5]).isT2SOImm())
|
||||
(static_cast<ARMOperand &>(*Operands[5]).isT2SOImm() ||
|
||||
static_cast<ARMOperand &>(*Operands[5]).isT2SOImmNeg()))
|
||||
return false;
|
||||
|
||||
// Otherwise, we use encoding T4, which does not have a cc_out
|
||||
@ -6609,9 +6610,34 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
|
||||
static_cast<ARMOperand &>(*Operands[1]).getReg() == 0 &&
|
||||
(static_cast<ARMOperand &>(*Operands[4]).isImm() ||
|
||||
(Operands.size() == 6 &&
|
||||
static_cast<ARMOperand &>(*Operands[5]).isImm())))
|
||||
return true;
|
||||
|
||||
static_cast<ARMOperand &>(*Operands[5]).isImm()))) {
|
||||
// Thumb2 (add|sub){s}{p}.w GPRnopc, sp, #{T2SOImm} has cc_out
|
||||
return (!(isThumbTwo() &&
|
||||
(static_cast<ARMOperand &>(*Operands[4]).isT2SOImm() ||
|
||||
static_cast<ARMOperand &>(*Operands[4]).isT2SOImmNeg())));
|
||||
}
|
||||
// Fixme: Should join all the thumb+thumb2 (add|sub) in a single if case
|
||||
// Thumb2 ADD r0, #4095 -> ADDW r0, r0, #4095 (T4)
|
||||
// Thumb2 SUB r0, #4095 -> SUBW r0, r0, #4095
|
||||
if (isThumbTwo() && (Mnemonic == "add" || Mnemonic == "sub") &&
|
||||
(Operands.size() == 5) &&
|
||||
static_cast<ARMOperand &>(*Operands[3]).isReg() &&
|
||||
static_cast<ARMOperand &>(*Operands[3]).getReg() != ARM::SP &&
|
||||
static_cast<ARMOperand &>(*Operands[3]).getReg() != ARM::PC &&
|
||||
static_cast<ARMOperand &>(*Operands[1]).getReg() == 0 &&
|
||||
static_cast<ARMOperand &>(*Operands[4]).isImm()) {
|
||||
const ARMOperand &IMM = static_cast<ARMOperand &>(*Operands[4]);
|
||||
if (IMM.isT2SOImm() || IMM.isT2SOImmNeg())
|
||||
return false; // add.w / sub.w
|
||||
if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(IMM.getImm())) {
|
||||
const int64_t Value = CE->getValue();
|
||||
// Thumb1 imm8 sub / add
|
||||
if ((Value < ((1 << 7) - 1) << 2) && inITBlock() && (!(Value & 3)) &&
|
||||
isARMLowRegister(static_cast<ARMOperand &>(*Operands[3]).getReg()))
|
||||
return false;
|
||||
return true; // Thumb2 T4 addw / subw
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7707,12 +7733,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
|
||||
}
|
||||
break;
|
||||
|
||||
case ARM::t2ADDri:
|
||||
case ARM::t2ADDri12:
|
||||
case ARM::t2ADDrr:
|
||||
case ARM::t2ADDrs:
|
||||
case ARM::t2SUBri:
|
||||
case ARM::t2SUBri12:
|
||||
case ARM::t2SUBrr:
|
||||
case ARM::t2SUBrs:
|
||||
if (Inst.getOperand(0).getReg() == ARM::SP &&
|
||||
@ -9750,23 +9772,33 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
|
||||
}
|
||||
break;
|
||||
case ARM::t2ADDri12:
|
||||
// If the immediate fits for encoding T3 (t2ADDri) and the generic "add"
|
||||
// mnemonic was used (not "addw"), encoding T3 is preferred.
|
||||
if (static_cast<ARMOperand &>(*Operands[0]).getToken() != "add" ||
|
||||
ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1)
|
||||
break;
|
||||
Inst.setOpcode(ARM::t2ADDri);
|
||||
Inst.addOperand(MCOperand::createReg(0)); // cc_out
|
||||
break;
|
||||
case ARM::t2SUBri12:
|
||||
// If the immediate fits for encoding T3 (t2SUBri) and the generic "sub"
|
||||
// mnemonic was used (not "subw"), encoding T3 is preferred.
|
||||
if (static_cast<ARMOperand &>(*Operands[0]).getToken() != "sub" ||
|
||||
case ARM::t2ADDspImm12:
|
||||
case ARM::t2SUBspImm12: {
|
||||
// If the immediate fits for encoding T3 and the generic
|
||||
// mnemonic was used, encoding T3 is preferred.
|
||||
const StringRef Token = static_cast<ARMOperand &>(*Operands[0]).getToken();
|
||||
if ((Token != "add" && Token != "sub") ||
|
||||
ARM_AM::getT2SOImmVal(Inst.getOperand(2).getImm()) == -1)
|
||||
break;
|
||||
Inst.setOpcode(ARM::t2SUBri);
|
||||
switch (Inst.getOpcode()) {
|
||||
case ARM::t2ADDri12:
|
||||
Inst.setOpcode(ARM::t2ADDri);
|
||||
break;
|
||||
case ARM::t2SUBri12:
|
||||
Inst.setOpcode(ARM::t2SUBri);
|
||||
break;
|
||||
case ARM::t2ADDspImm12:
|
||||
Inst.setOpcode(ARM::t2ADDspImm);
|
||||
break;
|
||||
case ARM::t2SUBspImm12:
|
||||
Inst.setOpcode(ARM::t2SUBspImm);
|
||||
break;
|
||||
}
|
||||
|
||||
Inst.addOperand(MCOperand::createReg(0)); // cc_out
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
case ARM::tADDi8:
|
||||
// If the immediate is in the range 0-7, we want tADDi3 iff Rd was
|
||||
// explicitly specified. From the ARM ARM: "Encoding T1 is preferred
|
||||
@ -9812,6 +9844,25 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
|
||||
Inst = TmpInst;
|
||||
return true;
|
||||
}
|
||||
case ARM::t2ADDspImm:
|
||||
case ARM::t2SUBspImm: {
|
||||
// Prefer T1 encoding if possible
|
||||
if (Inst.getOperand(5).getReg() != 0 || HasWideQualifier)
|
||||
break;
|
||||
unsigned V = Inst.getOperand(2).getImm();
|
||||
if (V & 3 || V > ((1 << 7) - 1) << 2)
|
||||
break;
|
||||
MCInst TmpInst;
|
||||
TmpInst.setOpcode(Inst.getOpcode() == ARM::t2ADDspImm ? ARM::tADDspi
|
||||
: ARM::tSUBspi);
|
||||
TmpInst.addOperand(MCOperand::createReg(ARM::SP)); // destination reg
|
||||
TmpInst.addOperand(MCOperand::createReg(ARM::SP)); // source reg
|
||||
TmpInst.addOperand(MCOperand::createImm(V / 4)); // immediate
|
||||
TmpInst.addOperand(Inst.getOperand(3)); // pred
|
||||
TmpInst.addOperand(Inst.getOperand(4));
|
||||
Inst = TmpInst;
|
||||
return true;
|
||||
}
|
||||
case ARM::t2ADDrr: {
|
||||
// If the destination and first source operand are the same, and
|
||||
// there's no setting of the flags, use encoding T2 instead of T3.
|
||||
|
@ -201,6 +201,9 @@ static DecodeStatus DecoderGPRRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address, const void *Decoder);
|
||||
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address, const void *Decoder);
|
||||
static DecodeStatus DecodeGPRspRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder);
|
||||
static DecodeStatus DecodeHPRRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address, const void *Decoder);
|
||||
static DecodeStatus DecodeSPRRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
@ -563,6 +566,9 @@ static DecodeStatus DecodeMVEVPNOT(MCInst &Inst, unsigned Insn,
|
||||
static DecodeStatus DecodeMVEOverlappingLongShift(MCInst &Inst, unsigned Insn,
|
||||
uint64_t Address,
|
||||
const void *Decoder);
|
||||
static DecodeStatus DecodeT2AddSubSPImm(MCInst &Inst, unsigned Insn,
|
||||
uint64_t Address, const void *Decoder);
|
||||
|
||||
#include "ARMGenDisassemblerTables.inc"
|
||||
|
||||
static MCDisassembler *createARMDisassembler(const Target &T,
|
||||
@ -1225,6 +1231,17 @@ static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
return S;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeGPRspRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
if (RegNo != 13)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
unsigned Register = GPRDecoderTable[RegNo];
|
||||
Inst.addOperand(MCOperand::createReg(Register));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodetcGPRRegisterClass(MCInst &Inst, unsigned RegNo,
|
||||
uint64_t Address, const void *Decoder) {
|
||||
unsigned Register = 0;
|
||||
@ -5582,14 +5599,25 @@ static DecodeStatus DecodeT2Adr(MCInst &Inst, uint32_t Insn,
|
||||
unsigned sign1 = fieldFromInstruction(Insn, 21, 1);
|
||||
unsigned sign2 = fieldFromInstruction(Insn, 23, 1);
|
||||
if (sign1 != sign2) return MCDisassembler::Fail;
|
||||
const unsigned Rd = fieldFromInstruction(Insn, 8, 4);
|
||||
assert(Inst.getNumOperands() == 0 && "We should receive an empty Inst");
|
||||
DecodeStatus S = DecoderGPRRegisterClass(Inst, Rd, Address, Decoder);
|
||||
|
||||
unsigned Val = fieldFromInstruction(Insn, 0, 8);
|
||||
Val |= fieldFromInstruction(Insn, 12, 3) << 8;
|
||||
Val |= fieldFromInstruction(Insn, 26, 1) << 11;
|
||||
Val |= sign1 << 12;
|
||||
Inst.addOperand(MCOperand::createImm(SignExtend32<13>(Val)));
|
||||
|
||||
return MCDisassembler::Success;
|
||||
// If sign, then it is decreasing the address.
|
||||
if (sign1) {
|
||||
// Following ARMv7 Architecture Manual, when the offset
|
||||
// is zero, it is decoded as a subw, not as a adr.w
|
||||
if (!Val) {
|
||||
Inst.setOpcode(ARM::t2SUBri12);
|
||||
Inst.addOperand(MCOperand::createReg(ARM::PC));
|
||||
} else
|
||||
Val = -Val;
|
||||
}
|
||||
Inst.addOperand(MCOperand::createImm(Val));
|
||||
return S;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeT2ShifterImmOperand(MCInst &Inst, uint32_t Val,
|
||||
@ -6589,3 +6617,40 @@ static DecodeStatus DecodeMVEVPNOT(MCInst &Inst, unsigned Insn, uint64_t Address
|
||||
Inst.addOperand(MCOperand::createReg(ARM::VPR));
|
||||
return S;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeT2AddSubSPImm(MCInst &Inst, unsigned Insn,
|
||||
uint64_t Address, const void *Decoder) {
|
||||
const unsigned Rd = fieldFromInstruction(Insn, 8, 4);
|
||||
const unsigned Rn = fieldFromInstruction(Insn, 16, 4);
|
||||
const unsigned Imm12 = fieldFromInstruction(Insn, 26, 1) << 11 |
|
||||
fieldFromInstruction(Insn, 12, 3) << 8 |
|
||||
fieldFromInstruction(Insn, 0, 8);
|
||||
const unsigned TypeT3 = fieldFromInstruction(Insn, 25, 1);
|
||||
unsigned sign1 = fieldFromInstruction(Insn, 21, 1);
|
||||
unsigned sign2 = fieldFromInstruction(Insn, 23, 1);
|
||||
unsigned S = fieldFromInstruction(Insn, 20, 1);
|
||||
if (sign1 != sign2)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
// T3 does a zext of imm12, where T2 does a ThumbExpandImm (T2SOImm)
|
||||
DecodeStatus DS = MCDisassembler::Success;
|
||||
if ((!Check(DS,
|
||||
DecodeGPRspRegisterClass(Inst, Rd, Address, Decoder))) || // dst
|
||||
(!Check(DS, DecodeGPRspRegisterClass(Inst, Rn, Address, Decoder))))
|
||||
return MCDisassembler::Fail;
|
||||
if (TypeT3) {
|
||||
Inst.setOpcode(sign1 ? ARM::t2SUBspImm12 : ARM::t2ADDspImm12);
|
||||
S = 0;
|
||||
Inst.addOperand(MCOperand::createImm(Imm12)); // zext imm12
|
||||
} else {
|
||||
Inst.setOpcode(sign1 ? ARM::t2SUBspImm : ARM::t2ADDspImm);
|
||||
if (!Check(DS, DecodeT2SOImm(Inst, Imm12, Address, Decoder))) // imm12
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
if (!Check(DS, DecodeCCOutOperand(Inst, S, Address, Decoder))) // cc_out
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
Inst.addOperand(MCOperand::createReg(0)); // pred
|
||||
|
||||
return DS;
|
||||
}
|
||||
|
@ -319,15 +319,19 @@ void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
|
||||
}
|
||||
bool HasCCOut = true;
|
||||
int ImmIsT2SO = ARM_AM::getT2SOImmVal(ThisVal);
|
||||
|
||||
Opc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
|
||||
bool ToSP = DestReg == ARM::SP;
|
||||
unsigned t2SUB = ToSP ? ARM::t2SUBspImm : ARM::t2SUBri;
|
||||
unsigned t2ADD = ToSP ? ARM::t2ADDspImm : ARM::t2ADDri;
|
||||
unsigned t2SUBi12 = ToSP ? ARM::t2SUBspImm12 : ARM::t2SUBri12;
|
||||
unsigned t2ADDi12 = ToSP ? ARM::t2ADDspImm12 : ARM::t2ADDri12;
|
||||
Opc = isSub ? t2SUB : t2ADD;
|
||||
// Prefer T2: sub rd, rn, so_imm | sub sp, sp, so_imm
|
||||
if (ImmIsT2SO != -1) {
|
||||
NumBytes = 0;
|
||||
} else if (ThisVal < 4096) {
|
||||
// Prefer T3 if can make it in a single go: subw rd, rn, imm12 | subw sp,
|
||||
// sp, imm12
|
||||
Opc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
|
||||
Opc = isSub ? t2SUBi12 : t2ADDi12;
|
||||
HasCCOut = false;
|
||||
NumBytes = 0;
|
||||
} else {
|
||||
@ -483,7 +487,8 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||
if (Opcode == ARM::INLINEASM || Opcode == ARM::INLINEASM_BR)
|
||||
AddrMode = ARMII::AddrModeT2_i12; // FIXME. mode for thumb2?
|
||||
|
||||
if (Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
|
||||
const bool IsSP = Opcode == ARM::t2ADDspImm12 || Opcode == ARM::t2ADDspImm;
|
||||
if (IsSP || Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
|
||||
Offset += MI.getOperand(FrameRegIdx+1).getImm();
|
||||
|
||||
unsigned PredReg;
|
||||
@ -500,14 +505,14 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasCCOut = Opcode != ARM::t2ADDri12;
|
||||
bool HasCCOut = (Opcode != ARM::t2ADDspImm12 && Opcode != ARM::t2ADDri12);
|
||||
|
||||
if (Offset < 0) {
|
||||
Offset = -Offset;
|
||||
isSub = true;
|
||||
MI.setDesc(TII.get(ARM::t2SUBri));
|
||||
MI.setDesc(IsSP ? TII.get(ARM::t2SUBspImm) : TII.get(ARM::t2SUBri));
|
||||
} else {
|
||||
MI.setDesc(TII.get(ARM::t2ADDri));
|
||||
MI.setDesc(IsSP ? TII.get(ARM::t2ADDspImm) : TII.get(ARM::t2ADDri));
|
||||
}
|
||||
|
||||
// Common case: small offset, fits into instruction.
|
||||
@ -523,7 +528,8 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||
// Another common case: imm12.
|
||||
if (Offset < 4096 &&
|
||||
(!HasCCOut || MI.getOperand(MI.getNumOperands()-1).getReg() == 0)) {
|
||||
unsigned NewOpc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
|
||||
unsigned NewOpc = isSub ? IsSP ? ARM::t2SUBspImm12 : ARM::t2SUBri12
|
||||
: IsSP ? ARM::t2ADDspImm12 : ARM::t2ADDri12;
|
||||
MI.setDesc(TII.get(NewOpc));
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
|
||||
|
@ -64,7 +64,7 @@ body: |
|
||||
|
||||
%1(s32) = G_CONSTANT i32 786444 ; 0x000c000c
|
||||
%2(s32) = G_ADD %0, %1
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:gprnopc = t2ADDri [[VREGX]], 786444, 14, $noreg, $noreg
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:rgpr = t2ADDri [[VREGX]], 786444, 14, $noreg, $noreg
|
||||
|
||||
$r0 = COPY %2(s32)
|
||||
; CHECK: $r0 = COPY [[VREGRES]]
|
||||
@ -92,7 +92,7 @@ body: |
|
||||
|
||||
%1(s32) = G_CONSTANT i32 4093
|
||||
%2(s32) = G_ADD %0, %1
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:gprnopc = t2ADDri12 [[VREGX]], 4093, 14, $noreg
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:rgpr = t2ADDri12 [[VREGX]], 4093, 14, $noreg
|
||||
|
||||
$r0 = COPY %2(s32)
|
||||
; CHECK: $r0 = COPY [[VREGRES]]
|
||||
@ -178,7 +178,7 @@ body: |
|
||||
|
||||
%1(s32) = G_CONSTANT i32 786444 ; 0x000c000c
|
||||
%2(s32) = G_SUB %0, %1
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:gprnopc = t2SUBri [[VREGX]], 786444, 14, $noreg, $noreg
|
||||
; CHECK: [[VREGRES:%[0-9]+]]:rgpr = t2SUBri [[VREGX]], 786444, 14, $noreg, $noreg
|
||||
|
||||
$r0 = COPY %2(s32)
|
||||
; CHECK: $r0 = COPY [[VREGRES]]
|
||||
|
@ -168,7 +168,7 @@ body: |
|
||||
liveins: $r0, $r1, $r2, $r3
|
||||
|
||||
%0(p0) = G_FRAME_INDEX %fixed-stack.2
|
||||
; CHECK: [[FI32VREG:%[0-9]+]]:gprnopc = t2ADDri %fixed-stack.[[FI32]], 0, 14, $noreg, $noreg
|
||||
; CHECK: [[FI32VREG:%[0-9]+]]:rgpr = t2ADDri %fixed-stack.[[FI32]], 0, 14, $noreg, $noreg
|
||||
|
||||
%1(s32) = G_LOAD %0(p0) :: (load 4)
|
||||
; CHECK: [[LD32VREG:%[0-9]+]]:gpr = t2LDRi12 [[FI32VREG]], 0, 14, $noreg
|
||||
@ -177,7 +177,7 @@ body: |
|
||||
; CHECK: $r0 = COPY [[LD32VREG]]
|
||||
|
||||
%2(p0) = G_FRAME_INDEX %fixed-stack.0
|
||||
; CHECK: [[FI1VREG:%[0-9]+]]:gprnopc = t2ADDri %fixed-stack.[[FI1]], 0, 14, $noreg, $noreg
|
||||
; CHECK: [[FI1VREG:%[0-9]+]]:rgpr = t2ADDri %fixed-stack.[[FI1]], 0, 14, $noreg, $noreg
|
||||
|
||||
%3(s1) = G_LOAD %2(p0) :: (load 1)
|
||||
; CHECK: [[LD1VREG:%[0-9]+]]:gprnopc = t2LDRBi12 [[FI1VREG]], 0, 14, $noreg
|
||||
|
@ -1,7 +1,7 @@
|
||||
--- |
|
||||
; RUN: llc --run-pass=prologepilog -o - %s | FileCheck %s
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_register $r7
|
||||
; CHECK-NEXT: $sp = frame-setup t2SUBri12 killed $sp, 4008, 14, $noreg
|
||||
; CHECK-NEXT: $sp = frame-setup t2SUBspImm12 killed $sp, 4008, 14, $noreg
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7-none-none-eabi"
|
||||
|
74
test/CodeGen/Thumb2/bug-subw.ll
Normal file
74
test/CodeGen/Thumb2/bug-subw.ll
Normal file
@ -0,0 +1,74 @@
|
||||
; pr23772 - [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80"
|
||||
; RUN: llc -march=thumb -mcpu=cortex-m3 -O3 -filetype=asm -o - %s | FileCheck %s
|
||||
; CHECK-NOT: sub{{.*}} sp, r{{.*}}, #
|
||||
; CHECK: .fnend
|
||||
; TODO: Missed optimization. The three instructions generated to subtract SP can be converged to a single one
|
||||
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32"
|
||||
target triple = "thumbv7m-unknown-unknown"
|
||||
%B = type {%B*}
|
||||
%R = type {i32}
|
||||
%U = type {%U*, i8, i8}
|
||||
%E = type {%B*, %U*}
|
||||
%X = type {i32, i8, i8}
|
||||
declare external [0 x i8]* @memalloc(i32, i32, i32)
|
||||
declare external void @memfree([0 x i8]*, i32, i32)
|
||||
define void @foo(%B* %pb$, %R* %pr$) nounwind {
|
||||
L.0:
|
||||
%pb = alloca %B*
|
||||
%pr = alloca %R*
|
||||
store %B* %pb$, %B** %pb
|
||||
store %R* %pr$, %R** %pr
|
||||
%pe = alloca %E*
|
||||
%0 = load %B*, %B** %pb
|
||||
%1 = bitcast %B* %0 to %E*
|
||||
store %E* %1, %E** %pe
|
||||
%2 = load %R*, %R** %pr
|
||||
%3 = getelementptr %R, %R* %2, i32 0, i32 0
|
||||
%4 = load i32, i32* %3
|
||||
switch i32 %4, label %L.1 [
|
||||
i32 1, label %L.3
|
||||
]
|
||||
L.3:
|
||||
%px = alloca %X*
|
||||
%5 = load %R*, %R** %pr
|
||||
%6 = bitcast %R* %5 to %X*
|
||||
store %X* %6, %X** %px
|
||||
%7 = load %X*, %X** %px
|
||||
%8 = getelementptr %X, %X* %7, i32 0, i32 0
|
||||
%9 = load i32, i32* %8
|
||||
%10 = icmp ne i32 %9, 0
|
||||
br i1 %10, label %L.5, label %L.4
|
||||
L.5:
|
||||
%pu = alloca %U*
|
||||
%11 = call [0 x i8]* @memalloc(i32 8, i32 4, i32 0)
|
||||
%12 = bitcast [0 x i8]* %11 to %U*
|
||||
store %U* %12, %U** %pu
|
||||
%13 = load %X*, %X** %px
|
||||
%14 = getelementptr %X, %X* %13, i32 0, i32 1
|
||||
%15 = load i8, i8* %14
|
||||
%16 = load %U*, %U** %pu
|
||||
%17 = getelementptr %U, %U* %16, i32 0, i32 1
|
||||
store i8 %15, i8* %17
|
||||
%18 = load %E*, %E** %pe
|
||||
%19 = getelementptr %E, %E* %18, i32 0, i32 1
|
||||
%20 = load %U*, %U** %19
|
||||
%21 = load %U*, %U** %pu
|
||||
%22 = getelementptr %U, %U* %21, i32 0, i32 0
|
||||
store %U* %20, %U** %22
|
||||
%23 = load %U*, %U** %pu
|
||||
%24 = load %E*, %E** %pe
|
||||
%25 = getelementptr %E, %E* %24, i32 0, i32 1
|
||||
store %U* %23, %U** %25
|
||||
br label %L.4
|
||||
L.4:
|
||||
%26 = load %X*, %X** %px
|
||||
%27 = bitcast %X* %26 to [0 x i8]*
|
||||
call void @memfree([0 x i8]* %27, i32 8, i32 0)
|
||||
br label %L.2
|
||||
L.1:
|
||||
br label %L.2
|
||||
L.2:
|
||||
br label %return
|
||||
return:
|
||||
ret void
|
||||
}
|
@ -27,7 +27,7 @@ body: |
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $r6, -28
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $r5, -32
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $r4, -36
|
||||
; CHECK: $sp = frame-setup t2SUBri killed $sp, 1208, 14, $noreg, $noreg
|
||||
; CHECK: $sp = frame-setup t2SUBspImm killed $sp, 1208, 14, $noreg, $noreg
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 1244
|
||||
; CHECK: $r0 = IMPLICIT_DEF
|
||||
; CHECK: $r1 = IMPLICIT_DEF
|
||||
|
@ -118,7 +118,7 @@ body: |
|
||||
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $r6, -28
|
||||
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $r5, -32
|
||||
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $r4, -36
|
||||
; CHECK-NEXT: $sp = frame-setup t2SUBri12 killed $sp, 1220, 14, $noreg
|
||||
; CHECK-NEXT: $sp = frame-setup t2SUBspImm12 killed $sp, 1220, 14, $noreg
|
||||
; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 1256
|
||||
; CHECK-NEXT: $r0 = IMPLICIT_DEF
|
||||
; CHECK-NEXT: $r1 = IMPLICIT_DEF
|
||||
|
@ -22,7 +22,7 @@ body: |
|
||||
%0:rgpr = COPY $r0
|
||||
%2:rgpr = t2MOVi 1, 14, $noreg, $noreg
|
||||
%3:gprnopc = t2ADDrr %0, %1, 14, $noreg, $noreg
|
||||
%4:gprnopc = t2SUBri %3, 0, 14, $noreg, def dead $cpsr
|
||||
%4:rgpr = t2SUBri %3, 0, 14, $noreg, def dead $cpsr
|
||||
t2CMPri killed %3, 0, 14, $noreg, implicit-def $cpsr
|
||||
%5:rgpr = t2MOVCCi %2, 0, 7, $cpsr
|
||||
$r0 = COPY %5
|
||||
@ -30,6 +30,6 @@ body: |
|
||||
|
||||
# CHECK-LABEL: name: test
|
||||
# CHECK: %3:gprnopc = t2ADDrr %0, %1, 14, $noreg, $noreg
|
||||
# CHECK-NEXT: %4:gprnopc = t2SUBri %3, 0, 14, $noreg, def $cpsr
|
||||
# CHECK-NEXT: %4:rgpr = t2SUBri %3, 0, 14, $noreg, def $cpsr
|
||||
# CHECK-NEXT: %5:rgpr = t2MOVCCi %2, 0, 7, $cpsr
|
||||
...
|
||||
|
@ -23,7 +23,7 @@ body: |
|
||||
liveins: $r0
|
||||
|
||||
%0:rgpr = COPY $r0
|
||||
%1:gprnopc = t2ADDri %stack.0.f, 0, 14, $noreg, $noreg
|
||||
%1:rgpr = t2ADDri %stack.0.f, 0, 14, $noreg, $noreg
|
||||
t2CMPrr %1, %0, 14, $noreg, implicit-def $cpsr
|
||||
t2Bcc %bb.2, 3, $cpsr
|
||||
t2B %bb.1, 14, $noreg
|
||||
@ -37,7 +37,7 @@ body: |
|
||||
tBX_RET 14, $noreg
|
||||
|
||||
# CHECK-LABEL: name: test_addir_frameindex
|
||||
# CHECK: %1:gprnopc = t2ADDri %stack.0.f, 0, 14, $noreg, $noreg
|
||||
# CHECK: %1:rgpr = t2ADDri %stack.0.f, 0, 14, $noreg, $noreg
|
||||
# CHECK-NEXT: t2CMPrr %1, %0, 14, $noreg, implicit-def $cpsr
|
||||
# CHECK-NEXT: t2Bcc %bb.2, 3, $cpsr
|
||||
...
|
||||
|
10
test/CodeGen/Thumb2/t2peephole-t2ADDrr-to-t2ADDri.ll
Normal file
10
test/CodeGen/Thumb2/t2peephole-t2ADDrr-to-t2ADDri.ll
Normal file
@ -0,0 +1,10 @@
|
||||
; RUN: llc -mtriple=thumb-eabi --stop-after=peephole-opt -mcpu=arm1156t2-s -mattr=+thumb2 %s -o - | FileCheck %s
|
||||
define i32 @t2_const_var2_1_ok_2(i32 %lhs) {
|
||||
; CHECK: [[R0:%0|%[1-9][0-9]*]]:gprnopc = COPY $r0
|
||||
; CHECK-NEXT: [[R1:%0|%[1-9][0-9]*]]:rgpr = t2ADDri [[R0]], 11206656
|
||||
; CHECK-NEXT: [[R2:%0|%[1-9][0-9]*]]:rgpr = t2ADDri killed [[R1]], 187
|
||||
; CHECK-NEXT: $r0 = COPY [[R2]]
|
||||
%ret = add i32 %lhs, 11206843 ; 0x00ab00bb
|
||||
ret i32 %ret
|
||||
}
|
||||
|
@ -79,7 +79,6 @@ _func:
|
||||
adds r2, r2, #56
|
||||
adds r2, #56
|
||||
add r1, r7, #0xcbcbcbcb
|
||||
add sp, sp, #0x1fe0000
|
||||
|
||||
adds.w r2, #-16
|
||||
adds.w r2, r2, #-16
|
||||
@ -103,7 +102,6 @@ _func:
|
||||
@ CHECK: adds r2, #56 @ encoding: [0x38,0x32]
|
||||
@ CHECK: adds r2, #56 @ encoding: [0x38,0x32]
|
||||
@ CHECK: add.w r1, r7, #3419130827 @ encoding: [0x07,0xf1,0xcb,0x31]
|
||||
@ CHECK: add.w sp, sp, #33423360 @ encoding: [0x0d,0xf1,0xff,0x7d]
|
||||
|
||||
@ CHECK: subs.w r2, r2, #16 @ encoding: [0xb2,0xf1,0x10,0x02]
|
||||
@ CHECK: subs.w r2, r2, #16 @ encoding: [0xb2,0xf1,0x10,0x02]
|
||||
@ -182,7 +180,102 @@ _func:
|
||||
@ CHECK: addw r6, sp, #1020 @ encoding: [0x0d,0xf2,0xfc,0x36]
|
||||
add r6, sp, #1019 // T4
|
||||
@ CHECK: addw r6, sp, #1019 @ encoding: [0x0d,0xf2,0xfb,0x36]
|
||||
|
||||
addw r0, r0, #4095
|
||||
addw r0, #4095
|
||||
add r0, r0, #4095
|
||||
add r0, #4095
|
||||
@ CHECK-NEXT: addw r0, r0, #4095 @ encoding: [0x00,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: addw r0, r0, #4095 @ encoding: [0x00,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: addw r0, r0, #4095 @ encoding: [0x00,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: addw r0, r0, #4095 @ encoding: [0x00,0xf6,0xff,0x70]
|
||||
add.w r0, r0, #-4096
|
||||
add r0, r0, #-4096
|
||||
add.w r0, #-4096
|
||||
add r0, #-4096
|
||||
@ CHECK-NEXT: sub.w r0, r0, #4096 @ encoding: [0xa0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: sub.w r0, r0, #4096 @ encoding: [0xa0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: sub.w r0, r0, #4096 @ encoding: [0xa0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: sub.w r0, r0, #4096 @ encoding: [0xa0,0xf5,0x80,0x50]
|
||||
adds.w r0, r0, #-4096
|
||||
adds r0, r0, #-4096
|
||||
adds.w r0, #-4096
|
||||
adds r0, #-4096
|
||||
@ CHECK-NEXT: subs.w r0, r0, #4096 @ encoding: [0xb0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: subs.w r0, r0, #4096 @ encoding: [0xb0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: subs.w r0, r0, #4096 @ encoding: [0xb0,0xf5,0x80,0x50]
|
||||
@ CHECK-NEXT: subs.w r0, r0, #4096 @ encoding: [0xb0,0xf5,0x80,0x50]
|
||||
@------------------------------------------------------------------------------
|
||||
@ ADD (SP plus immediate, writing to SP)
|
||||
@------------------------------------------------------------------------------
|
||||
add.w sp, sp, #0x1fe0000 //T3
|
||||
add.w sp, #0x1fe0000
|
||||
add sp, sp, #0x1fe0000
|
||||
add sp, #0x1fe0000
|
||||
@ CHECK-NEXT: add.w sp, sp, #33423360 @ encoding: [0x0d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: add.w sp, sp, #33423360 @ encoding: [0x0d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: add.w sp, sp, #33423360 @ encoding: [0x0d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: add.w sp, sp, #33423360 @ encoding: [0x0d,0xf1,0xff,0x7d]
|
||||
adds.w sp, sp, #0x1fe0000 //T3
|
||||
adds.w sp, #0x1fe0000
|
||||
adds sp, sp, #0x1fe0000
|
||||
adds sp, #0x1fe0000
|
||||
@ CHECK-NEXT: adds.w sp, sp, #33423360 @ encoding: [0x1d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, #33423360 @ encoding: [0x1d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, #33423360 @ encoding: [0x1d,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, #33423360 @ encoding: [0x1d,0xf1,0xff,0x7d]
|
||||
addw sp, sp, #4095 //T4
|
||||
add sp, sp, #4095
|
||||
addw sp, #4095
|
||||
add sp, #4095
|
||||
@ CHECK-NEXT: addw sp, sp, #4095 @ encoding: [0x0d,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: addw sp, sp, #4095 @ encoding: [0x0d,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: addw sp, sp, #4095 @ encoding: [0x0d,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: addw sp, sp, #4095 @ encoding: [0x0d,0xf6,0xff,0x7d]
|
||||
add sp, sp, #128 //T2
|
||||
add sp, #128
|
||||
@ CHECK-NEXT: add sp, #128 @ encoding: [0x20,0xb0]
|
||||
@ CHECK-NEXT: add sp, #128 @ encoding: [0x20,0xb0]
|
||||
adds sp, sp, #128 //T3
|
||||
adds sp, #128
|
||||
@ CHECK-NEXT: adds.w sp, sp, #128 @ encoding: [0x1d,0xf1,0x80,0x0d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, #128 @ encoding: [0x1d,0xf1,0x80,0x0d]
|
||||
add r0, sp, #128 //T1
|
||||
@ CHECK-NEXT: add r0, sp, #128 @ encoding: [0x20,0xa8]
|
||||
adds r0, sp, #128 //T3
|
||||
@ CHECK-NEXT: adds.w r0, sp, #128 @ encoding: [0x1d,0xf1,0x80,0x00]
|
||||
addw r0, sp, #128
|
||||
@ CHECK-NEXT: addw r0, sp, #128 @ encoding: [0x0d,0xf2,0x80,0x00]
|
||||
@------------------------------------------------------------------------------
|
||||
@ ADD (SP plus negative immediate, writing to SP)
|
||||
@------------------------------------------------------------------------------
|
||||
add sp, sp, #-508
|
||||
add sp, #-508
|
||||
@ CHECK-NEXT: sub sp, #508 @ encoding: [0xff,0xb0]
|
||||
@ CHECK-NEXT: sub sp, #508 @ encoding: [0xff,0xb0]
|
||||
addw sp, sp, #-4095
|
||||
add sp, sp, #-4095
|
||||
addw sp, #-4095
|
||||
add sp, #-4095
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
add.w sp, sp, #-4096
|
||||
add sp, sp, #-4096
|
||||
add.w sp, #-4096
|
||||
add sp, #-4096
|
||||
@ CHECK-NEXT: sub.w sp, sp, #4096 @ encoding: [0xad,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #4096 @ encoding: [0xad,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #4096 @ encoding: [0xad,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #4096 @ encoding: [0xad,0xf5,0x80,0x5d]
|
||||
adds.w sp, sp, #-4096
|
||||
adds sp, sp, #-4096
|
||||
adds.w sp, #-4096
|
||||
adds sp, #-4096
|
||||
@ CHECK-NEXT: subs.w sp, sp, #4096 @ encoding: [0xbd,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #4096 @ encoding: [0xbd,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #4096 @ encoding: [0xbd,0xf5,0x80,0x5d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #4096 @ encoding: [0xbd,0xf5,0x80,0x5d]
|
||||
@------------------------------------------------------------------------------
|
||||
@ ADD (SP plus register) A8.8.10
|
||||
@------------------------------------------------------------------------------
|
||||
@ -206,8 +299,22 @@ _func:
|
||||
@ CHECK: it eq @ encoding: [0x08,0xbf]
|
||||
addeq r2, sp, ip // T3
|
||||
@ CHECK: addeq.w r2, sp, r12 @ encoding: [0x0d,0xeb,0x0c,0x02]
|
||||
|
||||
|
||||
add.w r0, sp, r0, ror #2
|
||||
add r0, sp, r0, ror #2
|
||||
add sp, r1, lsl #15
|
||||
adds.w r0, sp, r0, ror #2
|
||||
adds r0, sp, r0, ror #2
|
||||
adds.w sp, sp, r0, ror #31
|
||||
adds sp, sp, r0, ror #31
|
||||
adds sp, r0, ror #31
|
||||
@ CHECK-NEXT: add.w r0, sp, r0, ror #2 @ encoding: [0x0d,0xeb,0xb0,0x00]
|
||||
@ CHECK-NEXT: add.w r0, sp, r0, ror #2 @ encoding: [0x0d,0xeb,0xb0,0x00]
|
||||
@ CHECK-NEXT: add.w sp, sp, r1, lsl #15 @ encoding: [0x0d,0xeb,0xc1,0x3d]
|
||||
@ CHECK-NEXT: adds.w r0, sp, r0, ror #2 @ encoding: [0x1d,0xeb,0xb0,0x00]
|
||||
@ CHECK-NEXT: adds.w r0, sp, r0, ror #2 @ encoding: [0x1d,0xeb,0xb0,0x00]
|
||||
@ CHECK-NEXT: adds.w sp, sp, r0, ror #31 @ encoding: [0x1d,0xeb,0xf0,0x7d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, r0, ror #31 @ encoding: [0x1d,0xeb,0xf0,0x7d]
|
||||
@ CHECK-NEXT: adds.w sp, sp, r0, ror #31 @ encoding: [0x1d,0xeb,0xf0,0x7d]
|
||||
@------------------------------------------------------------------------------
|
||||
@ FIXME: ADR
|
||||
@------------------------------------------------------------------------------
|
||||
@ -3083,7 +3190,10 @@ _func:
|
||||
sub r0, r0, #32
|
||||
subs r2, r2, #56
|
||||
subs r2, #56
|
||||
|
||||
subw r0, r0, #4095
|
||||
subw r0, #4095
|
||||
sub r0, r0, #4095
|
||||
sub r0, #4095
|
||||
@ CHECK: itet eq @ encoding: [0x0a,0xbf]
|
||||
@ CHECK: subeq r1, r2, #4 @ encoding: [0x11,0x1f]
|
||||
@ CHECK: subwne r5, r3, #1023 @ encoding: [0xa3,0xf2,0xff,0x35]
|
||||
@ -3099,8 +3209,47 @@ _func:
|
||||
@ CHECK: sub.w r0, r0, #32 @ encoding: [0xa0,0xf1,0x20,0x00]
|
||||
@ CHECK: subs r2, #56 @ encoding: [0x38,0x3a]
|
||||
@ CHECK: subs r2, #56 @ encoding: [0x38,0x3a]
|
||||
|
||||
|
||||
@ CHECK-NEXT: subw r0, r0, #4095 @ encoding: [0xa0,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: subw r0, r0, #4095 @ encoding: [0xa0,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: subw r0, r0, #4095 @ encoding: [0xa0,0xf6,0xff,0x70]
|
||||
@ CHECK-NEXT: subw r0, r0, #4095 @ encoding: [0xa0,0xf6,0xff,0x70]
|
||||
@------------------------------------------------------------------------------
|
||||
@ SUB (immediate, writting to SP)
|
||||
@------------------------------------------------------------------------------
|
||||
sub.w sp, sp, #0x1fe0000 //T2
|
||||
sub sp, sp, #0x1fe0000
|
||||
sub.w sp, #0x1fe0000
|
||||
sub sp, #0x1fe0000
|
||||
@ CHECK-NEXT: sub.w sp, sp, #33423360 @ encoding: [0xad,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #33423360 @ encoding: [0xad,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #33423360 @ encoding: [0xad,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: sub.w sp, sp, #33423360 @ encoding: [0xad,0xf1,0xff,0x7d]
|
||||
subs.w sp, sp, #0x1fe0000 //T2
|
||||
subs sp, sp, #0x1fe0000
|
||||
subs.w sp, #0x1fe0000
|
||||
subs sp, #0x1fe0000
|
||||
@ CHECK-NEXT: subs.w sp, sp, #33423360 @ encoding: [0xbd,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #33423360 @ encoding: [0xbd,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #33423360 @ encoding: [0xbd,0xf1,0xff,0x7d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #33423360 @ encoding: [0xbd,0xf1,0xff,0x7d]
|
||||
subw sp, sp, #4095 //T3
|
||||
sub sp, sp, #4095
|
||||
subw sp, #4095
|
||||
sub sp, #4095
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
@ CHECK-NEXT: subw sp, sp, #4095 @ encoding: [0xad,0xf6,0xff,0x7d]
|
||||
sub sp, #128 //T1
|
||||
@ CHECK-NEXT: sub sp, #128 @ encoding: [0xa0,0xb0]
|
||||
subs.w sp, #128 //T2
|
||||
subs sp, #128 //T2
|
||||
@ CHECK-NEXT: subs.w sp, sp, #128 @ encoding: [0xbd,0xf1,0x80,0x0d]
|
||||
@ CHECK-NEXT: subs.w sp, sp, #128 @ encoding: [0xbd,0xf1,0x80,0x0d]
|
||||
sub.w sp, #128 //T2
|
||||
@ CHECK-NEXT: sub.w sp, sp, #128 @ encoding: [0xad,0xf1,0x80,0x0d]
|
||||
subw sp, #128 //T4
|
||||
@ CHECK-NEXT: subw sp, sp, #128 @ encoding: [0xad,0xf2,0x80,0x0d]
|
||||
@------------------------------------------------------------------------------
|
||||
@ SUB (register)
|
||||
@------------------------------------------------------------------------------
|
||||
|
@ -1,20 +1,68 @@
|
||||
@ RUN: not llvm-mc -triple thumbv7-apple-ios %s -o - 2>&1 | FileCheck %s
|
||||
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ RUN: not llvm-mc -triple thumbv7-apple-ios %s -o /dev/null 2>&1 | FileCheck %s
|
||||
add sp, r5, #1
|
||||
addw sp, r7, #4
|
||||
add sp, r3, r2
|
||||
add sp, r3, r5, lsl #3
|
||||
|
||||
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
@ CHECK: error: source register must be sp if destination is sp
|
||||
sub sp, r5, #1
|
||||
subw sp, r7, #4
|
||||
sub sp, r3, r2
|
||||
sub sp, r3, r5, lsl #3
|
||||
@CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
@CHECK-NEXT: add sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: invalid operand for instruction
|
||||
@CHECK-NEXT: add sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: add sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: add sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register sp
|
||||
@CHECK-NEXT: add sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: invalid instruction, any one of the following would fix this:
|
||||
@CHECK-NEXT: addw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: addw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register sp
|
||||
@CHECK-NEXT: addw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: source register must be sp if destination is sp
|
||||
@CHECK-NEXT: add sp, r3, r2
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: source register must be sp if destination is sp
|
||||
@CHECK-NEXT: add sp, r3, r5, lsl #3
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: invalid instruction, any one of the following would fix this:
|
||||
@CHECK-NEXT: sub sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: invalid operand for instruction
|
||||
@CHECK-NEXT: sub sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: sub sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: sub sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register sp
|
||||
@CHECK-NEXT: sub sp, r5, #1
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: invalid instruction, any one of the following would fix this:
|
||||
@CHECK-NEXT: subw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register in range [r0, r12] or r14
|
||||
@CHECK-NEXT: subw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: note: operand must be a register sp
|
||||
@CHECK-NEXT: subw sp, r7, #4
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: source register must be sp if destination is sp
|
||||
@CHECK-NEXT: sub sp, r3, r2
|
||||
@CHECK-NEXT: ^
|
||||
@CHECK-NEXT: error: source register must be sp if destination is sp
|
||||
@CHECK-NEXT: sub sp, r3, r5, lsl #3
|
||||
|
@ -51,7 +51,7 @@
|
||||
.thumb
|
||||
|
||||
ADD r0, r1, #0xFFFFFF00
|
||||
# CHECK: subw r0, r1, #256
|
||||
# CHECK: sub.w r0, r1, #256
|
||||
# CHECK-DISABLED: note: instruction requires: NegativeImmediates
|
||||
# CHECK-DISABLED: ADD
|
||||
ADDS r0, r1, #0xFFFFFF00
|
||||
@ -175,7 +175,7 @@
|
||||
# CHECK-DISABLED: note: instruction requires: NegativeImmediates
|
||||
# CHECK-DISABLED: SUB.W
|
||||
SUB r0, r1, #0xFFFFFF00
|
||||
# CHECK: addw r0, r1, #256
|
||||
# CHECK: add.w r0, r1, #256
|
||||
# CHECK-DISABLED: note: instruction requires: NegativeImmediates
|
||||
# CHECK-DISABLED: SUB
|
||||
SUBS r0, r1, #0xFFFFFF00
|
||||
@ -188,6 +188,6 @@
|
||||
# CHECK-DISABLED: SUBS.W
|
||||
|
||||
ADD r0, r1, #-13
|
||||
# CHECK: subw r0, r1, #13
|
||||
# CHECK: sub.w r0, r1, #13
|
||||
# CHECK-DISABLED: note: instruction requires: NegativeImmediates
|
||||
# CHECK-DISABLED: ADD
|
||||
|
@ -1,12 +1,11 @@
|
||||
// RUN: not llvm-mc -triple armv6m--none-eabi < %s 2>&1 | FileCheck %s
|
||||
|
||||
// Some of these CHECK lines need to uses regexes to that the amount of
|
||||
// whitespace between the start of the line and the caret is significant.
|
||||
|
||||
add sp, r0, #4
|
||||
// CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
// CHECK: note: instruction requires: thumb2
|
||||
// CHECK: note: operand must be a register sp
|
||||
// CHECK-NEXT: {{^ add sp, r0, #4}}
|
||||
// CHECK-NEXT: {{^ \^}}
|
||||
// CHECK: note: too many operands for instruction
|
||||
// CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
// CHECK-NEXT: add sp, r0, #4
|
||||
// CHECK-NEXT: ^
|
||||
// CHECK-NEXT: note: operand must be a register sp
|
||||
// CHECK-NEXT: add sp, r0, #4
|
||||
// CHECK-NEXT: ^
|
||||
// CHECK-NEXT: note: too many operands for instruction
|
||||
// CHECK-NEXT: add sp, r0, #4
|
||||
// CHECK-NEXT: ^
|
||||
|
@ -244,24 +244,44 @@
|
||||
add sp, sp, #512
|
||||
add r2, sp, #1024
|
||||
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-ERRORS: add sp, #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: add sp, #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-ERRORS: add sp, #3
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-ERRORS: add sp, sp, #512
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: error: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: add r2, sp, #1024
|
||||
@ CHECK-ERRORS: add sp, #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
|
||||
@ CHECK-ERRORS: note: invalid operand for instruction
|
||||
@ CHECK-ERRORS: add sp, #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: add sp, #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-ERRORS: add sp, #3
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
|
||||
@ CHECK-ERRORS: add sp, #3
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: invalid operand for instruction
|
||||
@ CHECK-ERRORS: add sp, #3
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: add sp, #3
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-ERRORS: add sp, sp, #512
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
|
||||
@ CHECK-ERRORS: add sp, sp, #512
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: invalid operand for instruction
|
||||
@ CHECK-ERRORS: add sp, sp, #512
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: note: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: add sp, sp, #512
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: instruction requires: thumb2
|
||||
@ CHECK-ERRORS: add r2, sp, #1024
|
||||
@ CHECK-ERRORS: ^
|
||||
add r2, sp, ip
|
||||
@ CHECK-ERRORS: error: source register must be the same as destination
|
||||
@ CHECK-ERRORS: add r2, sp, ip
|
||||
|
@ -425,3 +425,8 @@
|
||||
# CHECK-V7-NEXT: [0xa3,0xeb,0x02,0x0d]
|
||||
# CHECK-V7: warning: potentially undefined instruction encoding
|
||||
# CHECK-V7-NEXT: [0xa3,0xeb,0xc5,0x0d]
|
||||
# CHECK-V7-NEXT: ^
|
||||
[0x0f,0xf2,0x00,0x4d]
|
||||
# CHECK-V7-NEXT: warning: potentially undefined instruction encoding
|
||||
# CHECK-V7-NEXT: [0x0f,0xf2,0x00,0x4d]
|
||||
# CHECK-V7-NEXT: ^
|
||||
|
@ -1,4 +1,4 @@
|
||||
# RUN: llvm-mc --disassemble %s -triple=thumbv7-apple-darwin9 -mcpu=cortex-a9 | FileCheck %s
|
||||
# RUN: llvm-mc --disassemble --show-encoding %s -triple=thumbv7-apple-darwin9 -mcpu=cortex-a9 | FileCheck %s
|
||||
|
||||
# CHECK: add r5, sp, #68
|
||||
0x11 0xad
|
||||
@ -84,9 +84,12 @@
|
||||
# CHECK: sub sp, #60
|
||||
0x8f 0xb0
|
||||
|
||||
# CHECK: subw r0, pc, #1
|
||||
# CHECK: adr.w r0, #-1
|
||||
0xaf 0xf2 0x01 0x00
|
||||
|
||||
# CHECK: subw r0, pc, #0
|
||||
0xaf 0xf2 0x00 0x00
|
||||
|
||||
# CHECK: subw r0, sp, #835
|
||||
0xad 0xf2 0x43 0x30
|
||||
|
||||
@ -155,7 +158,7 @@
|
||||
# CHECK: ldm r5!, {r0, r1, r2, r3, r4}
|
||||
0x1f 0xcd
|
||||
|
||||
# CHECK: addw r0, pc, #1050
|
||||
# CHECK: adr.w r0, #1050
|
||||
0x0f 0xf2 0x1a 0x40
|
||||
|
||||
# CHECK: ldrd r3, r8, [r11, #-60]
|
||||
|
@ -38,3 +38,5 @@
|
||||
0x90 0xec 0x00 0x0e
|
||||
# CHECK: ldc p14
|
||||
|
||||
[0x0f,0xf2,0x00,0x4d]
|
||||
# CHECK: adr.w sp, #1024
|
||||
|
@ -90,14 +90,14 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# ADR
|
||||
#------------------------------------------------------------------------------
|
||||
# CHECK: subw r11, pc, #3270
|
||||
# CHECK: subw r11, pc, #826
|
||||
# CHECK: subw r1, pc, #0
|
||||
|
||||
# CHECK: adr.w r11, #-3270
|
||||
# CHECK-NEXT: adr.w r11, #-826
|
||||
# CHECK-NEXT: subw r1, pc, #0
|
||||
# CHECK-NEXT: adr.w r0, #1024
|
||||
0xaf 0xf6 0xc6 0x4b
|
||||
0xaf 0xf2 0x3a 0x3b
|
||||
0xaf 0xf2 0x00 0x01
|
||||
|
||||
0x0f,0xf2,0x00,0x40
|
||||
#------------------------------------------------------------------------------
|
||||
# AND (immediate)
|
||||
#------------------------------------------------------------------------------
|
||||
|
26
test/tools/llvm-mca/ARM/simple-cortex-m33.s
Normal file
26
test/tools/llvm-mca/ARM/simple-cortex-m33.s
Normal file
@ -0,0 +1,26 @@
|
||||
# NOTE: Assertions have been autogenerated by utils/update_mca_test_checks.py
|
||||
# RUN: llvm-mca -mtriple=thumbv7 --mcpu=cortex-m33 -instruction-tables -o - %s | FileCheck %s
|
||||
|
||||
sub sp, #4
|
||||
|
||||
# CHECK: Instruction Info:
|
||||
# CHECK-NEXT: [1]: #uOps
|
||||
# CHECK-NEXT: [2]: Latency
|
||||
# CHECK-NEXT: [3]: RThroughput
|
||||
# CHECK-NEXT: [4]: MayLoad
|
||||
# CHECK-NEXT: [5]: MayStore
|
||||
# CHECK-NEXT: [6]: HasSideEffects (U)
|
||||
|
||||
# CHECK: [1] [2] [3] [4] [5] [6] Instructions:
|
||||
# CHECK-NEXT: 1 1 1.00 U sub sp, #4
|
||||
|
||||
# CHECK: Resources:
|
||||
# CHECK-NEXT: [0] - M4Unit
|
||||
|
||||
# CHECK: Resource pressure per iteration:
|
||||
# CHECK-NEXT: [0]
|
||||
# CHECK-NEXT: 1.00
|
||||
|
||||
# CHECK: Resource pressure by instruction:
|
||||
# CHECK-NEXT: [0] Instructions:
|
||||
# CHECK-NEXT: 1.00 sub sp, #4
|
Loading…
x
Reference in New Issue
Block a user