mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-29 14:40:25 +00:00
Major changes to Thumb (not Thumb2). Many 16-bit instructions either modifies CPSR when they are outside the IT blocks, or they can predicated when in Thumb2. Move the implicit def of CPSR to an optional def which defaults CPSR. This allows the 's' bit to be toggled dynamically.
A side-effect of this change is asm printer is now using unified assembly. There are some minor clean ups and fixes as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75359 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
dd6f63209c
commit
446c428bf3
@ -868,7 +868,7 @@ unsigned ARMBaseRegisterInfo::getRegisterPairOdd(unsigned Reg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Dup in ARMBaseInstrInfo.cpp
|
||||
static inline
|
||||
const MachineInstrBuilder &AddDefaultPred(const MachineInstrBuilder &MIB) {
|
||||
return MIB.addImm((int64_t)ARMCC::AL).addReg(0);
|
||||
|
@ -459,8 +459,11 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue Op, SDValue N,
|
||||
// wouldn't work without additional code to position the node within
|
||||
// ISel's topological ordering in a place where ISel will process it
|
||||
// normally. Instead, just explicitly issue a tMOVri8 node!
|
||||
Offset = SDValue(CurDAG->getTargetNode(ARM::tMOVi8, dl, MVT::i32,
|
||||
CurDAG->getTargetConstant(0, MVT::i32)), 0);
|
||||
SDValue CC = CurDAG->getRegister(ARM::CPSR, MVT::i32);
|
||||
SDValue Pred = CurDAG->getTargetConstant(0xEULL, MVT::i32);
|
||||
SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
|
||||
SDValue Ops[] = { CC, CurDAG->getTargetConstant(0, MVT::i32), Pred, PredReg };
|
||||
Offset = SDValue(CurDAG->getTargetNode(ARM::tMOVi8, dl, MVT::i32, Ops,4),0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -871,10 +874,13 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
TLI.getPointerTy());
|
||||
|
||||
SDNode *ResNode;
|
||||
if (Subtarget->isThumb1Only())
|
||||
if (Subtarget->isThumb1Only()) {
|
||||
SDValue Pred = CurDAG->getTargetConstant(0xEULL, MVT::i32);
|
||||
SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
|
||||
SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() };
|
||||
ResNode = CurDAG->getTargetNode(ARM::tLDRcp, dl, MVT::i32, MVT::Other,
|
||||
CPIdx, CurDAG->getEntryNode());
|
||||
else {
|
||||
Ops, 4);
|
||||
} else {
|
||||
SDValue Ops[] = {
|
||||
CPIdx,
|
||||
CurDAG->getRegister(0, MVT::i32),
|
||||
@ -901,11 +907,11 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, TFI,
|
||||
CurDAG->getTargetConstant(0, MVT::i32));
|
||||
} else {
|
||||
unsigned Opc = Subtarget->hasThumb2() ? ARM::t2ADDri : ARM::ADDri;
|
||||
SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32),
|
||||
getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
|
||||
CurDAG->getRegister(0, MVT::i32) };
|
||||
return CurDAG->SelectNodeTo(N, (Subtarget->hasThumb2()) ? ARM::t2ADDri : ARM::ADDri,
|
||||
MVT::i32, Ops, 5);
|
||||
getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
|
||||
CurDAG->getRegister(0, MVT::i32) };
|
||||
return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5);
|
||||
}
|
||||
}
|
||||
case ISD::ADD: {
|
||||
@ -922,7 +928,7 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
}
|
||||
if (RHSR && RHSR->getReg() == ARM::SP) {
|
||||
SDValue Val = SDValue(CurDAG->getTargetNode(ARM::tMOVlor2hir, dl,
|
||||
Op.getValueType(), N0, N0), 0);
|
||||
Op.getValueType(), N0, N0),0);
|
||||
return CurDAG->SelectNodeTo(N, ARM::tADDhirr, Op.getValueType(), Val, N1);
|
||||
}
|
||||
break;
|
||||
|
@ -110,6 +110,28 @@ def IndexModePost : IndexMode<2>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ARM special operands.
|
||||
//
|
||||
|
||||
// ARM Predicate operand. Default to 14 = always (AL). Second part is CC
|
||||
// register whose default is 0 (no register).
|
||||
def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),
|
||||
(ops (i32 14), (i32 zero_reg))> {
|
||||
let PrintMethod = "printPredicateOperand";
|
||||
}
|
||||
|
||||
// Conditional code result for instructions whose 's' bit is set, e.g. subs.
|
||||
def cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 zero_reg))> {
|
||||
let PrintMethod = "printSBitModifierOperand";
|
||||
}
|
||||
|
||||
// Same as cc_out except it defaults to setting CPSR.
|
||||
def s_cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 CPSR))> {
|
||||
let PrintMethod = "printSBitModifierOperand";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ARM Instruction templates.
|
||||
//
|
||||
|
||||
@ -773,26 +795,26 @@ class ARMV6Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
|
||||
// TI - Thumb instruction.
|
||||
|
||||
class ThumbI<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
|
||||
class ThumbI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
|
||||
string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
|
||||
let OutOperandList = outs;
|
||||
let InOperandList = ins;
|
||||
let OutOperandList = oops;
|
||||
let InOperandList = iops;
|
||||
let AsmString = asm;
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [IsThumb];
|
||||
}
|
||||
|
||||
class TI<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: ThumbI<outs, ins, AddrModeNone, Size2Bytes, asm, "", pattern>;
|
||||
class TI<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: ThumbI<oops, iops, AddrModeNone, Size2Bytes, asm, "", pattern>;
|
||||
|
||||
// BL, BLX(1) are translated by assembler into two instructions
|
||||
class TIx2<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: ThumbI<outs, ins, AddrModeNone, Size4Bytes, asm, "", pattern>;
|
||||
class TIx2<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: ThumbI<oops, iops, AddrModeNone, Size4Bytes, asm, "", pattern>;
|
||||
|
||||
// BR_JT instructions
|
||||
class TJTI<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: ThumbI<outs, ins, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
||||
class TJTI<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: ThumbI<oops, iops, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
||||
|
||||
// TPat - Same as Pat<>, but requires that the compiler be in Thumb mode.
|
||||
class TPat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
@ -804,34 +826,73 @@ class Tv5Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
}
|
||||
|
||||
// Thumb1 only
|
||||
class Thumb1I<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
|
||||
class Thumb1I<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
|
||||
string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
|
||||
let OutOperandList = outs;
|
||||
let InOperandList = ins;
|
||||
let OutOperandList = oops;
|
||||
let InOperandList = iops;
|
||||
let AsmString = asm;
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [IsThumb1Only];
|
||||
}
|
||||
|
||||
class T1I<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeNone, Size2Bytes, asm, "", pattern>;
|
||||
class T1I1<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeT1_1, Size2Bytes, asm, "", pattern>;
|
||||
class T1I2<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeT1_2, Size2Bytes, asm, "", pattern>;
|
||||
class T1I4<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeT1_4, Size2Bytes, asm, "", pattern>;
|
||||
class T1Is<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeT1_s, Size2Bytes, asm, "", pattern>;
|
||||
class T1Ix2<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeNone, Size4Bytes, asm, "", pattern>;
|
||||
class T1JTI<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
||||
class T1I<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: Thumb1I<oops, iops, AddrModeNone, Size2Bytes, asm, "", pattern>;
|
||||
class T1Ix2<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: Thumb1I<oops, iops, AddrModeNone, Size4Bytes, asm, "", pattern>;
|
||||
class T1JTI<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: Thumb1I<oops, iops, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
||||
|
||||
// Two-address instructions
|
||||
class T1It<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb1I<outs, ins, AddrModeNone, Size2Bytes, asm, "$lhs = $dst", pattern>;
|
||||
class T1It<dag oops, dag iops, string asm, list<dag> pattern>
|
||||
: Thumb1I<oops, iops, AddrModeNone, Size2Bytes, asm, "$lhs = $dst", pattern>;
|
||||
|
||||
// Thumb1 instruction that can either be predicated or set CPSR.
|
||||
class Thumb1sI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
|
||||
string opc, string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
|
||||
let OutOperandList = !con(oops, (ops s_cc_out:$s));
|
||||
let InOperandList = !con(iops, (ops pred:$p));
|
||||
let AsmString = !strconcat(opc, !strconcat("${s}${p}", asm));
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [IsThumb1Only];
|
||||
}
|
||||
|
||||
class T1sI<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1sI<oops, iops, AddrModeNone, Size2Bytes, opc, asm, "", pattern>;
|
||||
|
||||
// Two-address instructions
|
||||
class T1sIt<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1sI<oops, iops, AddrModeNone, Size2Bytes, opc, asm,
|
||||
"$lhs = $dst", pattern>;
|
||||
|
||||
// Thumb1 instruction that can be predicated.
|
||||
class Thumb1pI<dag oops, dag iops, AddrMode am, SizeFlagVal sz,
|
||||
string opc, string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
|
||||
let OutOperandList = oops;
|
||||
let InOperandList = !con(iops, (ops pred:$p));
|
||||
let AsmString = !strconcat(opc, !strconcat("${p}", asm));
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [IsThumb1Only];
|
||||
}
|
||||
|
||||
class T1pI<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeNone, Size2Bytes, opc, asm, "", pattern>;
|
||||
|
||||
// Two-address instructions
|
||||
class T1pIt<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeNone, Size2Bytes, opc, asm,
|
||||
"$lhs = $dst", pattern>;
|
||||
|
||||
class T1pI1<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeT1_1, Size2Bytes, opc, asm, "", pattern>;
|
||||
class T1pI2<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeT1_2, Size2Bytes, opc, asm, "", pattern>;
|
||||
class T1pI4<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeT1_4, Size2Bytes, opc, asm, "", pattern>;
|
||||
class T1pIs<dag oops, dag iops, string opc, string asm, list<dag> pattern>
|
||||
: Thumb1pI<oops, iops, AddrModeT1_s, Size2Bytes, opc, asm, "", pattern>;
|
||||
|
||||
class T1Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
list<Predicate> Predicates = [IsThumb1Only];
|
||||
|
@ -316,19 +316,6 @@ def addrmodepc : Operand<i32>,
|
||||
let MIOperandInfo = (ops GPR, i32imm);
|
||||
}
|
||||
|
||||
// ARM Predicate operand. Default to 14 = always (AL). Second part is CC
|
||||
// register whose default is 0 (no register).
|
||||
def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),
|
||||
(ops (i32 14), (i32 zero_reg))> {
|
||||
let PrintMethod = "printPredicateOperand";
|
||||
}
|
||||
|
||||
// Conditional code result for instructions whose 's' bit is set, e.g. subs.
|
||||
//
|
||||
def cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 zero_reg))> {
|
||||
let PrintMethod = "printSBitModifierOperand";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "ARMInstrFormats.td"
|
||||
|
@ -155,9 +155,9 @@ def tADDspi : T1It<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
|
||||
//
|
||||
|
||||
let isReturn = 1, isTerminator = 1 in {
|
||||
def tBX_RET : T1I<(outs), (ins), "bx lr", [(ARMretflag)]>;
|
||||
def tBX_RET : TI<(outs), (ins), "bx lr", [(ARMretflag)]>;
|
||||
// Alternative return instruction used by vararg functions.
|
||||
def tBX_RET_vararg : T1I<(outs), (ins tGPR:$target), "bx $target", []>;
|
||||
def tBX_RET_vararg : TI<(outs), (ins tGPR:$target), "bx $target", []>;
|
||||
}
|
||||
|
||||
// FIXME: remove when we have a way to marking a MI with these properties.
|
||||
@ -212,69 +212,69 @@ let isBranch = 1, isTerminator = 1 in
|
||||
//
|
||||
|
||||
let canFoldAsLoad = 1 in
|
||||
def tLDR : T1I4<(outs tGPR:$dst), (ins t_addrmode_s4:$addr),
|
||||
"ldr $dst, $addr",
|
||||
def tLDR : T1pI4<(outs tGPR:$dst), (ins t_addrmode_s4:$addr),
|
||||
"ldr", " $dst, $addr",
|
||||
[(set tGPR:$dst, (load t_addrmode_s4:$addr))]>;
|
||||
|
||||
def tLDRB : T1I1<(outs tGPR:$dst), (ins t_addrmode_s1:$addr),
|
||||
"ldrb $dst, $addr",
|
||||
def tLDRB : T1pI1<(outs tGPR:$dst), (ins t_addrmode_s1:$addr),
|
||||
"ldrb", " $dst, $addr",
|
||||
[(set tGPR:$dst, (zextloadi8 t_addrmode_s1:$addr))]>;
|
||||
|
||||
def tLDRH : T1I2<(outs tGPR:$dst), (ins t_addrmode_s2:$addr),
|
||||
"ldrh $dst, $addr",
|
||||
def tLDRH : T1pI2<(outs tGPR:$dst), (ins t_addrmode_s2:$addr),
|
||||
"ldrh", " $dst, $addr",
|
||||
[(set tGPR:$dst, (zextloadi16 t_addrmode_s2:$addr))]>;
|
||||
|
||||
def tLDRSB : T1I1<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
|
||||
"ldrsb $dst, $addr",
|
||||
def tLDRSB : T1pI1<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
|
||||
"ldrsb", " $dst, $addr",
|
||||
[(set tGPR:$dst, (sextloadi8 t_addrmode_rr:$addr))]>;
|
||||
|
||||
def tLDRSH : T1I2<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
|
||||
"ldrsh $dst, $addr",
|
||||
def tLDRSH : T1pI2<(outs tGPR:$dst), (ins t_addrmode_rr:$addr),
|
||||
"ldrsh", " $dst, $addr",
|
||||
[(set tGPR:$dst, (sextloadi16 t_addrmode_rr:$addr))]>;
|
||||
|
||||
let canFoldAsLoad = 1 in
|
||||
def tLDRspi : T1Is<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
|
||||
"ldr $dst, $addr",
|
||||
def tLDRspi : T1pIs<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
|
||||
"ldr", " $dst, $addr",
|
||||
[(set tGPR:$dst, (load t_addrmode_sp:$addr))]>;
|
||||
|
||||
// Special instruction for restore. It cannot clobber condition register
|
||||
// when it's expanded by eliminateCallFramePseudoInstr().
|
||||
let canFoldAsLoad = 1, mayLoad = 1 in
|
||||
def tRestore : T1Is<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
|
||||
"ldr $dst, $addr", []>;
|
||||
def tRestore : T1pIs<(outs tGPR:$dst), (ins t_addrmode_sp:$addr),
|
||||
"ldr", " $dst, $addr", []>;
|
||||
|
||||
// Load tconstpool
|
||||
let canFoldAsLoad = 1 in
|
||||
def tLDRpci : T1Is<(outs tGPR:$dst), (ins i32imm:$addr),
|
||||
"ldr $dst, $addr",
|
||||
def tLDRpci : T1pIs<(outs tGPR:$dst), (ins i32imm:$addr),
|
||||
"ldr", " $dst, $addr",
|
||||
[(set tGPR:$dst, (load (ARMWrapper tconstpool:$addr)))]>;
|
||||
|
||||
// Special LDR for loads from non-pc-relative constpools.
|
||||
let canFoldAsLoad = 1, mayLoad = 1, isReMaterializable = 1 in
|
||||
def tLDRcp : T1Is<(outs tGPR:$dst), (ins i32imm:$addr),
|
||||
"ldr $dst, $addr", []>;
|
||||
def tLDRcp : T1pIs<(outs tGPR:$dst), (ins i32imm:$addr),
|
||||
"ldr", " $dst, $addr", []>;
|
||||
|
||||
def tSTR : T1I4<(outs), (ins tGPR:$src, t_addrmode_s4:$addr),
|
||||
"str $src, $addr",
|
||||
def tSTR : T1pI4<(outs), (ins tGPR:$src, t_addrmode_s4:$addr),
|
||||
"str", " $src, $addr",
|
||||
[(store tGPR:$src, t_addrmode_s4:$addr)]>;
|
||||
|
||||
def tSTRB : T1I1<(outs), (ins tGPR:$src, t_addrmode_s1:$addr),
|
||||
"strb $src, $addr",
|
||||
def tSTRB : T1pI1<(outs), (ins tGPR:$src, t_addrmode_s1:$addr),
|
||||
"strb", " $src, $addr",
|
||||
[(truncstorei8 tGPR:$src, t_addrmode_s1:$addr)]>;
|
||||
|
||||
def tSTRH : T1I2<(outs), (ins tGPR:$src, t_addrmode_s2:$addr),
|
||||
"strh $src, $addr",
|
||||
def tSTRH : T1pI2<(outs), (ins tGPR:$src, t_addrmode_s2:$addr),
|
||||
"strh", " $src, $addr",
|
||||
[(truncstorei16 tGPR:$src, t_addrmode_s2:$addr)]>;
|
||||
|
||||
def tSTRspi : T1Is<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
|
||||
"str $src, $addr",
|
||||
def tSTRspi : T1pIs<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
|
||||
"str", " $src, $addr",
|
||||
[(store tGPR:$src, t_addrmode_sp:$addr)]>;
|
||||
|
||||
let mayStore = 1 in {
|
||||
// Special instruction for spill. It cannot clobber condition register
|
||||
// when it's expanded by eliminateCallFramePseudoInstr().
|
||||
def tSpill : T1Is<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
|
||||
"str $src, $addr", []>;
|
||||
def tSpill : T1pIs<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
|
||||
"str", " $src, $addr", []>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -282,6 +282,7 @@ def tSpill : T1Is<(outs), (ins tGPR:$src, t_addrmode_sp:$addr),
|
||||
//
|
||||
|
||||
// TODO: A7-44: LDMIA - load multiple
|
||||
// TODO: Allow these to be predicated
|
||||
|
||||
let mayLoad = 1 in
|
||||
def tPOP : T1I<(outs reglist:$dst1, variable_ops), (ins),
|
||||
@ -296,216 +297,209 @@ def tPUSH : T1I<(outs), (ins reglist:$src1, variable_ops),
|
||||
//
|
||||
|
||||
// Add with carry register
|
||||
let isCommutable = 1, Defs = [CPSR], Uses = [CPSR] in
|
||||
def tADCS : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"adc $dst, $rhs",
|
||||
let isCommutable = 1, Uses = [CPSR] in
|
||||
def tADC : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"adc", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (adde tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// Add immediate
|
||||
let Defs = [CPSR] in
|
||||
def tADDi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"add $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7:$rhs))]>;
|
||||
def tADDi3 : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"add", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7:$rhs))]>;
|
||||
|
||||
let Defs = [CPSR] in
|
||||
def tADDi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"add $dst, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255:$rhs))]>;
|
||||
def tADDi8 : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"add", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255:$rhs))]>;
|
||||
|
||||
// Add register
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tADDrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"add $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let isCommutable = 1 in
|
||||
def tADDrr : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"add", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
let neverHasSideEffects = 1 in
|
||||
def tADDhirr : T1It<(outs tGPR:$dst), (ins GPR:$lhs, GPR:$rhs),
|
||||
"add $dst, $rhs @ addhirr", []>;
|
||||
def tADDhirr : T1pIt<(outs tGPR:$dst), (ins GPR:$lhs, GPR:$rhs),
|
||||
"add", " $dst, $rhs @ addhirr", []>;
|
||||
|
||||
// And register
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tAND : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"and $dst, $rhs",
|
||||
[(set tGPR:$dst, (and tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let isCommutable = 1 in
|
||||
def tAND : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"and", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (and tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// ASR immediate
|
||||
let Defs = [CPSR] in
|
||||
def tASRri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"asr $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (sra tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
def tASRri : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"asr", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (sra tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
|
||||
// ASR register
|
||||
let Defs = [CPSR] in
|
||||
def tASRrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"asr $dst, $rhs",
|
||||
[(set tGPR:$dst, (sra tGPR:$lhs, tGPR:$rhs))]>;
|
||||
def tASRrr : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"asr", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (sra tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// BIC register
|
||||
let Defs = [CPSR] in
|
||||
def tBIC : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"bic $dst, $rhs",
|
||||
[(set tGPR:$dst, (and tGPR:$lhs, (not tGPR:$rhs)))]>;
|
||||
def tBIC : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"bic", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (and tGPR:$lhs, (not tGPR:$rhs)))]>;
|
||||
|
||||
// CMN register
|
||||
let Defs = [CPSR] in {
|
||||
def tCMN : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmn $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, (ineg tGPR:$rhs))]>;
|
||||
def tCMNZ : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmn $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, (ineg tGPR:$rhs))]>;
|
||||
def tCMN : T1pI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmn", " $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, (ineg tGPR:$rhs))]>;
|
||||
def tCMNZ : T1pI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmn", " $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, (ineg tGPR:$rhs))]>;
|
||||
}
|
||||
|
||||
// CMP immediate
|
||||
let Defs = [CPSR] in {
|
||||
def tCMPi8 : T1I<(outs), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"cmp $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, imm0_255:$rhs)]>;
|
||||
def tCMPZi8 : T1I<(outs), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"cmp $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, imm0_255:$rhs)]>;
|
||||
def tCMPi8 : T1pI<(outs), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"cmp", " $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, imm0_255:$rhs)]>;
|
||||
def tCMPZi8 : T1pI<(outs), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"cmp", " $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, imm0_255:$rhs)]>;
|
||||
|
||||
}
|
||||
|
||||
// CMP register
|
||||
let Defs = [CPSR] in {
|
||||
def tCMPr : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmp $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, tGPR:$rhs)]>;
|
||||
def tCMPZr : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmp $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, tGPR:$rhs)]>;
|
||||
def tCMPr : T1pI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmp", " $lhs, $rhs",
|
||||
[(ARMcmp tGPR:$lhs, tGPR:$rhs)]>;
|
||||
def tCMPZr : T1pI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"cmp", " $lhs, $rhs",
|
||||
[(ARMcmpZ tGPR:$lhs, tGPR:$rhs)]>;
|
||||
|
||||
// TODO: Make use of the followings cmp hi regs
|
||||
def tCMPhir : T1pI<(outs), (ins GPR:$lhs, GPR:$rhs),
|
||||
"cmp", " $lhs, $rhs", []>;
|
||||
def tCMPZhir : T1pI<(outs), (ins GPR:$lhs, GPR:$rhs),
|
||||
"cmp", " $lhs, $rhs", []>;
|
||||
}
|
||||
|
||||
// TODO: A7-37: CMP(3) - cmp hi regs
|
||||
|
||||
// XOR register
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tEOR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"eor $dst, $rhs",
|
||||
[(set tGPR:$dst, (xor tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let isCommutable = 1 in
|
||||
def tEOR : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"eor", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (xor tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// LSL immediate
|
||||
let Defs = [CPSR] in
|
||||
def tLSLri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"lsl $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (shl tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
def tLSLri : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"lsl", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (shl tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
|
||||
// LSL register
|
||||
let Defs = [CPSR] in
|
||||
def tLSLrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"lsl $dst, $rhs",
|
||||
[(set tGPR:$dst, (shl tGPR:$lhs, tGPR:$rhs))]>;
|
||||
def tLSLrr : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"lsl", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (shl tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// LSR immediate
|
||||
let Defs = [CPSR] in
|
||||
def tLSRri : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"lsr $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (srl tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
def tLSRri : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"lsr", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (srl tGPR:$lhs, (i32 imm:$rhs)))]>;
|
||||
|
||||
// LSR register
|
||||
let Defs = [CPSR] in
|
||||
def tLSRrr : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"lsr $dst, $rhs",
|
||||
[(set tGPR:$dst, (srl tGPR:$lhs, tGPR:$rhs))]>;
|
||||
def tLSRrr : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"lsr", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (srl tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// move register
|
||||
let Defs = [CPSR] in
|
||||
def tMOVi8 : T1I<(outs tGPR:$dst), (ins i32imm:$src),
|
||||
"mov $dst, $src",
|
||||
[(set tGPR:$dst, imm0_255:$src)]>;
|
||||
def tMOVi8 : T1sI<(outs tGPR:$dst), (ins i32imm:$src),
|
||||
"mov", " $dst, $src",
|
||||
[(set tGPR:$dst, imm0_255:$src)]>;
|
||||
|
||||
// TODO: A7-73: MOV(2) - mov setting flag.
|
||||
|
||||
|
||||
// Note: MOV(2) of two low regs updates the flags, so we emit this as 'cpy',
|
||||
// which is MOV(3). This also supports high registers.
|
||||
let neverHasSideEffects = 1 in {
|
||||
// FIXME: Make this predicable.
|
||||
def tMOVr : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"cpy $dst, $src", []>;
|
||||
"mov $dst, $src", []>;
|
||||
let Defs = [CPSR] in
|
||||
def tMOVSr : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"movs $dst, $src", []>;
|
||||
|
||||
// FIXME: Make these predicable.
|
||||
def tMOVhir2lor : T1I<(outs tGPR:$dst), (ins GPR:$src),
|
||||
"cpy $dst, $src\t@ hir2lor", []>;
|
||||
"mov $dst, $src\t@ hir2lor", []>;
|
||||
def tMOVlor2hir : T1I<(outs GPR:$dst), (ins tGPR:$src),
|
||||
"cpy $dst, $src\t@ lor2hir", []>;
|
||||
"mov $dst, $src\t@ lor2hir", []>;
|
||||
def tMOVhir2hir : T1I<(outs GPR:$dst), (ins GPR:$src),
|
||||
"cpy $dst, $src\t@ hir2hir", []>;
|
||||
"mov $dst, $src\t@ hir2hir", []>;
|
||||
} // neverHasSideEffects
|
||||
|
||||
// multiply register
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tMUL : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"mul $dst, $rhs",
|
||||
[(set tGPR:$dst, (mul tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let isCommutable = 1 in
|
||||
def tMUL : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"mul", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (mul tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// move inverse register
|
||||
let Defs = [CPSR] in
|
||||
def tMVN : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"mvn $dst, $src",
|
||||
[(set tGPR:$dst, (not tGPR:$src))]>;
|
||||
|
||||
// negate register
|
||||
let Defs = [CPSR] in
|
||||
def tNEG : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"neg $dst, $src",
|
||||
[(set tGPR:$dst, (ineg tGPR:$src))]>;
|
||||
def tMVN : T1sI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"mvn", " $dst, $src",
|
||||
[(set tGPR:$dst, (not tGPR:$src))]>;
|
||||
|
||||
// bitwise or register
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tORR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"orr $dst, $rhs",
|
||||
[(set tGPR:$dst, (or tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let isCommutable = 1 in
|
||||
def tORR : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"orr", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (or tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// swaps
|
||||
def tREV : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"rev $dst, $src",
|
||||
[(set tGPR:$dst, (bswap tGPR:$src))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
def tREV16 : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"rev16 $dst, $src",
|
||||
[(set tGPR:$dst,
|
||||
(or (and (srl tGPR:$src, (i32 8)), 0xFF),
|
||||
(or (and (shl tGPR:$src, (i32 8)), 0xFF00),
|
||||
(or (and (srl tGPR:$src, (i32 8)), 0xFF0000),
|
||||
(and (shl tGPR:$src, (i32 8)), 0xFF000000)))))]>,
|
||||
def tREV : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"rev", " $dst, $src",
|
||||
[(set tGPR:$dst, (bswap tGPR:$src))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
def tREVSH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"revsh $dst, $src",
|
||||
[(set tGPR:$dst,
|
||||
(sext_inreg
|
||||
(or (srl (and tGPR:$src, 0xFFFF), (i32 8)),
|
||||
(shl tGPR:$src, (i32 8))), i16))]>,
|
||||
def tREV16 : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"rev16", " $dst, $src",
|
||||
[(set tGPR:$dst,
|
||||
(or (and (srl tGPR:$src, (i32 8)), 0xFF),
|
||||
(or (and (shl tGPR:$src, (i32 8)), 0xFF00),
|
||||
(or (and (srl tGPR:$src, (i32 8)), 0xFF0000),
|
||||
(and (shl tGPR:$src, (i32 8)), 0xFF000000)))))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
def tREVSH : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"revsh", " $dst, $src",
|
||||
[(set tGPR:$dst,
|
||||
(sext_inreg
|
||||
(or (srl (and tGPR:$src, 0xFFFF), (i32 8)),
|
||||
(shl tGPR:$src, (i32 8))), i16))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
// rotate right register
|
||||
let Defs = [CPSR] in
|
||||
def tROR : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"ror $dst, $rhs",
|
||||
[(set tGPR:$dst, (rotr tGPR:$lhs, tGPR:$rhs))]>;
|
||||
def tROR : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"ror", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (rotr tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// negate register
|
||||
def tRSB : T1sI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"rsb", " $dst, $src, #0",
|
||||
[(set tGPR:$dst, (ineg tGPR:$src))]>;
|
||||
|
||||
// Subtract with carry register
|
||||
let Defs = [CPSR], Uses = [CPSR] in
|
||||
def tSBCS : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"sbc $dst, $rhs",
|
||||
[(set tGPR:$dst, (sube tGPR:$lhs, tGPR:$rhs))]>;
|
||||
let Uses = [CPSR] in
|
||||
def tSBC : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"sbc", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (sube tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// Subtract immediate
|
||||
let Defs = [CPSR] in
|
||||
def tSUBi3 : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"sub $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7_neg:$rhs))]>;
|
||||
def tSUBi3 : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"sub", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm0_7_neg:$rhs))]>;
|
||||
|
||||
let Defs = [CPSR] in
|
||||
def tSUBi8 : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"sub $dst, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255_neg:$rhs))]>;
|
||||
def tSUBi8 : T1sIt<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"sub", " $dst, $rhs",
|
||||
[(set tGPR:$dst, (add tGPR:$lhs, imm8_255_neg:$rhs))]>;
|
||||
|
||||
// subtract register
|
||||
let Defs = [CPSR] in
|
||||
def tSUBrr : T1I<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"sub $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (sub tGPR:$lhs, tGPR:$rhs))]>;
|
||||
def tSUBrr : T1sI<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"sub", " $dst, $lhs, $rhs",
|
||||
[(set tGPR:$dst, (sub tGPR:$lhs, tGPR:$rhs))]>;
|
||||
|
||||
// TODO: A7-96: STMIA - store multiple.
|
||||
|
||||
@ -513,38 +507,39 @@ def tSUBspi : T1It<(outs tGPR:$dst), (ins tGPR:$lhs, i32imm:$rhs),
|
||||
"sub $dst, $rhs * 4", []>;
|
||||
|
||||
// sign-extend byte
|
||||
def tSXTB : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"sxtb $dst, $src",
|
||||
[(set tGPR:$dst, (sext_inreg tGPR:$src, i8))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
def tSXTB : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"sxtb", " $dst, $src",
|
||||
[(set tGPR:$dst, (sext_inreg tGPR:$src, i8))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
// sign-extend short
|
||||
def tSXTH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"sxth $dst, $src",
|
||||
[(set tGPR:$dst, (sext_inreg tGPR:$src, i16))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
def tSXTH : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"sxth", " $dst, $src",
|
||||
[(set tGPR:$dst, (sext_inreg tGPR:$src, i16))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
// test
|
||||
let isCommutable = 1, Defs = [CPSR] in
|
||||
def tTST : T1I<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"tst $lhs, $rhs",
|
||||
[(ARMcmpZ (and tGPR:$lhs, tGPR:$rhs), 0)]>;
|
||||
def tTST : T1pI<(outs), (ins tGPR:$lhs, tGPR:$rhs),
|
||||
"tst", " $lhs, $rhs",
|
||||
[(ARMcmpZ (and tGPR:$lhs, tGPR:$rhs), 0)]>;
|
||||
|
||||
// zero-extend byte
|
||||
def tUXTB : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"uxtb $dst, $src",
|
||||
[(set tGPR:$dst, (and tGPR:$src, 0xFF))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
def tUXTB : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"uxtb", " $dst, $src",
|
||||
[(set tGPR:$dst, (and tGPR:$src, 0xFF))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
// zero-extend short
|
||||
def tUXTH : T1I<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"uxth $dst, $src",
|
||||
[(set tGPR:$dst, (and tGPR:$src, 0xFFFF))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
def tUXTH : T1pI<(outs tGPR:$dst), (ins tGPR:$src),
|
||||
"uxth", " $dst, $src",
|
||||
[(set tGPR:$dst, (and tGPR:$src, 0xFFFF))]>,
|
||||
Requires<[IsThumb1Only, HasV6]>;
|
||||
|
||||
|
||||
// Conditional move tMOVCCr - Used to implement the Thumb SELECT_CC DAG operation.
|
||||
// Expanded by the scheduler into a branch sequence.
|
||||
// FIXME: Add actual movcc in IT blocks for Thumb2.
|
||||
let usesCustomDAGSchedInserter = 1 in // Expanded by the scheduler.
|
||||
def tMOVCCr :
|
||||
PseudoInst<(outs tGPR:$dst), (ins tGPR:$false, tGPR:$true, pred:$cc),
|
||||
@ -553,19 +548,21 @@ let usesCustomDAGSchedInserter = 1 in // Expanded by the scheduler.
|
||||
|
||||
// tLEApcrel - Load a pc-relative address into a register without offending the
|
||||
// assembler.
|
||||
let Defs = [CPSR] in {
|
||||
def tLEApcrel : T1Ix2<(outs tGPR:$dst), (ins i32imm:$label),
|
||||
!strconcat(!strconcat(".set PCRELV${:uid}, ($label-(",
|
||||
"${:private}PCRELL${:uid}+4))\n"),
|
||||
!strconcat("\tmov $dst, #PCRELV${:uid}\n",
|
||||
!strconcat("\tmovs $dst, #PCRELV${:uid}\n",
|
||||
"${:private}PCRELL${:uid}:\n\tadd $dst, pc")),
|
||||
[]>;
|
||||
|
||||
def tLEApcrelJT : T1Ix2<(outs tGPR:$dst), (ins i32imm:$label, i32imm:$id),
|
||||
!strconcat(!strconcat(".set PCRELV${:uid}, (${label}_${id:no_hash}-(",
|
||||
"${:private}PCRELL${:uid}+4))\n"),
|
||||
!strconcat("\tmov $dst, #PCRELV${:uid}\n",
|
||||
!strconcat("\tmovs $dst, #PCRELV${:uid}\n",
|
||||
"${:private}PCRELL${:uid}:\n\tadd $dst, pc")),
|
||||
[]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TLS Instructions
|
||||
|
@ -1059,9 +1059,6 @@ let isCall = 1,
|
||||
// Control-Flow Instructions
|
||||
//
|
||||
|
||||
let isReturn = 1, isTerminator = 1 in
|
||||
def t2BX_RET : T2XI<(outs), (ins), "bx lr", [(ARMretflag)]>;
|
||||
|
||||
// FIXME: remove when we have a way to marking a MI with these properties.
|
||||
// FIXME: $dst1 should be a def. But the extra ops must be in the end of the
|
||||
// operand list.
|
||||
|
@ -1006,7 +1006,7 @@ bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
|
||||
|
||||
MachineBasicBlock::iterator MBBI = prior(MBB.end());
|
||||
if (MBBI != MBB.begin() &&
|
||||
(MBBI->getOpcode() == ARM::BX_RET || MBBI->getOpcode() == ARM::t2BX_RET)){
|
||||
(MBBI->getOpcode() == ARM::BX_RET || MBBI->getOpcode() == ARM::tBX_RET)) {
|
||||
MachineInstr *PrevMI = prior(MBBI);
|
||||
if (PrevMI->getOpcode() == ARM::LDM || PrevMI->getOpcode() == ARM::t2LDM) {
|
||||
MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1);
|
||||
|
@ -974,8 +974,8 @@ bool ARMAsmPrinter::doInitialization(Module &M) {
|
||||
bool Result = AsmPrinter::doInitialization(M);
|
||||
DW = getAnalysisIfAvailable<DwarfWriter>();
|
||||
|
||||
// Thumb-2 instructions are supported only in unified assembler syntax mode.
|
||||
if (Subtarget->hasThumb2())
|
||||
// Use unified assembler syntax mode for Thumb.
|
||||
if (Subtarget->isThumb())
|
||||
O << "\t.syntax unified\n";
|
||||
|
||||
// Emit ARM Build Attributes
|
||||
|
@ -238,3 +238,18 @@ to avoid extra work when we convert Thumb2 instructions to Thumb1 instructions.
|
||||
We need to make (some of the) Thumb1 instructions predicable. That will allow
|
||||
shrinking of predicated Thumb2 instructions. To allow this, we need to be able
|
||||
to toggle the 's' bit since they do not set CPSR when they are inside IT blocks.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Make use of hi register variants of cmp: tCMPhir / tCMPZhir.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Rather than generating ldrsb, sometimes it's better to select to ldrb + sxtb.
|
||||
The problem is ldrsb addressing mode [r, r] means the zero offset requires an
|
||||
extra move. e.g. ldr_ext.ll test3:
|
||||
movs r1, #0
|
||||
ldrsb r0, [r0, r1]
|
||||
=>
|
||||
ldrb r0, [r0, #0]
|
||||
sxtb r0, r0
|
||||
|
@ -22,17 +22,20 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static inline
|
||||
const MachineInstrBuilder &AddDefaultPred(const MachineInstrBuilder &MIB) {
|
||||
return MIB.addImm((int64_t)ARMCC::AL).addReg(0);
|
||||
}
|
||||
|
||||
Thumb1InstrInfo::Thumb1InstrInfo(const ARMSubtarget &STI)
|
||||
: ARMBaseInstrInfo(STI), RI(*this, STI) {
|
||||
}
|
||||
|
||||
unsigned Thumb1InstrInfo::
|
||||
getUnindexedOpcode(unsigned Opc) const {
|
||||
unsigned Thumb1InstrInfo::getUnindexedOpcode(unsigned Opc) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Thumb1InstrInfo::
|
||||
getOpcode(ARMII::Op Op) const {
|
||||
unsigned Thumb1InstrInfo::getOpcode(ARMII::Op Op) const {
|
||||
switch (Op) {
|
||||
case ARMII::ADDri: return ARM::tADDi8;
|
||||
case ARMII::ADDrs: return 0;
|
||||
@ -207,9 +210,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
assert(RC == ARM::tGPRRegisterClass && "Unknown regclass!");
|
||||
|
||||
if (RC == ARM::tGPRRegisterClass) {
|
||||
BuildMI(MBB, I, DL, get(ARM::tSpill))
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addFrameIndex(FI).addImm(0);
|
||||
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::tSpill))
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addFrameIndex(FI).addImm(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,6 +233,7 @@ void Thumb1InstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
|
||||
BuildMI(MF, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill));
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i)
|
||||
MIB.addOperand(Addr[i]);
|
||||
AddDefaultPred(MIB);
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
@ -244,8 +248,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
assert(RC == ARM::tGPRRegisterClass && "Unknown regclass!");
|
||||
|
||||
if (RC == ARM::tGPRRegisterClass) {
|
||||
BuildMI(MBB, I, DL, get(ARM::tRestore), DestReg)
|
||||
.addFrameIndex(FI).addImm(0);
|
||||
AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::tRestore), DestReg)
|
||||
.addFrameIndex(FI).addImm(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +268,7 @@ loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
|
||||
MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
|
||||
for (unsigned i = 0, e = Addr.size(); i != e; ++i)
|
||||
MIB.addOperand(Addr[i]);
|
||||
AddDefaultPred(MIB);
|
||||
NewMIs.push_back(MIB);
|
||||
return;
|
||||
}
|
||||
@ -339,18 +344,19 @@ foldMemoryOperandImpl(MachineFunction &MF, MachineInstr *MI,
|
||||
if (RI.isPhysicalRegister(SrcReg) && !isARMLowRegister(SrcReg))
|
||||
// tSpill cannot take a high register operand.
|
||||
break;
|
||||
NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tSpill))
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addFrameIndex(FI).addImm(0);
|
||||
NewMI = AddDefaultPred(BuildMI(MF, MI->getDebugLoc(), get(ARM::tSpill))
|
||||
.addReg(SrcReg, getKillRegState(isKill))
|
||||
.addFrameIndex(FI).addImm(0));
|
||||
} else { // move -> load
|
||||
unsigned DstReg = MI->getOperand(0).getReg();
|
||||
if (RI.isPhysicalRegister(DstReg) && !isARMLowRegister(DstReg))
|
||||
// tRestore cannot target a high register operand.
|
||||
break;
|
||||
bool isDead = MI->getOperand(0).isDead();
|
||||
NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tRestore))
|
||||
.addReg(DstReg, RegState::Define | getDeadRegState(isDead))
|
||||
.addFrameIndex(FI).addImm(0);
|
||||
NewMI = AddDefaultPred(BuildMI(MF, MI->getDebugLoc(), get(ARM::tRestore))
|
||||
.addReg(DstReg,
|
||||
RegState::Define | getDeadRegState(isDead))
|
||||
.addFrameIndex(FI).addImm(0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -45,6 +45,16 @@ Thumb1RegisterInfo::Thumb1RegisterInfo(const ARMBaseInstrInfo &tii,
|
||||
: ARMBaseRegisterInfo(tii, sti) {
|
||||
}
|
||||
|
||||
static inline
|
||||
const MachineInstrBuilder &AddDefaultPred(const MachineInstrBuilder &MIB) {
|
||||
return MIB.addImm((int64_t)ARMCC::AL).addReg(0);
|
||||
}
|
||||
|
||||
static inline
|
||||
const MachineInstrBuilder &AddDefaultCC(const MachineInstrBuilder &MIB) {
|
||||
return MIB.addReg(ARM::CPSR);
|
||||
}
|
||||
|
||||
/// emitLoadConstPool - Emits a load from constpool to materialize the
|
||||
/// specified immediate.
|
||||
void Thumb1RegisterInfo::emitLoadConstPool(MachineBasicBlock &MBB,
|
||||
@ -59,7 +69,7 @@ void Thumb1RegisterInfo::emitLoadConstPool(MachineBasicBlock &MBB,
|
||||
unsigned Idx = ConstantPool->getConstantPoolIndex(C, 4);
|
||||
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tLDRcp), DestReg)
|
||||
.addConstantPoolIndex(Idx);
|
||||
.addConstantPoolIndex(Idx).addImm(Pred).addReg(PredReg);
|
||||
}
|
||||
|
||||
const TargetRegisterClass*
|
||||
@ -95,6 +105,7 @@ bool Thumb1RegisterInfo::hasReservedCallFrame(MachineFunction &MF) const {
|
||||
return !MF.getFrameInfo()->hasVarSizedObjects();
|
||||
}
|
||||
|
||||
|
||||
/// emitThumbRegPlusImmInReg - Emits a series of instructions to materialize
|
||||
/// a destreg = basereg + immediate in Thumb code. Materialize the immediate
|
||||
/// in a register using mov / mvn sequences or load the immediate from a
|
||||
@ -127,22 +138,28 @@ void emitThumbRegPlusImmInReg(MachineBasicBlock &MBB,
|
||||
}
|
||||
|
||||
if (NumBytes <= 255 && NumBytes >= 0)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8), LdReg).addImm(NumBytes);
|
||||
AddDefaultCC(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8), LdReg))
|
||||
.addImm(NumBytes);
|
||||
else if (NumBytes < 0 && NumBytes >= -255) {
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8), LdReg).addImm(NumBytes);
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tNEG), LdReg)
|
||||
AddDefaultCC(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8), LdReg))
|
||||
.addImm(NumBytes);
|
||||
AddDefaultCC(BuildMI(MBB, MBBI, dl, TII.get(ARM::tRSB), LdReg))
|
||||
.addReg(LdReg, RegState::Kill);
|
||||
} else
|
||||
MRI.emitLoadConstPool(MBB, MBBI, dl, LdReg, NumBytes);
|
||||
|
||||
// Emit add / sub.
|
||||
int Opc = (isSub) ? ARM::tSUBrr : (isHigh ? ARM::tADDhirr : ARM::tADDrr);
|
||||
const MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl,
|
||||
TII.get(Opc), DestReg);
|
||||
MachineInstrBuilder MIB =
|
||||
BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg);
|
||||
if (Opc != ARM::tADDhirr)
|
||||
MIB = AddDefaultCC(MIB);
|
||||
if (DestReg == ARM::SP || isSub)
|
||||
MIB.addReg(BaseReg).addReg(LdReg, RegState::Kill);
|
||||
else
|
||||
MIB.addReg(LdReg).addReg(BaseReg, RegState::Kill);
|
||||
AddDefaultPred(MIB);
|
||||
|
||||
if (DestReg == ARM::SP)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVhir2lor), ARM::R3)
|
||||
.addReg(ARM::R12, RegState::Kill);
|
||||
@ -191,6 +208,8 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
unsigned Scale = 1;
|
||||
int Opc = 0;
|
||||
int ExtraOpc = 0;
|
||||
bool NeedCC = false;
|
||||
bool NeedPred = false;
|
||||
|
||||
if (DestReg == BaseReg && BaseReg == ARM::SP) {
|
||||
assert(isMul4 && "Thumb sp inc / dec size must be multiple of 4!");
|
||||
@ -218,6 +237,7 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
DstNotEqBase = true;
|
||||
NumBits = 8;
|
||||
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
|
||||
NeedPred = NeedCC = true;
|
||||
isTwoAddr = true;
|
||||
}
|
||||
|
||||
@ -237,8 +257,10 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
unsigned Chunk = (1 << 3) - 1;
|
||||
unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
|
||||
Bytes -= ThisVal;
|
||||
BuildMI(MBB, MBBI, dl,TII.get(isSub ? ARM::tSUBi3 : ARM::tADDi3), DestReg)
|
||||
.addReg(BaseReg, RegState::Kill).addImm(ThisVal);
|
||||
const TargetInstrDesc &TID = TII.get(isSub ? ARM::tSUBi3 : ARM::tADDi3);
|
||||
const MachineInstrBuilder MIB =
|
||||
AddDefaultCC(BuildMI(MBB, MBBI, dl, TID, DestReg));
|
||||
AddDefaultPred(MIB.addReg(BaseReg, RegState::Kill).addImm(ThisVal));
|
||||
} else {
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), DestReg)
|
||||
.addReg(BaseReg, RegState::Kill);
|
||||
@ -252,13 +274,22 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
Bytes -= ThisVal;
|
||||
ThisVal /= Scale;
|
||||
// Build the new tADD / tSUB.
|
||||
if (isTwoAddr)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
|
||||
.addReg(DestReg).addImm(ThisVal);
|
||||
if (isTwoAddr) {
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg);
|
||||
if (NeedCC)
|
||||
MIB = AddDefaultCC(MIB);
|
||||
MIB .addReg(DestReg).addImm(ThisVal);
|
||||
if (NeedPred)
|
||||
MIB = AddDefaultPred(MIB);
|
||||
}
|
||||
else {
|
||||
bool isKill = BaseReg != ARM::SP;
|
||||
BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
|
||||
.addReg(BaseReg, getKillRegState(isKill)).addImm(ThisVal);
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg);
|
||||
if (NeedCC)
|
||||
MIB = AddDefaultCC(MIB);
|
||||
MIB.addReg(BaseReg, getKillRegState(isKill)).addImm(ThisVal);
|
||||
if (NeedPred)
|
||||
MIB = AddDefaultPred(MIB);
|
||||
BaseReg = DestReg;
|
||||
|
||||
if (Opc == ARM::tADDrSPi) {
|
||||
@ -269,15 +300,17 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
Scale = 1;
|
||||
Chunk = ((1 << NumBits) - 1) * Scale;
|
||||
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
|
||||
isTwoAddr = true;
|
||||
NeedPred = NeedCC = isTwoAddr = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraOpc)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ExtraOpc), DestReg)
|
||||
.addReg(DestReg, RegState::Kill)
|
||||
.addImm(((unsigned)NumBytes) & 3);
|
||||
if (ExtraOpc) {
|
||||
const TargetInstrDesc &TID = TII.get(ExtraOpc);
|
||||
AddDefaultPred(AddDefaultCC(BuildMI(MBB, MBBI, dl, TID, DestReg))
|
||||
.addReg(DestReg, RegState::Kill)
|
||||
.addImm(((unsigned)NumBytes) & 3));
|
||||
}
|
||||
}
|
||||
|
||||
static void emitSPUpdate(MachineBasicBlock &MBB,
|
||||
@ -333,12 +366,22 @@ static void emitThumbConstant(MachineBasicBlock &MBB,
|
||||
int Chunk = (1 << 8) - 1;
|
||||
int ThisVal = (Imm > Chunk) ? Chunk : Imm;
|
||||
Imm -= ThisVal;
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8), DestReg).addImm(ThisVal);
|
||||
AddDefaultPred(AddDefaultCC(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVi8),
|
||||
DestReg))
|
||||
.addImm(ThisVal));
|
||||
if (Imm > 0)
|
||||
emitThumbRegPlusImmediate(MBB, MBBI, DestReg, DestReg, Imm, TII, MRI, dl);
|
||||
if (isSub)
|
||||
BuildMI(MBB, MBBI, dl, TII.get(ARM::tNEG), DestReg)
|
||||
.addReg(DestReg, RegState::Kill);
|
||||
if (isSub) {
|
||||
const TargetInstrDesc &TID = TII.get(ARM::tRSB);
|
||||
AddDefaultPred(AddDefaultCC(BuildMI(MBB, MBBI, dl, TID, DestReg))
|
||||
.addReg(DestReg, RegState::Kill));
|
||||
}
|
||||
}
|
||||
|
||||
static void removeOperands(MachineInstr &MI, unsigned i) {
|
||||
unsigned Op = i;
|
||||
for (unsigned e = MI.getNumOperands(); i != e; ++i)
|
||||
MI.RemoveOperand(Op);
|
||||
}
|
||||
|
||||
void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
@ -384,7 +427,7 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
unsigned Scale = 1;
|
||||
if (FrameReg != ARM::SP) {
|
||||
Opcode = ARM::tADDi3;
|
||||
MI.setDesc(TII.get(ARM::tADDi3));
|
||||
MI.setDesc(TII.get(Opcode));
|
||||
NumBits = 3;
|
||||
} else {
|
||||
NumBits = 8;
|
||||
@ -405,8 +448,14 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
unsigned Mask = (1 << NumBits) - 1;
|
||||
if (((Offset / Scale) & ~Mask) == 0) {
|
||||
// Replace the FrameIndex with sp / fp
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Offset / Scale);
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, i);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultCC(MIB).addReg(FrameReg).addImm(Offset/Scale));
|
||||
} else {
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Offset / Scale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -426,8 +475,14 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
// Translate r0 = add sp, imm to
|
||||
// r0 = add sp, 255*4
|
||||
// r0 = add r0, (imm - 255*4)
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Mask);
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, i);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultCC(MIB).addReg(FrameReg).addImm(Mask));
|
||||
} else {
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Mask);
|
||||
}
|
||||
Offset = (Offset - Mask * Scale);
|
||||
MachineBasicBlock::iterator NII = next(II);
|
||||
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
|
||||
@ -498,6 +553,11 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
// SP+LargeImm.
|
||||
assert(Offset && "This code isn't needed if offset already handled!");
|
||||
|
||||
// Remove predicate first.
|
||||
int PIdx = MI.findFirstPredOperandIdx();
|
||||
if (PIdx != -1)
|
||||
removeOperands(MI, PIdx);
|
||||
|
||||
if (Desc.mayLoad()) {
|
||||
// Use the destination register to materialize sp + offset.
|
||||
unsigned TmpReg = MI.getOperand(0).getReg();
|
||||
@ -510,9 +570,11 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
emitLoadConstPool(MBB, II, dl, TmpReg, Offset);
|
||||
UseRR = true;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, Offset, TII,
|
||||
*this, dl);
|
||||
}
|
||||
|
||||
MI.setDesc(TII.get(ARM::tLDR));
|
||||
MI.getOperand(i).ChangeToRegister(TmpReg, false, false, true);
|
||||
if (UseRR)
|
||||
@ -567,6 +629,12 @@ void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
.addReg(ARM::R12, RegState::Kill);
|
||||
} else
|
||||
assert(false && "Unexpected opcode!");
|
||||
|
||||
// Add predicate back if it's needed.
|
||||
if (MI.getDesc().isPredicable()) {
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(MIB);
|
||||
}
|
||||
}
|
||||
|
||||
void Thumb1RegisterInfo::emitPrologue(MachineFunction &MF) const {
|
||||
|
@ -26,14 +26,12 @@ Thumb2InstrInfo::Thumb2InstrInfo(const ARMSubtarget &STI)
|
||||
: ARMBaseInstrInfo(STI), RI(*this, STI) {
|
||||
}
|
||||
|
||||
unsigned Thumb2InstrInfo::
|
||||
getUnindexedOpcode(unsigned Opc) const {
|
||||
unsigned Thumb2InstrInfo::getUnindexedOpcode(unsigned Opc) const {
|
||||
// FIXME
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Thumb2InstrInfo::
|
||||
getOpcode(ARMII::Op Op) const {
|
||||
unsigned Thumb2InstrInfo::getOpcode(ARMII::Op Op) const {
|
||||
switch (Op) {
|
||||
case ARMII::ADDri: return ARM::t2ADDri;
|
||||
case ARMII::ADDrs: return ARM::t2ADDrs;
|
||||
@ -43,7 +41,7 @@ getOpcode(ARMII::Op Op) const {
|
||||
case ARMII::BR_JTr: return ARM::t2BR_JTr;
|
||||
case ARMII::BR_JTm: return ARM::t2BR_JTm;
|
||||
case ARMII::BR_JTadd: return ARM::t2BR_JTadd;
|
||||
case ARMII::BX_RET: return ARM::t2BX_RET;
|
||||
case ARMII::BX_RET: return ARM::tBX_RET;
|
||||
case ARMII::FCPYS: return ARM::FCPYS;
|
||||
case ARMII::FCPYD: return ARM::FCPYD;
|
||||
case ARMII::FLDD: return ARM::FLDD;
|
||||
@ -71,7 +69,6 @@ Thumb2InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
|
||||
|
||||
// FIXME
|
||||
switch (MBB.back().getOpcode()) {
|
||||
case ARM::t2BX_RET:
|
||||
case ARM::t2LDM_RET:
|
||||
case ARM::t2B: // Uncond branch.
|
||||
case ARM::t2BR_JTr: // Jumptable branch.
|
||||
|
@ -1,7 +1,9 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb | grep {lsr r0, r0, #31}
|
||||
; RUN: llvm-as < %s | llc -march=thumb | FileCheck %s
|
||||
|
||||
define i32 @test1(i32 %X) {
|
||||
entry:
|
||||
; CHECK: test1:
|
||||
; CHECK: lsrs r0, r0, #31
|
||||
icmp slt i32 %X, 0 ; <i1>:0 [#uses=1]
|
||||
zext i1 %0 to i32 ; <i32>:1 [#uses=1]
|
||||
ret i32 %1
|
||||
|
@ -1,6 +1,8 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb | grep cpy | count 2
|
||||
; RUN: llvm-as < %s | llc -march=thumb | FileCheck %s
|
||||
|
||||
define i32 @f1() {
|
||||
; CHECK: f1:
|
||||
; CHECK: ldr r0
|
||||
%buf = alloca [32 x i32], align 4
|
||||
%tmp = getelementptr [32 x i32]* %buf, i32 0, i32 0
|
||||
%tmp1 = load i32* %tmp
|
||||
@ -8,6 +10,9 @@ define i32 @f1() {
|
||||
}
|
||||
|
||||
define i32 @f2() {
|
||||
; CHECK: f2:
|
||||
; CHECK: mov r0
|
||||
; CHECK: ldrb
|
||||
%buf = alloca [32 x i8], align 4
|
||||
%tmp = getelementptr [32 x i8]* %buf, i32 0, i32 0
|
||||
%tmp1 = load i8* %tmp
|
||||
@ -16,6 +21,8 @@ define i32 @f2() {
|
||||
}
|
||||
|
||||
define i32 @f3() {
|
||||
; CHECK: f3:
|
||||
; CHECK: ldr r0
|
||||
%buf = alloca [32 x i32], align 4
|
||||
%tmp = getelementptr [32 x i32]* %buf, i32 0, i32 32
|
||||
%tmp1 = load i32* %tmp
|
||||
@ -23,6 +30,9 @@ define i32 @f3() {
|
||||
}
|
||||
|
||||
define i32 @f4() {
|
||||
; CHECK: f4:
|
||||
; CHECK: mov r0
|
||||
; CHECK: ldrb
|
||||
%buf = alloca [32 x i8], align 4
|
||||
%tmp = getelementptr [32 x i8]* %buf, i32 0, i32 2
|
||||
%tmp1 = load i8* %tmp
|
||||
|
Loading…
Reference in New Issue
Block a user