aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/ARM/ARMInstrThumb.td
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/ARM/ARMInstrThumb.td')
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td513
1 files changed, 513 insertions, 0 deletions
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
new file mode 100644
index 0000000000..58cef04188
--- /dev/null
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -0,0 +1,513 @@
+//===- ARMInstrThumb.td - Thumb support for ARM ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the Thumb instruction set.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Thumb specific DAG Nodes.
+//
+
+def ARMtcall : SDNode<"ARMISD::tCALL", SDT_ARMcall,
+ [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
+
+// TI - Thumb instruction.
+
+// ThumbPat - Same as Pat<>, but requires that the compiler be in Thumb mode.
+class ThumbPat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb];
+}
+
+class ThumbV5Pat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb, HasV5T];
+}
+
+class ThumbI<dag ops, AddrMode am, SizeFlagVal sz,
+ string asm, string cstr, list<dag> pattern>
+ // FIXME: Set all opcodes to 0 for now.
+ : InstARM<0, am, sz, IndexModeNone, ops, asm, cstr> {
+ let Pattern = pattern;
+ list<Predicate> Predicates = [IsThumb];
+}
+
+class TI<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeNone, Size2Bytes, asm, "", pattern>;
+class TI1<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeT1, Size2Bytes, asm, "", pattern>;
+class TI2<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeT2, Size2Bytes, asm, "", pattern>;
+class TI4<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeT4, Size2Bytes, asm, "", pattern>;
+class TIs<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeTs, Size2Bytes, asm, "", pattern>;
+
+// Two-address instructions
+class TIt<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeNone, Size2Bytes, asm, "$lhs = $dst", pattern>;
+
+// BL, BLX(1) are translated by assembler into two instructions
+class TIx2<dag ops, string asm, list<dag> pattern>
+ : ThumbI<ops, AddrModeNone, Size4Bytes, asm, "", pattern>;
+
+def imm_neg_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(-(int)N->getValue(), MVT::i32);
+}]>;
+def imm_comp_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(~((uint32_t)N->getValue()), MVT::i32);
+}]>;
+
+
+/// imm0_7 predicate - True if the 32-bit immediate is in the range [0,7].
+def imm0_7 : PatLeaf<(i32 imm), [{
+ return (uint32_t)N->getValue() < 8;
+}]>;
+def imm0_7_neg : PatLeaf<(i32 imm), [{
+ return (uint32_t)-N->getValue() < 8;
+}], imm_neg_XFORM>;
+
+def imm0_255 : PatLeaf<(i32 imm), [{
+ return (uint32_t)N->getValue() < 256;
+}]>;
+def imm0_255_comp : PatLeaf<(i32 imm), [{
+ return ~((uint32_t)N->getValue()) < 256;
+}]>;
+
+def imm8_255 : PatLeaf<(i32 imm), [{
+ return (uint32_t)N->getValue() >= 8 && (uint32_t)N->getValue() < 256;
+}]>;
+def imm8_255_neg : PatLeaf<(i32 imm), [{
+ unsigned Val = -N->getValue();
+ return Val >= 8 && Val < 256;
+}], imm_neg_XFORM>;
+
+// Break imm's up into two pieces: an immediate + a left shift.
+// This uses thumb_immshifted to match and thumb_immshifted_val and
+// thumb_immshifted_shamt to get the val/shift pieces.
+def thumb_immshifted : PatLeaf<(imm), [{
+ return ARM_AM::isThumbImmShiftedVal((unsigned)N->getValue());
+}]>;
+
+def thumb_immshifted_val : SDNodeXForm<imm, [{
+ unsigned V = ARM_AM::getThumbImmNonShiftedVal((unsigned)N->getValue());
+ return CurDAG->getTargetConstant(V, MVT::i32);
+}]>;
+
+def thumb_immshifted_shamt : SDNodeXForm<imm, [{
+ unsigned V = ARM_AM::getThumbImmValShift((unsigned)N->getValue());
+ return CurDAG->getTargetConstant(V, MVT::i32);
+}]>;
+
+// Define Thumb specific addressing modes.
+
+// t_addrmode_rr := reg + reg
+//
+def t_addrmode_rr : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectThumbAddrModeRR", []> {
+ let PrintMethod = "printThumbAddrModeRROperand";
+ let MIOperandInfo = (ops GPR:$base, GPR:$offsreg);
+}
+
+// t_addrmode_ri5_{1|2|4} := reg + imm5 * {1|2|4}
+//
+def t_addrmode_ri5_1 : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectThumbAddrModeRI5_1", []> {
+ let PrintMethod = "printThumbAddrModeRI5_1Operand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+def t_addrmode_ri5_2 : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectThumbAddrModeRI5_2", []> {
+ let PrintMethod = "printThumbAddrModeRI5_2Operand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+def t_addrmode_ri5_4 : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectThumbAddrModeRI5_4", []> {
+ let PrintMethod = "printThumbAddrModeRI5_4Operand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+
+// t_addrmode_sp := sp + imm8 * 4
+//
+def t_addrmode_sp : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectThumbAddrModeSP", []> {
+ let PrintMethod = "printThumbAddrModeSPOperand";
+ let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
+}
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instructions.
+//
+
+def tPICADD : TIt<(ops GPR:$dst, GPR:$lhs, pclabel:$cp),
+ "\n$cp:\n\tadd $dst, pc",
+ [(set GPR:$dst, (ARMpic_add GPR:$lhs, imm:$cp))]>;
+
+//===----------------------------------------------------------------------===//
+// Control Flow Instructions.
+//
+
+let isReturn = 1, isTerminator = 1 in
+ def tBX_RET : TI<(ops), "bx lr", [(ARMretflag)]>;
+
+// FIXME: remove when we have a way to marking a MI with these properties.
+let isLoad = 1, isReturn = 1, isTerminator = 1 in
+def tPOP_RET : TI<(ops reglist:$dst1, variable_ops),
+ "pop $dst1", []>;
+
+let isCall = 1, noResults = 1,
+ Defs = [R0, R1, R2, R3, LR,
+ D0, D1, D2, D3, D4, D5, D6, D7] in {
+ def tBL : TIx2<(ops i32imm:$func, variable_ops),
+ "bl ${func:call}",
+ [(ARMtcall tglobaladdr:$func)]>;
+ // ARMv5T and above
+ def tBLXi : TIx2<(ops i32imm:$func, variable_ops),
+ "blx ${func:call}",
+ [(ARMcall tglobaladdr:$func)]>, Requires<[HasV5T]>;
+ def tBLXr : TI<(ops GPR:$dst, variable_ops),
+ "blx $dst",
+ [(ARMtcall GPR:$dst)]>, Requires<[HasV5T]>;
+ // ARMv4T
+ def tBX : TIx2<(ops GPR:$dst, variable_ops),
+ "cpy lr, pc\n\tbx $dst",
+ [(ARMcall_nolink GPR:$dst)]>;
+}
+
+let isBranch = 1, isTerminator = 1, isBarrier = 1 in
+ def tB : TI<(ops brtarget:$dst), "b $dst", [(br bb:$dst)]>;
+
+let isBranch = 1, isTerminator = 1, noResults = 1, isBarrier = 1 in
+ def tBcc : TI<(ops brtarget:$dst, CCOp:$cc), "b$cc $dst",
+ [(ARMbrcond bb:$dst, imm:$cc)]>;
+
+//===----------------------------------------------------------------------===//
+// Load Store Instructions.
+//
+
+let isLoad = 1 in {
+def tLDRri : TI4<(ops GPR:$dst, t_addrmode_ri5_4:$addr),
+ "ldr $dst, $addr",
+ [(set GPR:$dst, (load t_addrmode_ri5_4:$addr))]>;
+
+def tLDRrr : TI<(ops GPR:$dst, t_addrmode_rr:$addr),
+ "ldr $dst, $addr",
+ [(set GPR:$dst, (load t_addrmode_rr:$addr))]>;
+// def tLDRpci
+def tLDRspi : TIs<(ops GPR:$dst, t_addrmode_sp:$addr),
+ "ldr $dst, $addr",
+ [(set GPR:$dst, (load t_addrmode_sp:$addr))]>;
+
+def tLDRBri : TI1<(ops GPR:$dst, t_addrmode_ri5_1:$addr),
+ "ldrb $dst, $addr",
+ [(set GPR:$dst, (zextloadi8 t_addrmode_ri5_1:$addr))]>;
+
+def tLDRBrr : TI1<(ops GPR:$dst, t_addrmode_rr:$addr),
+ "ldrb $dst, $addr",
+ [(set GPR:$dst, (zextloadi8 t_addrmode_rr:$addr))]>;
+
+def tLDRHri : TI2<(ops GPR:$dst, t_addrmode_ri5_2:$addr),
+ "ldrh $dst, $addr",
+ [(set GPR:$dst, (zextloadi16 t_addrmode_ri5_2:$addr))]>;
+
+def tLDRHrr : TI2<(ops GPR:$dst, t_addrmode_rr:$addr),
+ "ldrh $dst, $addr",
+ [(set GPR:$dst, (zextloadi16 t_addrmode_rr:$addr))]>;
+
+def tLDRSBrr : TI1<(ops GPR:$dst, t_addrmode_rr:$addr),
+ "ldrsb $dst, $addr",
+ [(set GPR:$dst, (sextloadi8 t_addrmode_rr:$addr))]>;
+
+def tLDRSHrr : TI2<(ops GPR:$dst, t_addrmode_rr:$addr),
+ "ldrsh $dst, $addr",
+ [(set GPR:$dst, (sextloadi16 t_addrmode_rr:$addr))]>;
+} // isLoad
+
+let isStore = 1 in {
+def tSTRri : TI4<(ops GPR:$src, t_addrmode_ri5_4:$addr),
+ "str $src, $addr",
+ [(store GPR:$src, t_addrmode_ri5_4:$addr)]>;
+
+def tSTRrr : TI<(ops GPR:$src, t_addrmode_rr:$addr),
+ "str $src, $addr",
+ [(store GPR:$src, t_addrmode_rr:$addr)]>;
+
+def tSTRspi : TIs<(ops GPR:$src, t_addrmode_sp:$addr),
+ "str $src, $addr",
+ [(store GPR:$src, t_addrmode_sp:$addr)]>;
+
+def tSTRBri : TI1<(ops GPR:$src, t_addrmode_ri5_1:$addr),
+ "strb $src, $addr",
+ [(truncstorei8 GPR:$src, t_addrmode_ri5_1:$addr)]>;
+
+def tSTRBrr : TI1<(ops GPR:$src, t_addrmode_rr:$addr),
+ "strb $src, $addr",
+ [(truncstorei8 GPR:$src, t_addrmode_rr:$addr)]>;
+
+def tSTRHri : TI2<(ops GPR:$src, t_addrmode_ri5_2:$addr),
+ "strh $src, $addr",
+ [(truncstorei16 GPR:$src, t_addrmode_ri5_1:$addr)]>;
+
+def tSTRHrr : TI2<(ops GPR:$src, t_addrmode_rr:$addr),
+ "strh $src, $addr",
+ [(truncstorei16 GPR:$src, t_addrmode_rr:$addr)]>;
+}
+
+//===----------------------------------------------------------------------===//
+// Load / store multiple Instructions.
+//
+
+// TODO: A7-44: LDMIA - load multiple
+
+let isLoad = 1 in
+def tPOP : TI<(ops reglist:$dst1, variable_ops),
+ "pop $dst1", []>;
+
+let isStore = 1 in
+def tPUSH : TI<(ops reglist:$src1, variable_ops),
+ "push $src1", []>;
+
+//===----------------------------------------------------------------------===//
+// Arithmetic Instructions.
+//
+
+def tADDi3 : TI<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "add $dst, $lhs, $rhs",
+ [(set GPR:$dst, (add GPR:$lhs, imm0_7:$rhs))]>;
+
+def tADDi8 : TIt<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "add $dst, $rhs",
+ [(set GPR:$dst, (add GPR:$lhs, imm8_255:$rhs))]>;
+
+def tADDrr : TI<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "add $dst, $lhs, $rhs",
+ [(set GPR:$dst, (add GPR:$lhs, GPR:$rhs))]>;
+
+def tADDhirr : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "add $dst, $rhs", []>;
+
+def tADDrPCi : TI<(ops GPR:$dst, i32imm:$rhs),
+ "add $dst, pc, $rhs * 4", []>;
+def tADDrSPi : TI<(ops GPR:$dst, GPR:$sp, i32imm:$rhs),
+ "add $dst, $sp, $rhs * 4", []>;
+def tADDspi : TI<(ops GPR:$sp, i32imm:$rhs),
+ "add $sp, $rhs * 4", []>;
+
+
+def tAND : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "and $dst, $rhs",
+ [(set GPR:$dst, (and GPR:$lhs, GPR:$rhs))]>;
+
+def tASRri : TI<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "asr $dst, $lhs, $rhs",
+ [(set GPR:$dst, (sra GPR:$lhs, imm:$rhs))]>;
+
+def tASRrr : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "asr $dst, $rhs",
+ [(set GPR:$dst, (sra GPR:$lhs, GPR:$rhs))]>;
+
+def tBIC : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "bic $dst, $rhs",
+ [(set GPR:$dst, (and GPR:$lhs, (not GPR:$rhs)))]>;
+
+
+def tCMN : TI<(ops GPR:$lhs, GPR:$rhs),
+ "cmn $lhs, $rhs",
+ [(ARMcmp GPR:$lhs, (ineg GPR:$rhs))]>;
+
+def tCMPi8 : TI<(ops GPR:$lhs, i32imm:$rhs),
+ "cmp $lhs, $rhs",
+ [(ARMcmp GPR:$lhs, imm0_255:$rhs)]>;
+
+def tCMPr : TI<(ops GPR:$lhs, GPR:$rhs),
+ "cmp $lhs, $rhs",
+ [(ARMcmp GPR:$lhs, GPR:$rhs)]>;
+
+// TODO: A7-37: CMP(3) - cmp hi regs
+
+def tEOR : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "eor $dst, $rhs",
+ [(set GPR:$dst, (xor GPR:$lhs, GPR:$rhs))]>;
+
+def tLSLri : TI<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "lsl $dst, $lhs, $rhs",
+ [(set GPR:$dst, (shl GPR:$lhs, imm:$rhs))]>;
+
+def tLSLrr : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "lsl $dst, $rhs",
+ [(set GPR:$dst, (shl GPR:$lhs, GPR:$rhs))]>;
+
+def tLSRri : TI<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "lsr $dst, $lhs, $rhs",
+ [(set GPR:$dst, (srl GPR:$lhs, imm:$rhs))]>;
+
+def tLSRrr : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "lsr $dst, $rhs",
+ [(set GPR:$dst, (srl GPR:$lhs, GPR:$rhs))]>;
+
+def tMOVri8 : TI<(ops GPR:$dst, i32imm:$src),
+ "mov $dst, $src",
+ [(set GPR:$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.
+def tMOVrr : TI<(ops GPR:$dst, GPR:$src),
+ "cpy $dst, $src", []>;
+
+def tMUL : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "mul $dst, $rhs",
+ [(set GPR:$dst, (mul GPR:$lhs, GPR:$rhs))]>;
+
+def tMVN : TI<(ops GPR:$dst, GPR:$src),
+ "mvn $dst, $src",
+ [(set GPR:$dst, (not GPR:$src))]>;
+
+def tNEG : TI<(ops GPR:$dst, GPR:$src),
+ "neg $dst, $src",
+ [(set GPR:$dst, (ineg GPR:$src))]>;
+
+def tORR : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "orr $dst, $rhs",
+ [(set GPR:$dst, (or GPR:$lhs, GPR:$rhs))]>;
+
+
+def tREV : TI<(ops GPR:$dst, GPR:$src),
+ "rev $dst, $src",
+ [(set GPR:$dst, (bswap GPR:$src))]>,
+ Requires<[IsThumb, HasV6]>;
+
+def tREV16 : TI<(ops GPR:$dst, GPR:$src),
+ "rev16 $dst, $src",
+ [(set GPR:$dst,
+ (or (and (srl GPR:$src, 8), 0xFF),
+ (or (and (shl GPR:$src, 8), 0xFF00),
+ (or (and (srl GPR:$src, 8), 0xFF0000),
+ (and (shl GPR:$src, 8), 0xFF000000)))))]>,
+ Requires<[IsThumb, HasV6]>;
+
+def tREVSH : TI<(ops GPR:$dst, GPR:$src),
+ "revsh $dst, $src",
+ [(set GPR:$dst,
+ (sext_inreg
+ (or (srl (and GPR:$src, 0xFFFF), 8),
+ (shl GPR:$src, 8)), i16))]>,
+ Requires<[IsThumb, HasV6]>;
+
+def tROR : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "ror $dst, $rhs",
+ [(set GPR:$dst, (rotr GPR:$lhs, GPR:$rhs))]>;
+
+def tSBC : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "sbc $dst, $rhs",
+ [(set GPR:$dst, (sube GPR:$lhs, GPR:$rhs))]>;
+
+// TODO: A7-96: STMIA - store multiple.
+
+def tSUBi3 : TI<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "sub $dst, $lhs, $rhs",
+ [(set GPR:$dst, (add GPR:$lhs, imm0_7_neg:$rhs))]>;
+
+def tSUBi8 : TIt<(ops GPR:$dst, GPR:$lhs, i32imm:$rhs),
+ "sub $dst, $rhs",
+ [(set GPR:$dst, (add GPR:$lhs, imm8_255_neg:$rhs))]>;
+
+def tSUBrr : TI<(ops GPR:$dst, GPR:$lhs, GPR:$rhs),
+ "sub $dst, $lhs, $rhs",
+ [(set GPR:$dst, (sub GPR:$lhs, GPR:$rhs))]>;
+
+def tSUBspi : TI<(ops GPR:$sp, i32imm:$rhs),
+ "sub $sp, $rhs * 4", []>;
+
+def tSXTB : TI<(ops GPR:$dst, GPR:$src),
+ "sxtb $dst, $src",
+ [(set GPR:$dst, (sext_inreg GPR:$src, i8))]>,
+ Requires<[IsThumb, HasV6]>;
+def tSXTH : TI<(ops GPR:$dst, GPR:$src),
+ "sxth $dst, $src",
+ [(set GPR:$dst, (sext_inreg GPR:$src, i16))]>,
+ Requires<[IsThumb, HasV6]>;
+
+// TODO: A7-122: TST - test.
+
+def tUXTB : TI<(ops GPR:$dst, GPR:$src),
+ "uxtb $dst, $src",
+ [(set GPR:$dst, (and GPR:$src, 0xFF))]>,
+ Requires<[IsThumb, HasV6]>;
+def tUXTH : TI<(ops GPR:$dst, GPR:$src),
+ "uxth $dst, $src",
+ [(set GPR:$dst, (and GPR:$src, 0xFFFF))]>,
+ Requires<[IsThumb, HasV6]>;
+
+
+// Conditional move tMOVCCr - Used to implement the Thumb SELECT_CC DAG operation.
+// Expanded by the scheduler into a branch sequence.
+let usesCustomDAGSchedInserter = 1 in // Expanded by the scheduler.
+ def tMOVCCr :
+ PseudoInst<(ops GPR:$dst, GPR:$false, GPR:$true, CCOp:$cc),
+ "@ tMOVCCr $cc",
+ [(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc))]>;
+
+// tLEApcrel - Load a pc-relative address into a register without offending the
+// assembler.
+def tLEApcrel : TI<(ops GPR:$dst, i32imm:$label),
+ !strconcat(!strconcat(".set PCRELV${:uid}, ($label-(",
+ "${:private}PCRELL${:uid}+4))\n"),
+ !strconcat("${:private}PCRELL${:uid}:\n\t",
+ "add $dst, pc, #PCRELV${:uid}")),
+ []>;
+
+def tLEApcrelCall : TI<(ops GPR:$dst, i32imm:$label),
+ !strconcat(!strconcat(".set PCRELV${:uid}, (${label:call}-(",
+ "${:private}PCRELL${:uid}+4))\n"),
+ !strconcat("${:private}PCRELL${:uid}:\n\t",
+ "add $dst, pc, #PCRELV${:uid}")),
+ []>;
+
+//===----------------------------------------------------------------------===//
+// Non-Instruction Patterns
+//
+
+// ConstantPool, GlobalAddress
+def : ThumbPat<(ARMWrapper tglobaladdr :$dst), (tLEApcrel tglobaladdr :$dst)>;
+def : ThumbPat<(ARMWrapper tconstpool :$dst), (tLEApcrel tconstpool :$dst)>;
+def : ThumbPat<(ARMWrapperCall tglobaladdr :$dst),
+ (tLEApcrelCall tglobaladdr :$dst)>;
+def : ThumbPat<(ARMWrapperCall texternalsym:$dst),
+ (tLEApcrelCall texternalsym:$dst)>;
+
+// Direct calls
+def : ThumbPat<(ARMtcall texternalsym:$func), (tBL texternalsym:$func)>;
+def : ThumbV5Pat<(ARMcall texternalsym:$func), (tBLXi texternalsym:$func)>;
+
+// Indirect calls to ARM routines
+def : ThumbV5Pat<(ARMcall GPR:$dst), (tBLXr GPR:$dst)>;
+
+// zextload i1 -> zextload i8
+def : ThumbPat<(zextloadi1 t_addrmode_ri5_1:$addr),
+ (tLDRBri t_addrmode_ri5_1:$addr)>;
+def : ThumbPat<(zextloadi1 t_addrmode_rr:$addr),
+ (tLDRBri t_addrmode_rr:$addr)>;
+
+// truncstore i1 -> truncstore i8
+def : ThumbPat<(truncstorei1 GPR:$src, t_addrmode_ri5_1:$dst),
+ (tSTRBri GPR:$src, t_addrmode_ri5_1:$dst)>;
+def : ThumbPat<(truncstorei1 GPR:$src, t_addrmode_rr:$dst),
+ (tSTRBrr GPR:$src, t_addrmode_rr:$dst)>;
+
+// Large immediate handling.
+
+// Two piece imms.
+def : ThumbPat<(i32 thumb_immshifted:$src),
+ (tLSLri (tMOVri8 (thumb_immshifted_val imm:$src)),
+ (thumb_immshifted_shamt imm:$src))>;
+
+def : ThumbPat<(i32 imm0_255_comp:$src),
+ (tMVN (tMOVri8 (imm_comp_XFORM imm:$src)))>;