diff options
Diffstat (limited to 'lib/Target/ARM/ARMInstrThumb.td')
-rw-r--r-- | lib/Target/ARM/ARMInstrThumb.td | 513 |
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)))>; |