//===-- ARMInstrThumb.td - Thumb support for ARM -----------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file 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, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def imm_sr_XFORM: SDNodeXFormgetZExtValue(); return CurDAG->getTargetConstant((Imm == 32 ? 0 : Imm), MVT::i32); }]>; def ThumbSRImmAsmOperand: AsmOperandClass { let Name = "ImmThumbSR"; } def imm_sr : Operand, PatLeaf<(imm), [{ uint64_t Imm = N->getZExtValue(); return Imm > 0 && Imm <= 32; }], imm_sr_XFORM> { let PrintMethod = "printThumbSRImm"; let ParserMatchClass = ThumbSRImmAsmOperand; } def imm_comp_XFORM : SDNodeXFormgetTargetConstant(~((uint32_t)N->getZExtValue()), MVT::i32); }]>; def imm0_7_neg : PatLeaf<(i32 imm), [{ return (uint32_t)-N->getZExtValue() < 8; }], imm_neg_XFORM>; def imm0_255_comp : PatLeaf<(i32 imm), [{ return ~((uint32_t)N->getZExtValue()) < 256; }]>; def imm8_255 : ImmLeaf= 8 && Imm < 256; }]>; def imm8_255_neg : PatLeaf<(i32 imm), [{ unsigned Val = -N->getZExtValue(); 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->getZExtValue()); }]>; def thumb_immshifted_val : SDNodeXFormgetZExtValue()); return CurDAG->getTargetConstant(V, MVT::i32); }]>; def thumb_immshifted_shamt : SDNodeXFormgetZExtValue()); return CurDAG->getTargetConstant(V, MVT::i32); }]>; // ADR instruction labels. def t_adrlabel : Operand { let EncoderMethod = "getThumbAdrLabelOpValue"; } // Scaled 4 immediate. def t_imm0_1020s4_asmoperand: AsmOperandClass { let Name = "Imm0_1020s4"; } def t_imm0_1020s4 : Operand { let PrintMethod = "printThumbS4ImmOperand"; let ParserMatchClass = t_imm0_1020s4_asmoperand; let OperandType = "OPERAND_IMMEDIATE"; } def t_imm0_508s4_asmoperand: AsmOperandClass { let Name = "Imm0_508s4"; } def t_imm0_508s4 : Operand { let PrintMethod = "printThumbS4ImmOperand"; let ParserMatchClass = t_imm0_508s4_asmoperand; let OperandType = "OPERAND_IMMEDIATE"; } // Alias use only, so no printer is necessary. def t_imm0_508s4_neg_asmoperand: AsmOperandClass { let Name = "Imm0_508s4Neg"; } def t_imm0_508s4_neg : Operand { let ParserMatchClass = t_imm0_508s4_neg_asmoperand; let OperandType = "OPERAND_IMMEDIATE"; } // Define Thumb specific addressing modes. let OperandType = "OPERAND_PCREL" in { def t_brtarget : Operand { let EncoderMethod = "getThumbBRTargetOpValue"; let DecoderMethod = "DecodeThumbBROperand"; } def t_bcctarget : Operand { let EncoderMethod = "getThumbBCCTargetOpValue"; let DecoderMethod = "DecodeThumbBCCTargetOperand"; } def t_cbtarget : Operand { let EncoderMethod = "getThumbCBTargetOpValue"; let DecoderMethod = "DecodeThumbCmpBROperand"; } def t_bltarget : Operand { let EncoderMethod = "getThumbBLTargetOpValue"; let DecoderMethod = "DecodeThumbBLTargetOperand"; } def t_blxtarget : Operand { let EncoderMethod = "getThumbBLXTargetOpValue"; let DecoderMethod = "DecodeThumbBLXOffset"; } } // t_addrmode_rr := reg + reg // def t_addrmode_rr_asm_operand : AsmOperandClass { let Name = "MemThumbRR"; } def t_addrmode_rr : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; let DecoderMethod = "DecodeThumbAddrModeRR"; let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); } // t_addrmode_rrs := reg + reg // // We use separate scaled versions because the Select* functions need // to explicitly check for a matching constant and return false here so that // the reg+imm forms will match instead. This is a horrible way to do that, // as it forces tight coupling between the methods, but it's how selectiondag // currently works. def t_addrmode_rrs1 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; let DecoderMethod = "DecodeThumbAddrModeRR"; let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); } def t_addrmode_rrs2 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let DecoderMethod = "DecodeThumbAddrModeRR"; let PrintMethod = "printThumbAddrModeRROperand"; let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); } def t_addrmode_rrs4 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let DecoderMethod = "DecodeThumbAddrModeRR"; let PrintMethod = "printThumbAddrModeRROperand"; let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); } // t_addrmode_is4 := reg + imm5 * 4 // def t_addrmode_is4_asm_operand : AsmOperandClass { let Name = "MemThumbRIs4"; } def t_addrmode_is4 : Operand, ComplexPattern { let EncoderMethod = "getAddrModeISOpValue"; let DecoderMethod = "DecodeThumbAddrModeIS"; let PrintMethod = "printThumbAddrModeImm5S4Operand"; let ParserMatchClass = t_addrmode_is4_asm_operand; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); } // t_addrmode_is2 := reg + imm5 * 2 // def t_addrmode_is2_asm_operand : AsmOperandClass { let Name = "MemThumbRIs2"; } def t_addrmode_is2 : Operand, ComplexPattern { let EncoderMethod = "getAddrModeISOpValue"; let DecoderMethod = "DecodeThumbAddrModeIS"; let PrintMethod = "printThumbAddrModeImm5S2Operand"; let ParserMatchClass = t_addrmode_is2_asm_operand; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); } // t_addrmode_is1 := reg + imm5 // def t_addrmode_is1_asm_operand : AsmOperandClass { let Name = "MemThumbRIs1"; } def t_addrmode_is1 : Operand, ComplexPattern { let EncoderMethod = "getAddrModeISOpValue"; let DecoderMethod = "DecodeThumbAddrModeIS"; let PrintMethod = "printThumbAddrModeImm5S1Operand"; let ParserMatchClass = t_addrmode_is1_asm_operand; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); } // t_addrmode_sp := sp + imm8 * 4 // // FIXME: This really shouldn't have an explicit SP operand at all. It should // be implicit, just like in the instruction encoding itself. def t_addrmode_sp_asm_operand : AsmOperandClass { let Name = "MemThumbSPI"; } def t_addrmode_sp : Operand, ComplexPattern { let EncoderMethod = "getAddrModeThumbSPOpValue"; let DecoderMethod = "DecodeThumbAddrModeSP"; let PrintMethod = "printThumbAddrModeSPOperand"; let ParserMatchClass = t_addrmode_sp_asm_operand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t_addrmode_pc :=