summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td14
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td86
-rw-r--r--lib/Target/ARM/ARMInstrNEON.td45
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td28
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td13
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassembler.cpp2726
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassembler.h39
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp3894
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassemblerCore.h337
-rw-r--r--lib/Target/ARM/Disassembler/CMakeLists.txt1
-rw-r--r--lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h2461
-rw-r--r--lib/Target/ARM/Makefile2
-rw-r--r--test/MC/Disassembler/ARM/arm-tests.txt9
-rw-r--r--test/MC/Disassembler/ARM/invalid-BFI-arm.txt3
-rw-r--r--test/MC/Disassembler/ARM/invalid-Bcc-thumb.txt5
-rw-r--r--test/MC/Disassembler/ARM/invalid-CPS2p-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-CPS3p-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-DMB-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-DSB-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDC-form-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDRB_POST-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDRD_PRE-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDRT-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDR_POST-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-LSL-regform.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-MCR-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-MOVTi16-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-MOVr-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-MOVs-LSL-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-MOVs-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-MSRi-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-RFEorLDMIA-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-RSC-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-SBFX-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-SMLAD-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-SRS-arm.txt2
-rw-r--r--test/MC/Disassembler/ARM/invalid-SSAT-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-STMIA_UPD-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-STRBrs-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-SXTB-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-UMAAL-arm.txt4
-rw-r--r--test/MC/Disassembler/ARM/invalid-UQADD8-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-VLD1DUPq8_UPD-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-VLD3DUPd32_UPD-thumb.txt4
-rw-r--r--test/MC/Disassembler/ARM/invalid-VLDMSDB_UPD-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-VQADD-arm.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-VST2b32_UPD-arm.txt3
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2Bcc-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2LDRBT-thumb.txt4
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2LDREXD-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2LDRSHi12-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2LDRSHi8-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2STRD_PRE-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2STREXB-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2STREXD-thumb.txt4
-rw-r--r--test/MC/Disassembler/ARM/invalid-t2STR_POST-thumb.txt1
-rw-r--r--test/MC/Disassembler/ARM/neon-tests.txt4
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp7
59 files changed, 2477 insertions, 7261 deletions
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index 97e807ccc2..b8d7b99d5a 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -152,6 +152,7 @@ def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),
(ops (i32 14), (i32 zero_reg))> {
let PrintMethod = "printPredicateOperand";
let ParserMatchClass = CondCodeOperand;
+ let DecoderMethod = "DecodePredicateOperand";
}
// Conditional code result for instructions whose 's' bit is set, e.g. subs.
@@ -160,6 +161,7 @@ def cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 zero_reg))> {
let EncoderMethod = "getCCOutOpValue";
let PrintMethod = "printSBitModifierOperand";
let ParserMatchClass = CCOutOperand;
+ let DecoderMethod = "DecodeCCOutOperand";
}
// Same as cc_out except it defaults to setting CPSR.
@@ -167,6 +169,7 @@ def s_cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 CPSR))> {
let EncoderMethod = "getCCOutOpValue";
let PrintMethod = "printSBitModifierOperand";
let ParserMatchClass = CCOutOperand;
+ let DecoderMethod = "DecodeCCOutOperand";
}
// ARM special operands for disassembly only.
@@ -199,15 +202,19 @@ def msr_mask : Operand<i32> {
// 64 64 - <imm> is encoded in imm6<5:0>
def shr_imm8 : Operand<i32> {
let EncoderMethod = "getShiftRight8Imm";
+ let DecoderMethod = "DecodeShiftRight8Imm";
}
def shr_imm16 : Operand<i32> {
let EncoderMethod = "getShiftRight16Imm";
+ let DecoderMethod = "DecodeShiftRight16Imm";
}
def shr_imm32 : Operand<i32> {
let EncoderMethod = "getShiftRight32Imm";
+ let DecoderMethod = "DecodeShiftRight32Imm";
}
def shr_imm64 : Operand<i32> {
let EncoderMethod = "getShiftRight64Imm";
+ let DecoderMethod = "DecodeShiftRight64Imm";
}
//===----------------------------------------------------------------------===//
@@ -579,6 +586,8 @@ class AI3ld<bits<4> op, bit op20, dag oops, dag iops, Format f,
let Inst{11-8} = addr{7-4}; // imm7_4/zero
let Inst{7-4} = op;
let Inst{3-0} = addr{3-0}; // imm3_0/Rm
+
+ let DecoderMethod = "DecodeAddrMode3Instruction";
}
class AI3ldstidx<bits<4> op, bit op20, bit isLd, bit isPre, dag oops, dag iops,
@@ -1265,6 +1274,7 @@ class VFPI<dag oops, dag iops, AddrMode am, int sz,
let AsmString = !strconcat(opc, "${p}", asm);
let Pattern = pattern;
let PostEncoderMethod = "VFPThumb2PostEncoder";
+ let DecoderNamespace = "VFP";
list<Predicate> Predicates = [HasVFP2];
}
@@ -1280,6 +1290,7 @@ class VFPXI<dag oops, dag iops, AddrMode am, int sz,
let AsmString = asm;
let Pattern = pattern;
let PostEncoderMethod = "VFPThumb2PostEncoder";
+ let DecoderNamespace = "VFP";
list<Predicate> Predicates = [HasVFP2];
}
@@ -1597,6 +1608,7 @@ class NeonI<dag oops, dag iops, AddrMode am, IndexMode im, Format f,
let AsmString = !strconcat(opc, "${p}", ".", dt, "\t", asm);
let Pattern = pattern;
list<Predicate> Predicates = [HasNEON];
+ let DecoderNamespace = "NEON";
}
// Same as NeonI except it does not have a "data type" specifier.
@@ -1609,6 +1621,7 @@ class NeonXI<dag oops, dag iops, AddrMode am, IndexMode im, Format f,
let AsmString = !strconcat(opc, "${p}", "\t", asm);
let Pattern = pattern;
list<Predicate> Predicates = [HasNEON];
+ let DecoderNamespace = "NEON";
}
class NLdSt<bit op23, bits<2> op21_20, bits<4> op11_8, bits<4> op7_4,
@@ -1700,6 +1713,7 @@ class N1ModImm<bit op23, bits<3> op21_19, bits<4> op11_8, bit op7, bit op6,
let Inst{24} = SIMM{7};
let Inst{18-16} = SIMM{6-4};
let Inst{3-0} = SIMM{3-0};
+ let DecoderMethod = "DecodeNEONModImmInstruction";
}
// NEON 2 vector register format.
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index 28d6f9f329..819b8987d4 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -315,6 +315,7 @@ def fsub_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fsub node:$lhs, node:$rhs),[{
def brtarget : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValue";
let OperandType = "OPERAND_PCREL";
+ let DecoderMethod = "DecodeT2BROperand";
}
// FIXME: get rid of this one?
@@ -343,6 +344,7 @@ def bl_target : Operand<i32> {
// Encoded the same as branch targets.
let EncoderMethod = "getARMBranchTargetOpValue";
let OperandType = "OPERAND_PCREL";
+ let DecoderMethod = "DecodeBLTargetOperand";
}
@@ -352,6 +354,7 @@ def reglist : Operand<i32> {
let EncoderMethod = "getRegisterListOpValue";
let ParserMatchClass = RegListAsmOperand;
let PrintMethod = "printRegisterList";
+ let DecoderMethod = "DecodeRegListOperand";
}
def DPRRegListAsmOperand : AsmOperandClass { let Name = "DPRRegList"; }
@@ -359,6 +362,7 @@ def dpr_reglist : Operand<i32> {
let EncoderMethod = "getRegisterListOpValue";
let ParserMatchClass = DPRRegListAsmOperand;
let PrintMethod = "printRegisterList";
+ let DecoderMethod = "DecodeDPRRegListOperand";
}
def SPRRegListAsmOperand : AsmOperandClass { let Name = "SPRRegList"; }
@@ -366,6 +370,7 @@ def spr_reglist : Operand<i32> {
let EncoderMethod = "getRegisterListOpValue";
let ParserMatchClass = SPRRegListAsmOperand;
let PrintMethod = "printRegisterList";
+ let DecoderMethod = "DecodeSPRRegListOperand";
}
// An operand for the CONSTPOOL_ENTRY pseudo-instruction.
@@ -385,6 +390,7 @@ def adrlabel : Operand<i32> {
def neon_vcvt_imm32 : Operand<i32> {
let EncoderMethod = "getNEONVcvtImm32OpValue";
+ let DecoderMethod = "DecodeVCVTImmOperand";
}
// rot_imm: An integer that encodes a rotate amount. Must be 8, 16, or 24.
@@ -431,6 +437,7 @@ def so_reg_reg : Operand<i32>, // reg reg imm
[shl, srl, sra, rotr]> {
let EncoderMethod = "getSORegRegOpValue";
let PrintMethod = "printSORegRegOperand";
+ let DecoderMethod = "DecodeSORegRegOperand";
let ParserMatchClass = ShiftedRegAsmOperand;
let MIOperandInfo = (ops GPR, GPR, i32imm);
}
@@ -441,6 +448,7 @@ def so_reg_imm : Operand<i32>, // reg imm
[shl, srl, sra, rotr]> {
let EncoderMethod = "getSORegImmOpValue";
let PrintMethod = "printSORegImmOperand";
+ let DecoderMethod = "DecodeSORegImmOperand";
let ParserMatchClass = ShiftedImmAsmOperand;
let MIOperandInfo = (ops GPR, i32imm);
}
@@ -451,6 +459,7 @@ def shift_so_reg_reg : Operand<i32>, // reg reg imm
[shl,srl,sra,rotr]> {
let EncoderMethod = "getSORegRegOpValue";
let PrintMethod = "printSORegRegOperand";
+ let DecoderMethod = "DecodeSORegRegOperand";
let MIOperandInfo = (ops GPR, GPR, i32imm);
}
@@ -460,6 +469,7 @@ def shift_so_reg_imm : Operand<i32>, // reg reg imm
[shl,srl,sra,rotr]> {
let EncoderMethod = "getSORegImmOpValue";
let PrintMethod = "printSORegImmOperand";
+ let DecoderMethod = "DecodeSORegImmOperand";
let MIOperandInfo = (ops GPR, i32imm);
}
@@ -472,6 +482,7 @@ def so_imm : Operand<i32>, ImmLeaf<i32, [{
}]> {
let EncoderMethod = "getSOImmOpValue";
let ParserMatchClass = SOImmAsmOperand;
+ let DecoderMethod = "DecodeSOImmOperand";
}
// Break so_imm's up into two pieces. This handles immediates with up to 16
@@ -552,6 +563,7 @@ def bf_inv_mask_imm : Operand<i32>,
}] > {
let EncoderMethod = "getBitfieldInvertedMaskOpValue";
let PrintMethod = "printBitfieldInvMaskImmOperand";
+ let DecoderMethod = "DecodeBitfieldMaskOperand";
let ParserMatchClass = BitfieldAsmOperand;
}
@@ -599,6 +611,7 @@ def addrmode_imm12 : Operand<i32>,
let EncoderMethod = "getAddrModeImm12OpValue";
let PrintMethod = "printAddrModeImm12Operand";
+ let DecoderMethod = "DecodeAddrModeImm12Operand";
let ParserMatchClass = MemImm12OffsetAsmOperand;
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
@@ -610,6 +623,7 @@ def ldst_so_reg : Operand<i32>,
let EncoderMethod = "getLdStSORegOpValue";
// FIXME: Simplify the printer
let PrintMethod = "printAddrMode2Operand";
+ let DecoderMethod = "DecodeSORegMemOperand";
let ParserMatchClass = MemRegOffsetAsmOperand;
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$shift);
}
@@ -645,6 +659,7 @@ def PostIdxRegAsmOperand : AsmOperandClass {
}
def postidx_reg : Operand<i32> {
let EncoderMethod = "getPostIdxRegOpValue";
+ let DecoderMethod = "DecodePostIdxReg";
let PrintMethod = "printPostIdxRegOperand";
let ParserMatchClass = PostIdxRegAsmOperand;
let MIOperandInfo = (ops GPR, i32imm);
@@ -707,6 +722,7 @@ def am3offset : Operand<i32>,
ComplexPattern<i32, 2, "SelectAddrMode3Offset",
[], [SDNPWantRoot]> {
let EncoderMethod = "getAddrMode3OffsetOpValue";
+ let DecoderMethod = "DecodeAddrMode3Offset";
let PrintMethod = "printAddrMode3OffsetOperand";
let MIOperandInfo = (ops GPR, i32imm);
}
@@ -725,6 +741,7 @@ def addrmode5 : Operand<i32>,
ComplexPattern<i32, 2, "SelectAddrMode5", []> {
let PrintMethod = "printAddrMode5Operand";
let EncoderMethod = "getAddrMode5OpValue";
+ let DecoderMethod = "DecodeAddrMode5Operand";
let ParserMatchClass = AddrMode5AsmOperand;
let MIOperandInfo = (ops GPR:$base, i32imm);
}
@@ -736,6 +753,7 @@ def addrmode6 : Operand<i32>,
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm);
let EncoderMethod = "getAddrMode6AddressOpValue";
+ let DecoderMethod = "DecodeAddrMode6Operand";
}
def am6offset : Operand<i32>,
@@ -744,6 +762,7 @@ def am6offset : Operand<i32>,
let PrintMethod = "printAddrMode6OffsetOperand";
let MIOperandInfo = (ops GPR);
let EncoderMethod = "getAddrMode6OffsetOpValue";
+ let DecoderMethod = "DecodeGPRRegisterClass";
}
// Special version of addrmode6 to handle alignment encoding for VST1/VLD1
@@ -778,6 +797,7 @@ def MemNoOffsetAsmOperand : AsmOperandClass { let Name = "MemNoOffset"; }
def addr_offset_none : Operand<i32>,
ComplexPattern<i32, 1, "SelectAddrOffsetNone", []> {
let PrintMethod = "printAddrMode7Operand";
+ let DecoderMethod = "DecodeAddrMode7Operand";
let ParserMatchClass = MemNoOffsetAsmOperand;
let MIOperandInfo = (ops GPR:$base);
}
@@ -793,6 +813,7 @@ def CoprocNumAsmOperand : AsmOperandClass {
def p_imm : Operand<i32> {
let PrintMethod = "printPImmediate";
let ParserMatchClass = CoprocNumAsmOperand;
+ let DecoderMethod = "DecodeCoprocessor";
}
def CoprocRegAsmOperand : AsmOperandClass {
@@ -1654,6 +1675,7 @@ let isBranch = 1, isTerminator = 1 in {
[/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]> {
bits<24> target;
let Inst{23-0} = target;
+ let DecoderMethod = "DecodeBranchImmInstruction";
}
let isBarrier = 1 in {
@@ -1917,6 +1939,7 @@ multiclass AI2_ldridx<bit isByte, string opc, InstrItinClass itin> {
let Inst{23} = addr{12};
let Inst{19-16} = addr{17-14};
let Inst{11-0} = addr{11-0};
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
let AsmMatchConverter = "cvtLdWriteBackRegAddrMode2";
}
@@ -1933,6 +1956,8 @@ multiclass AI2_ldridx<bit isByte, string opc, InstrItinClass itin> {
let Inst{23} = offset{12};
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def _POST_IMM : AI2ldstidx<1, isByte, 0, (outs GPR:$Rt, GPR:$Rn_wb),
@@ -1948,7 +1973,10 @@ multiclass AI2_ldridx<bit isByte, string opc, InstrItinClass itin> {
let Inst{23} = offset{12};
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
+
}
let mayLoad = 1, neverHasSideEffects = 1 in {
@@ -2019,20 +2047,39 @@ def LDRD_POST: AI3ldstidx<0b1101, 0, 1, 0, (outs GPR:$Rt, GPR:$Rt2, GPR:$Rn_wb),
// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.
let mayLoad = 1, neverHasSideEffects = 1 in {
-def LDRT : AI2ldstidx<1, 0, 0, (outs GPR:$Rt, GPR:$base_wb),
- (ins addrmode2:$addr), IndexModePost, LdFrm, IIC_iLoad_ru,
+def LDRTr : AI2ldstidx<1, 0, 0, (outs GPR:$Rt, GPR:$base_wb),
+ (ins ldst_so_reg:$addr), IndexModePost, LdFrm, IIC_iLoad_ru,
+ "ldrt", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
+ // {17-14} Rn
+ // {13} 1 == Rm, 0 == imm12
+ // {12} isAdd
+ // {11-0} imm12/Rm
+ bits<18> addr;
+ let Inst{25} = 1;
+ let Inst{23} = addr{12};
+ let Inst{21} = 1; // overwrite
+ let Inst{19-16} = addr{17-14};
+ let Inst{11-5} = addr{11-5};
+ let Inst{4} = 0;
+ let Inst{3-0} = addr{3-0};
+ let AsmMatchConverter = "cvtLdWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
+}
+def LDRTi : AI2ldstidx<1, 0, 0, (outs GPR:$Rt, GPR:$base_wb),
+ (ins addrmode_imm12:$addr), IndexModePost, LdFrm, IIC_iLoad_ru,
"ldrt", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
// {17-14} Rn
// {13} 1 == Rm, 0 == imm12
// {12} isAdd
// {11-0} imm12/Rm
bits<18> addr;
- let Inst{25} = addr{13};
+ let Inst{25} = 0;
let Inst{23} = addr{12};
let Inst{21} = 1; // overwrite
let Inst{19-16} = addr{17-14};
let Inst{11-0} = addr{11-0};
let AsmMatchConverter = "cvtLdWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def LDRBT_POST_REG : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb),
@@ -2049,6 +2096,7 @@ def LDRBT_POST_REG : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb),
let Inst{21} = 1; // overwrite
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def LDRBT_POST_IMM : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb),
@@ -2065,6 +2113,7 @@ def LDRBT_POST_IMM : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb),
let Inst{21} = 1; // overwrite
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
multiclass AI3ldrT<bits<4> op, string opc> {
@@ -2151,6 +2200,8 @@ multiclass AI2_stridx<bit isByte, string opc, InstrItinClass itin> {
let Inst{23} = offset{12};
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def _POST_IMM : AI2ldstidx<0, isByte, 0, (outs GPR:$Rn_wb),
@@ -2166,6 +2217,8 @@ multiclass AI2_stridx<bit isByte, string opc, InstrItinClass itin> {
let Inst{23} = offset{12};
let Inst{19-16} = addr;
let Inst{11-0} = offset{11-0};
+
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
}
@@ -2287,6 +2340,7 @@ def STRTr : AI2stridxT<0, 0, (outs GPR:$Rn_wb),
let Inst{21} = 1; // overwrite
let Inst{4} = 0;
let AsmMatchConverter = "cvtStWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def STRTi : AI2stridxT<0, 0, (outs GPR:$Rn_wb),
@@ -2297,6 +2351,7 @@ def STRTi : AI2stridxT<0, 0, (outs GPR:$Rn_wb),
let Inst{25} = 0;
let Inst{21} = 1; // overwrite
let AsmMatchConverter = "cvtStWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
@@ -2309,6 +2364,7 @@ def STRBTr : AI2stridxT<1, 0, (outs GPR:$Rn_wb),
let Inst{21} = 1; // overwrite
let Inst{4} = 0;
let AsmMatchConverter = "cvtStWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
def STRBTi : AI2stridxT<1, 0, (outs GPR:$Rn_wb),
@@ -2319,6 +2375,7 @@ def STRBTi : AI2stridxT<1, 0, (outs GPR:$Rn_wb),
let Inst{25} = 0;
let Inst{21} = 1; // overwrite
let AsmMatchConverter = "cvtStWriteBackRegAddrMode2";
+ let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
multiclass AI3strT<bits<4> op, string opc> {
@@ -2373,6 +2430,8 @@ multiclass arm_ldst_mult<string asm, bit L_bit, Format f,
let Inst{24-23} = 0b01; // Increment After
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
+
+ let DecoderMethod = "DecodeMemMultipleWritebackInstruction";
}
def DA :
AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
@@ -2389,6 +2448,8 @@ multiclass arm_ldst_mult<string asm, bit L_bit, Format f,
let Inst{24-23} = 0b00; // Decrement After
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
+
+ let DecoderMethod = "DecodeMemMultipleWritebackInstruction";
}
def DB :
AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
@@ -2405,6 +2466,8 @@ multiclass arm_ldst_mult<string asm, bit L_bit, Format f,
let Inst{24-23} = 0b10; // Decrement Before
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
+
+ let DecoderMethod = "DecodeMemMultipleWritebackInstruction";
}
def IB :
AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
@@ -2421,6 +2484,8 @@ multiclass arm_ldst_mult<string asm, bit L_bit, Format f,
let Inst{24-23} = 0b11; // Increment Before
let Inst{21} = 1; // Writeback
let Inst{20} = L_bit;
+
+ let DecoderMethod = "DecodeMemMultipleWritebackInstruction";
}
}
@@ -2504,8 +2569,6 @@ def MOVsi : AsI1<0b1101, (outs GPR:$Rd), (ins shift_so_reg_imm:$src),
let Inst{25} = 0;
}
-
-
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMOVi,
"mov", "\t$Rd, $imm", [(set GPR:$Rd, so_imm:$imm)]>, UnaryDP {
@@ -3383,6 +3446,7 @@ multiclass AI_smul<string opc, PatFrag opnode> {
multiclass AI_smla<string opc, PatFrag opnode> {
+ let DecoderMethod = "DecodeSMLAInstruction" in {
def BB : AMulxyIa<0b0001000, 0b00, (outs GPR:$Rd),
(ins GPR:$Rn, GPR:$Rm, GPR:$Ra),
IIC_iMAC16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm, $Ra",
@@ -3425,6 +3489,7 @@ multiclass AI_smla<string opc, PatFrag opnode> {
[(set GPR:$Rd, (add GPR:$Ra, (sra (opnode GPR:$Rn,
(sra GPR:$Rm, (i32 16))), (i32 16))))]>,
Requires<[IsARM, HasV5TE]>;
+ }
}
defm SMUL : AI_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
@@ -3989,7 +4054,7 @@ class ACI<dag oops, dag iops, string opc, string asm,
}
multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
-
+ let DecoderNamespace = "Common" in {
def _OFFSET : ACI<(outs),
!con((ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr), ops),
!strconcat(opc, cond), "\tp$cop, cr$CRd, $addr"> {
@@ -3998,6 +4063,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 0; // W = 0
let Inst{22} = 0; // D = 0
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def _PRE : ACI<(outs),
@@ -4008,6 +4074,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 1; // W = 1
let Inst{22} = 0; // D = 0
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def _POST : ACI<(outs),
@@ -4018,6 +4085,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 1; // W = 1
let Inst{22} = 0; // D = 0
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def _OPTION : ACI<(outs),
@@ -4030,6 +4098,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 0; // W = 0
let Inst{22} = 0; // D = 0
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def L_OFFSET : ACI<(outs),
@@ -4040,6 +4109,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 0; // W = 0
let Inst{22} = 1; // D = 1
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def L_PRE : ACI<(outs),
@@ -4051,6 +4121,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 1; // W = 1
let Inst{22} = 1; // D = 1
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def L_POST : ACI<(outs),
@@ -4063,6 +4134,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 1; // W = 1
let Inst{22} = 1; // D = 1
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
}
def L_OPTION : ACI<(outs),
@@ -4076,6 +4148,8 @@ multiclass LdStCop<bits<4> op31_28, bit load, dag ops, string opc, string cond>{
let Inst{21} = 0; // W = 0
let Inst{22} = 1; // D = 1
let Inst{20} = load;
+ let DecoderMethod = "DecodeCopMemInstruction";
+ }
}
}
diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td
index 48071155c6..f6451704c1 100644
--- a/lib/Target/ARM/ARMInstrNEON.td
+++ b/lib/Target/ARM/ARMInstrNEON.td
@@ -191,6 +191,7 @@ class VLD1D<bits<4> op7_4, string Dt>
"vld1", Dt, "\\{$Vd\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD1Q<bits<4> op7_4, string Dt>
: NLdSt<0,0b10,0b1010,op7_4, (outs DPR:$Vd, DPR:$dst2),
@@ -198,6 +199,7 @@ class VLD1Q<bits<4> op7_4, string Dt>
"vld1", Dt, "\\{$Vd, $dst2\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD1d8 : VLD1D<{0,0,0,?}, "8">;
@@ -222,6 +224,7 @@ class VLD1DWB<bits<4> op7_4, string Dt>
"vld1", Dt, "\\{$Vd\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD1QWB<bits<4> op7_4, string Dt>
: NLdSt<0,0b10,0b1010,op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb),
@@ -229,6 +232,7 @@ class VLD1QWB<bits<4> op7_4, string Dt>
"vld1", Dt, "\\{$Vd, $dst2\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD1d8_UPD : VLD1DWB<{0,0,0,?}, "8">;
@@ -253,12 +257,14 @@ class VLD1D3<bits<4> op7_4, string Dt>
"\\{$Vd, $dst2, $dst3\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD1D3WB<bits<4> op7_4, string Dt>
: NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb),
(ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD1x3u, "vld1", Dt,
"\\{$Vd, $dst2, $dst3\\}, $Rn$Rm", "$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD1d8T : VLD1D3<{0,0,0,?}, "8">;
@@ -281,6 +287,7 @@ class VLD1D4<bits<4> op7_4, string Dt>
"\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD1D4WB<bits<4> op7_4, string Dt>
: NLdSt<0,0b10,0b0010,op7_4,
@@ -289,6 +296,7 @@ class VLD1D4WB<bits<4> op7_4, string Dt>
"\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm", "$Rn.addr = $wb",
[]> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD1d8Q : VLD1D4<{0,0,?,?}, "8">;
@@ -311,6 +319,7 @@ class VLD2D<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld2", Dt, "\\{$Vd, $dst2\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD2Q<bits<4> op7_4, string Dt>
: NLdSt<0, 0b10, 0b0011, op7_4,
@@ -319,6 +328,7 @@ class VLD2Q<bits<4> op7_4, string Dt>
"vld2", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD2d8 : VLD2D<0b1000, {0,0,?,?}, "8">;
@@ -344,6 +354,7 @@ class VLD2DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld2", Dt, "\\{$Vd, $dst2\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
class VLD2QWB<bits<4> op7_4, string Dt>
: NLdSt<0, 0b10, 0b0011, op7_4,
@@ -352,6 +363,7 @@ class VLD2QWB<bits<4> op7_4, string Dt>
"vld2", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD2d8_UPD : VLD2DWB<0b1000, {0,0,?,?}, "8">;
@@ -385,6 +397,7 @@ class VLD3D<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld3", Dt, "\\{$Vd, $dst2, $dst3\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD3d8 : VLD3D<0b0100, {0,0,0,?}, "8">;
@@ -403,6 +416,7 @@ class VLD3DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld3", Dt, "\\{$Vd, $dst2, $dst3\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD3d8_UPD : VLD3DWB<0b0100, {0,0,0,?}, "8">;
@@ -442,6 +456,7 @@ class VLD4D<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld4", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD4d8 : VLD4D<0b0000, {0,0,?,?}, "8">;
@@ -460,6 +475,7 @@ class VLD4DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
"vld4", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVLDInstruction";
}
def VLD4d8_UPD : VLD4DWB<0b0000, {0,0,?,?}, "8">;
@@ -826,6 +842,7 @@ class VLD1DUP<bits<4> op7_4, string Dt, ValueType Ty, PatFrag LoadOp>
[(set DPR:$Vd, (Ty (NEONvdup (i32 (LoadOp addrmode6dup:$Rn)))))]> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD1DupInstruction";
}
class VLD1QDUPPseudo<ValueType Ty, PatFrag LoadOp> : VLDQPseudo<IIC_VLD1dup> {
let Pattern = [(set QPR:$dst,
@@ -853,6 +870,7 @@ class VLD1QDUP<bits<4> op7_4, string Dt>
"vld1", Dt, "\\{$Vd[], $dst2[]\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD1DupInstruction";
}
def VLD1DUPq8 : VLD1QDUP<{0,0,1,0}, "8">;
@@ -865,12 +883,14 @@ class VLD1DUPWB<bits<4> op7_4, string Dt>
(ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD1dupu,
"vld1", Dt, "\\{$Vd[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD1DupInstruction";
}
class VLD1QDUPWB<bits<4> op7_4, string Dt>
: NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb),
(ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD1dupu,
"vld1", Dt, "\\{$Vd[], $dst2[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD1DupInstruction";
}
def VLD1DUPd8_UPD : VLD1DUPWB<{0,0,0,0}, "8">;
@@ -892,6 +912,7 @@ class VLD2DUP<bits<4> op7_4, string Dt>
"vld2", Dt, "\\{$Vd[], $dst2[]\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD2DupInstruction";
}
def VLD2DUPd8 : VLD2DUP<{0,0,0,?}, "8">;
@@ -913,6 +934,7 @@ class VLD2DUPWB<bits<4> op7_4, string Dt>
(ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD2dupu,
"vld2", Dt, "\\{$Vd[], $dst2[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD2DupInstruction";
}
def VLD2DUPd8_UPD : VLD2DUPWB<{0,0,0,0}, "8">;
@@ -934,6 +956,7 @@ class VLD3DUP<bits<4> op7_4, string Dt>
"vld3", Dt, "\\{$Vd[], $dst2[], $dst3[]\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD3DupInstruction";
}
def VLD3DUPd8 : VLD3DUP<{0,0,0,?}, "8">;
@@ -956,6 +979,7 @@ class VLD3DUPWB<bits<4> op7_4, string Dt>
"vld3", Dt, "\\{$Vd[], $dst2[], $dst3[]\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD3DupInstruction";
}
def VLD3DUPd8_UPD : VLD3DUPWB<{0,0,0,0}, "8">;
@@ -978,6 +1002,7 @@ class VLD4DUP<bits<4> op7_4, string Dt>
"vld4", Dt, "\\{$Vd[], $dst2[], $dst3[], $dst4[]\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD4DupInstruction";
}
def VLD4DUPd8 : VLD4DUP<{0,0,0,?}, "8">;
@@ -1001,6 +1026,7 @@ class VLD4DUPWB<bits<4> op7_4, string Dt>
"vld4", Dt, "\\{$Vd[], $dst2[], $dst3[], $dst4[]\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVLD4DupInstruction";
}
def VLD4DUPd8_UPD : VLD4DUPWB<{0,0,0,0}, "8">;
@@ -1046,6 +1072,7 @@ class VST1D<bits<4> op7_4, string Dt>
IIC_VST1, "vst1", Dt, "\\{$Vd\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST1Q<bits<4> op7_4, string Dt>
: NLdSt<0,0b00,0b1010,op7_4, (outs),
@@ -1053,6 +1080,7 @@ class VST1Q<bits<4> op7_4, string Dt>
"vst1", Dt, "\\{$Vd, $src2\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST1d8 : VST1D<{0,0,0,?}, "8">;
@@ -1076,6 +1104,7 @@ class VST1DWB<bits<4> op7_4, string Dt>
(ins addrmode6:$Rn, am6offset:$Rm, DPR:$Vd), IIC_VST1u,
"vst1", Dt, "\\{$Vd\\}, $Rn$Rm", "$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST1QWB<bits<4> op7_4, string Dt>
: NLdSt<0, 0b00, 0b1010, op7_4, (outs GPR:$wb),
@@ -1083,6 +1112,7 @@ class VST1QWB<bits<4> op7_4, string Dt>
IIC_VST1x2u, "vst1", Dt, "\\{$Vd, $src2\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST1d8_UPD : VST1DWB<{0,0,0,?}, "8">;
@@ -1107,6 +1137,7 @@ class VST1D3<bits<4> op7_4, string Dt>
IIC_VST1x3, "vst1", Dt, "\\{$Vd, $src2, $src3\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST1D3WB<bits<4> op7_4, string Dt>
: NLdSt<0, 0b00, 0b0110, op7_4, (outs GPR:$wb),
@@ -1115,6 +1146,7 @@ class VST1D3WB<bits<4> op7_4, string Dt>
IIC_VST1x3u, "vst1", Dt, "\\{$Vd, $src2, $src3\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST1d8T : VST1D3<{0,0,0,?}, "8">;
@@ -1138,6 +1170,7 @@ class VST1D4<bits<4> op7_4, string Dt>
[]> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST1D4WB<bits<4> op7_4, string Dt>
: NLdSt<0, 0b00, 0b0010, op7_4, (outs GPR:$wb),
@@ -1146,6 +1179,7 @@ class VST1D4WB<bits<4> op7_4, string Dt>
"vst1", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST1d8Q : VST1D4<{0,0,?,?}, "8">;
@@ -1168,6 +1202,7 @@ class VST2D<bits<4> op11_8, bits<4> op7_4, string Dt>
IIC_VST2, "vst2", Dt, "\\{$Vd, $src2\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST2Q<bits<4> op7_4, string Dt>
: NLdSt<0, 0b00, 0b0011, op7_4, (outs),
@@ -1176,6 +1211,7 @@ class VST2Q<bits<4> op7_4, string Dt>
"", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST2d8 : VST2D<0b1000, {0,0,?,?}, "8">;
@@ -1201,6 +1237,7 @@ class VST2DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
IIC_VST2u, "vst2", Dt, "\\{$Vd, $src2\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
class VST2QWB<bits<4> op7_4, string Dt>
: NLdSt<0, 0b00, 0b0011, op7_4, (outs GPR:$wb),
@@ -1209,6 +1246,7 @@ class VST2QWB<bits<4> op7_4, string Dt>
"vst2", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST2d8_UPD : VST2DWB<0b1000, {0,0,?,?}, "8">;
@@ -1242,6 +1280,7 @@ class VST3D<bits<4> op11_8, bits<4> op7_4, string Dt>
"vst3", Dt, "\\{$Vd, $src2, $src3\\}, $Rn", "", []> {
let Rm = 0b1111;
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST3d8 : VST3D<0b0100, {0,0,0,?}, "8">;
@@ -1260,6 +1299,7 @@ class VST3DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
"vst3", Dt, "\\{$Vd, $src2, $src3\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{4} = Rn{4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST3d8_UPD : VST3DWB<0b0100, {0,0,0,?}, "8">;
@@ -1299,6 +1339,7 @@ class VST4D<bits<4> op11_8, bits<4> op7_4, string Dt>
"", []> {
let Rm = 0b1111;
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST4d8 : VST4D<0b0000, {0,0,?,?}, "8">;
@@ -1317,6 +1358,7 @@ class VST4DWB<bits<4> op11_8, bits<4> op7_4, string Dt>
"vst4", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm",
"$Rn.addr = $wb", []> {
let Inst{5-4} = Rn{5-4};
+ let DecoderMethod = "DecodeVSTInstruction";
}
def VST4d8_UPD : VST4DWB<0b0000, {0,0,?,?}, "8">;
@@ -4040,6 +4082,7 @@ class N2VLShMax<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7,
: N2VLSh<op24, op23, op11_8, op7, op6, op4, OpcodeStr, Dt,
ResTy, OpTy, OpNode> {
let Inst{21-16} = op21_16;
+ let DecoderMethod = "DecodeVSHLMaxInstruction";
}
def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8",
v8i16, v8i8, NEONvshlli>;
@@ -4754,6 +4797,7 @@ def VZIPq32 : N2VQShuffle<0b10, 0b00011, IIC_VPERMQ3, "vzip", "32">;
// Vector Table Lookup and Table Extension.
// VTBL : Vector Table Lookup
+let DecoderMethod = "DecodeTBLInstruction" in {
def VTBL1
: N3V<1,1,0b11,0b1000,0,0, (outs DPR:$Vd),
(ins DPR:$Vn, DPR:$Vm), NVTBLFrm, IIC_VTB1,
@@ -4816,6 +4860,7 @@ def VTBX3Pseudo
def VTBX4Pseudo
: PseudoNeonI<(outs DPR:$dst), (ins DPR:$orig, QQPR:$tbl, DPR:$src),
IIC_VTBX4, "$orig = $dst", []>;
+} // DecoderMethod = "DecodeTBLInstruction"
//===----------------------------------------------------------------------===//
// NEON instructions for single-precision FP math
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index 8442e06503..2500e11d99 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -82,14 +82,17 @@ def t_imm_s4 : Operand<i32> {
let OperandType = "OPERAND_PCREL" in {
def t_brtarget : Operand<OtherVT> {
let EncoderMethod = "getThumbBRTargetOpValue";
+ let DecoderMethod = "DecodeThumbBROperand";
}
def t_bcctarget : Operand<i32> {
let EncoderMethod = "getThumbBCCTargetOpValue";
+ let DecoderMethod = "DecodeThumbBCCTargetOperand";
}
def t_cbtarget : Operand<i32> {
let EncoderMethod = "getThumbCBTargetOpValue";
+ let DecoderMethod = "DecodeThumbCmpBROperand";
}
def t_bltarget : Operand<i32> {
@@ -119,12 +122,14 @@ def t_addrmode_rrs1 : Operand<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeRI5S1", []> {
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<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeRI5S2", []> {
let EncoderMethod = "getThumbAddrModeRegRegOpValue";
+ let DecoderMethod = "DecodeThumbAddrModeRR";
let PrintMethod = "printThumbAddrModeRROperand";
let ParserMatchClass = t_addrmode_rr_asm_operand;
let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg);
@@ -132,6 +137,7 @@ def t_addrmode_rrs2 : Operand<i32>,
def t_addrmode_rrs4 : Operand<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeRI5S4", []> {
let EncoderMethod = "getThumbAddrModeRegRegOpValue";
+ let DecoderMethod = "DecodeThumbAddrModeRR";
let PrintMethod = "printThumbAddrModeRROperand";
let ParserMatchClass = t_addrmode_rr_asm_operand;
let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg);
@@ -142,6 +148,7 @@ def t_addrmode_rrs4 : Operand<i32>,
def t_addrmode_is4 : Operand<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeImm5S4", []> {
let EncoderMethod = "getAddrModeISOpValue";
+ let DecoderMethod = "DecodeThumbAddrModeIS";
let PrintMethod = "printThumbAddrModeImm5S4Operand";
let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm);
}
@@ -151,6 +158,7 @@ def t_addrmode_is4 : Operand<i32>,
def t_addrmode_is2 : Operand<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeImm5S2", []> {
let EncoderMethod = "getAddrModeISOpValue";
+ let DecoderMethod = "DecodeThumbAddrModeIS";
let PrintMethod = "printThumbAddrModeImm5S2Operand";
let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm);
}
@@ -160,6 +168,7 @@ def t_addrmode_is2 : Operand<i32>,
def t_addrmode_is1 : Operand<i32>,
ComplexPattern<i32, 2, "SelectThumbAddrModeImm5S1", []> {
let EncoderMethod = "getAddrModeISOpValue";
+ let DecoderMethod = "DecodeThumbAddrModeIS";
let PrintMethod = "printThumbAddrModeImm5S1Operand";
let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm);
}
@@ -178,6 +187,7 @@ def t_addrmode_sp : Operand<i32>,
//
def t_addrmode_pc : Operand<i32> {
let EncoderMethod = "getAddrModePCOpValue";
+ let DecoderMethod = "DecodeThumbAddrModePC";
}
//===----------------------------------------------------------------------===//
@@ -259,6 +269,7 @@ def tCPS : T1I<(outs), (ins imod_op:$imod, iflags_op:$iflags),
let Inst{4} = imod;
let Inst{3} = 0;
let Inst{2-0} = iflags;
+ let DecoderMethod = "DecodeThumbCPS";
}
// For both thumb1 and thumb2.
@@ -272,17 +283,6 @@ def tPICADD : TIt<(outs GPR:$dst), (ins GPR:$lhs, pclabel:$cp), IIC_iALUr, "",
let Inst{2-0} = dst;
}
-// PC relative add (ADR).
-def tADDrPCi : T1I<(outs tGPR:$dst), (ins t_imm_s4:$rhs), IIC_iALUi,
- "add\t$dst, pc, $rhs", []>,
- T1Encoding<{1,0,1,0,0,?}> {
- // A6.2 & A8.6.10
- bits<3> dst;
- bits<8> rhs;
- let Inst{10-8} = dst;
- let Inst{7-0} = rhs;
-}
-
// ADD <Rd>, sp, #<imm8>
// This is rematerializable, which is particularly useful for taking the
// address of locals.
@@ -295,6 +295,7 @@ def tADDrSPi : T1I<(outs tGPR:$dst), (ins GPR:$sp, t_imm_s4:$rhs), IIC_iALUi,
bits<8> rhs;
let Inst{10-8} = dst;
let Inst{7-0} = rhs;
+ let DecoderMethod = "DecodeThumbAddSpecialReg";
}
// ADD sp, sp, #<imm7>
@@ -304,6 +305,7 @@ def tADDspi : TIt<(outs GPR:$dst), (ins GPR:$lhs, t_imm_s4:$rhs), IIC_iALUi,
// A6.2.5 & A8.6.8
bits<7> rhs;
let Inst{6-0} = rhs;
+ let DecoderMethod = "DecodeThumbAddSPImm";
}
// SUB sp, sp, #<imm7>
@@ -314,6 +316,7 @@ def tSUBspi : TIt<(outs GPR:$dst), (ins GPR:$lhs, t_imm_s4:$rhs), IIC_iALUi,
// A6.2.5 & A8.6.214
bits<7> rhs;
let Inst{6-0} = rhs;
+ let DecoderMethod = "DecodeThumbAddSPImm";
}
// ADD <Rm>, sp
@@ -325,6 +328,7 @@ def tADDrSP : TIt<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr,
let Inst{7} = dst{3};
let Inst{6-3} = 0b1101;
let Inst{2-0} = dst{2-0};
+ let DecoderMethod = "DecodeThumbAddSPReg";
}
// ADD sp, <Rm>
@@ -336,6 +340,7 @@ def tADDspr : TIt<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr,
let Inst{7} = 1;
let Inst{6-3} = dst;
let Inst{2-0} = 0b101;
+ let DecoderMethod = "DecodeThumbAddSPReg";
}
//===----------------------------------------------------------------------===//
@@ -1189,6 +1194,7 @@ def tADR : T1I<(outs tGPR:$Rd), (ins t_adrlabel:$addr, pred:$p),
bits<8> addr;
let Inst{10-8} = Rd;
let Inst{7-0} = addr;
+ let DecoderMethod = "DecodeThumbAddSpecialReg";
}
let neverHasSideEffects = 1, isReMaterializable = 1 in
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 25a3441066..795473bf8b 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -50,6 +50,7 @@ def t2_so_imm : Operand<i32>, ImmLeaf<i32, [{
}]> {
let ParserMatchClass = t2_so_imm_asmoperand;
let EncoderMethod = "getT2SOImmOpValue";
+ let DecoderMethod = "DecodeT2SOImm";
}
// t2_so_imm_not - Match an immediate that is a complement
@@ -100,6 +101,7 @@ def t2addrmode_imm12 : Operand<i32>,
ComplexPattern<i32, 2, "SelectT2AddrModeImm12", []> {
let PrintMethod = "printAddrModeImm12Operand";
let EncoderMethod = "getAddrModeImm12OpValue";
+ let DecoderMethod = "DecodeT2AddrModeImm12";
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
@@ -121,6 +123,7 @@ def t2addrmode_imm8 : Operand<i32>,
ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
let PrintMethod = "printT2AddrModeImm8Operand";
let EncoderMethod = "getT2AddrModeImm8OpValue";
+ let DecoderMethod = "DecodeT2AddrModeImm8";
let ParserMatchClass = MemImm8OffsetAsmOperand;
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
@@ -130,12 +133,14 @@ def t2am_imm8_offset : Operand<i32>,
[], [SDNPWantRoot]> {
let PrintMethod = "printT2AddrModeImm8OffsetOperand";
let EncoderMethod = "getT2AddrModeImm8OffsetOpValue";
+ let DecoderMethod = "DecodeT2Imm8";
}
// t2addrmode_imm8s4 := reg +/- (imm8 << 2)
def t2addrmode_imm8s4 : Operand<i32> {
let PrintMethod = "printT2AddrModeImm8s4Operand";
let EncoderMethod = "getT2AddrModeImm8s4OpValue";
+ let DecoderMethod = "DecodeT2AddrModeImm8s4";
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
@@ -149,6 +154,7 @@ def t2addrmode_so_reg : Operand<i32>,
ComplexPattern<i32, 3, "SelectT2AddrModeSoReg", []> {
let PrintMethod = "printT2AddrModeSoRegOperand";
let EncoderMethod = "getT2AddrModeSORegOpValue";
+ let DecoderMethod = "DecodeT2AddrModeSOReg";
let MIOperandInfo = (ops GPR:$base, rGPR:$offsreg, i32imm:$offsimm);
}
@@ -158,6 +164,7 @@ def t2addrmode_so_reg : Operand<i32>,
//
def t2addrmode_reg : Operand<i32> {
let PrintMethod = "printAddrMode7Operand";
+ let DecoderMethod = "DecodeGPRRegisterClass";
let MIOperandInfo = (ops GPR);
}
@@ -892,6 +899,8 @@ multiclass T2I_ld<bit signed, bits<2> opcod, string opc,
let Inst{19-16} = addr{9-6}; // Rn
let Inst{3-0} = addr{5-2}; // Rm
let Inst{5-4} = addr{1-0}; // imm
+
+ let DecoderMethod = "DecodeT2LoadShift";
}
// FIXME: Is the pci variant actually needed?
@@ -1430,6 +1439,8 @@ multiclass T2Ipl<bits<1> write, bits<1> instr, string opc> {
let Inst{19-16} = addr{9-6}; // Rn
let Inst{3-0} = addr{5-2}; // Rm
let Inst{5-4} = addr{1-0}; // imm2
+
+ let DecoderMethod = "DecodeT2LoadShift";
}
}
@@ -2994,6 +3005,8 @@ def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br,
let Inst{13} = target{18};
let Inst{21-16} = target{17-12};
let Inst{10-0} = target{11-1};
+
+ let DecoderMethod = "DecodeThumb2BCCInstruction";
}
// Tail calls. The Darwin version of thumb tail calls uses a t2 branch, so
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index c89e3e8a8f..8ae8ce8342 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -6,584 +6,2328 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file is part of the ARM Disassembler.
-// It contains code to implement the public interfaces of ARMDisassembler and
-// ThumbDisassembler, both of which are instances of MCDisassembler.
-//
-//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "arm-disassembler"
#include "ARMDisassembler.h"
-#include "ARMDisassemblerCore.h"
-
-#include "llvm/ADT/OwningPtr.h"
+#include "ARM.h"
+#include "ARMRegisterInfo.h"
+#include "MCTargetDesc/ARMAddressingModes.h"
+#include "MCTargetDesc/ARMBaseInfo.h"
#include "llvm/MC/EDInstInfo.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-//#define DEBUG(X) do { X; } while (0)
-
-/// ARMGenDecoderTables.inc - ARMDecoderTables.inc is tblgen'ed from
-/// ARMDecoderEmitter.cpp TableGen backend. It contains:
-///
-/// o Mappings from opcode to ARM/Thumb instruction format
-///
-/// o static uint16_t decodeInstruction(uint32_t insn) - the decoding function
-/// for an ARM instruction.
-///
-/// o static uint16_t decodeThumbInstruction(field_t insn) - the decoding
-/// function for a Thumb instruction.
-///
-#include "ARMGenDecoderTables.inc"
-
+// Forward declare these because the autogenerated code will reference them.
+// Definitions are further down.
+static bool DecodeGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodetGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodetcGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecoderGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodeDPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodeDPR_8RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodeDPR_VFP2RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+static bool DecodeQPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+
+static bool DecodePredicateOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeCCOutOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSOImmOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSPRRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeDPRRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+
+static bool DecodeBitfieldMaskOperand(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeCopMemInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode2IdxInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSORegMemOperand(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode3Instruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSORegImmOperand(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeSORegRegOperand(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+static bool DecodeMemMultipleWritebackInstruction(llvm::MCInst & Inst,
+ unsigned Insn,
+ uint64_t Adddress,
+ const void *Decoder);
+static bool DecodeSMLAInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrModeImm12Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode5Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode7Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeBranchImmInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVCVTImmOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode6Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVLDInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVSTInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVLD1DupInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVLD2DupInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVLD3DupInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVLD4DupInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeNEONModImmInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVSHLMaxInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeShiftRight8Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeShiftRight16Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeShiftRight32Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeShiftRight64Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeTBLInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeVFPfpImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodePostIdxReg(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeCoprocessor(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeAddrMode3Offset(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+
+static bool DecodeThumbAddSpecialReg(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbBROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2BROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbCmpBROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddrModeRR(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddrModeIS(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddrModePC(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddrModeSP(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2AddrModeSOReg(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2LoadShift(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2Imm8S4(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2AddrModeImm8s4(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2Imm8(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2AddrModeImm8(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddSPImm(llvm::MCInst &Inst, uint16_t Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbAddSPReg(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbCPS(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbBLXOffset(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2AddrModeImm12(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbSRImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumb2BCCInstruction(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeT2SOImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbBCCTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+static bool DecodeThumbBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder);
+
+#include "ARMGenDisassemblerTables.inc"
+#include "ARMGenInstrInfo.inc"
#include "ARMGenEDInfo.inc"
using namespace llvm;
-/// showBitVector - Use the raw_ostream to log a diagnostic message describing
-/// the inidividual bits of the instruction.
-///
-static inline void showBitVector(raw_ostream &os, const uint32_t &insn) {
- // Split the bit position markers into more than one lines to fit 80 columns.
- os << " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11"
- << " 10 9 8 7 6 5 4 3 2 1 0 \n";
- os << "---------------------------------------------------------------"
- << "----------------------------------\n";
- os << '|';
- for (unsigned i = 32; i != 0; --i) {
- if (insn >> (i - 1) & 0x01)
- os << " 1";
- else
- os << " 0";
- os << (i%4 == 1 ? '|' : ':');
- }
- os << '\n';
- // Split the bit position markers into more than one lines to fit 80 columns.
- os << "---------------------------------------------------------------"
- << "----------------------------------\n";
- os << '\n';
-}
-
-/// decodeARMInstruction is a decorator function which tries special cases of
-/// instruction matching before calling the auto-generated decoder function.
-static unsigned decodeARMInstruction(uint32_t &insn) {
- if (slice(insn, 31, 28) == 15)
- goto AutoGenedDecoder;
-
- // Special case processing, if any, goes here....
-
- // LLVM combines the offset mode of A8.6.197 & A8.6.198 into STRB.
- // The insufficient encoding information of the combined instruction confuses
- // the decoder wrt BFC/BFI. Therefore, we try to recover here.
- // For BFC, Inst{27-21} = 0b0111110 & Inst{6-0} = 0b0011111.
- // For BFI, Inst{27-21} = 0b0111110 & Inst{6-4} = 0b001 & Inst{3-0} =! 0b1111.
- if (slice(insn, 27, 21) == 0x3e && slice(insn, 6, 4) == 1) {
- if (slice(insn, 3, 0) == 15)
- return ARM::BFC;
- else
- return ARM::BFI;
- }
-
- // Ditto for STRBT, which is a super-instruction for A8.6.199 Encodings
- // A1 & A2.
- // As a result, the decoder fails to deocode USAT properly.
- if (slice(insn, 27, 21) == 0x37 && slice(insn, 5, 4) == 1)
- return ARM::USAT;
- // As a result, the decoder fails to deocode UQADD16 properly.
- if (slice(insn, 27, 20) == 0x66 && slice(insn, 7, 4) == 1)
- return ARM::UQADD16;
-
- // Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8.
- // As a result, the decoder fails to decode UMULL properly.
- if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) {
- return ARM::UMULL;
- }
-
- // Ditto for STR_PRE, which is a super-instruction for A8.6.194 & A8.6.195.
- // As a result, the decoder fails to decode SBFX properly.
- if (slice(insn, 27, 21) == 0x3d && slice(insn, 6, 4) == 5)
- return ARM::SBFX;
-
- // And STRB_PRE, which is a super-instruction for A8.6.197 & A8.6.198.
- // As a result, the decoder fails to decode UBFX properly.
- if (slice(insn, 27, 21) == 0x3f && slice(insn, 6, 4) == 5)
- return ARM::UBFX;
-
- // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2.
- // As a result, the decoder fails to deocode SSAT properly.
- if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1)
- return ARM::SSAT;
-
- // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147.
- // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT.
- if (slice(insn, 27, 24) == 0) {
- switch (slice(insn, 21, 20)) {
- case 2:
- switch (slice(insn, 7, 4)) {
- case 11:
- return slice(insn, 22, 22) ? ARM::STRHTi : ARM::STRHTr;
- default:
- break; // fallthrough
+static MCDisassembler *createARMDisassembler(const Target &T) {
+ return new ARMDisassembler;
+}
+
+static MCDisassembler *createThumbDisassembler(const Target &T) {
+ return new ThumbDisassembler;
+}
+
+EDInstInfo *ARMDisassembler::getEDInfo() const {
+ return instInfoARM;
+}
+
+EDInstInfo *ThumbDisassembler::getEDInfo() const {
+ return instInfoARM;
+}
+
+
+bool ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
+ const MemoryObject &Region,
+ uint64_t Address,raw_ostream &os) const {
+ uint8_t bytes[4];
+
+ // We want to read exactly 4 bytes of data.
+ if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1)
+ return false;
+
+ // Encoded as a small-endian 32-bit word in the stream.
+ uint32_t insn = (bytes[3] << 24) |
+ (bytes[2] << 16) |
+ (bytes[1] << 8) |
+ (bytes[0] << 0);
+
+ // Calling the auto-generated decoder function.
+ bool result = decodeARMInstruction32(MI, insn, Address, this);
+ if (result) {
+ Size = 4;
+ return true;
+ }
+
+ // Instructions that are shared between ARM and Thumb modes.
+ // FIXME: This shouldn't really exist. It's an artifact of the
+ // fact that we fail to encode a few instructions properly for Thumb.
+ MI.clear();
+ result = decodeCommonInstruction32(MI, insn, Address, this);
+ if (result) {
+ Size = 4;
+ return true;
+ }
+
+ // VFP and NEON instructions, similarly, are shared between ARM
+ // and Thumb modes.
+ MI.clear();
+ result = decodeVFPInstruction32(MI, insn, Address, this);
+ if (result) {
+ Size = 4;
+ return true;
+ }
+
+ MI.clear();
+ result = decodeNEONInstruction32(MI, insn, Address, this);
+ if (result) {
+ // Add a fake predicate operand, because we share these instruction
+ // definitions with Thumb2 where these instructions are predicable.
+ if (!DecodePredicateOperand(MI, 0xE, Address, this)) return false;
+ Size = 4;
+ return true;
+ }
+
+ MI.clear();
+
+ return false;
+}
+
+namespace llvm {
+extern MCInstrDesc ARMInsts[];
+}
+
+// Thumb1 instructions don't have explicit S bits. Rather, they
+// implicitly set CPSR. Since it's not represented in the encoding, the
+// auto-generated decoder won't inject the CPSR operand. We need to fix
+// that as a post-pass.
+static void AddThumb1SBit(MCInst &MI, bool InITBlock) {
+ const MCOperandInfo *OpInfo = ARMInsts[MI.getOpcode()].OpInfo;
+ MCInst::iterator I = MI.begin();
+ for (unsigned i = 0; i < MI.size(); ++i, ++I) {
+ if (OpInfo[i].isOptionalDef() && OpInfo[i].RegClass == ARM::CCRRegClassID) {
+ MI.insert(I, MCOperand::CreateReg(InITBlock ? 0 : ARM::CPSR));
+ return;
+ }
+ }
+
+ if (OpInfo[MI.size()].isOptionalDef() &&
+ OpInfo[MI.size()].RegClass == ARM::CCRRegClassID)
+ MI.insert(MI.end(), MCOperand::CreateReg(InITBlock ? 0 : ARM::CPSR));
+}
+
+// Most Thumb instructions don't have explicit predicates in the
+// encoding, but rather get their predicates from IT context. We need
+// to fix up the predicate operands using this context information as a
+// post-pass.
+void ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
+ // A few instructions actually have predicates encoded in them. Don't
+ // try to overwrite it if we're seeing one of those.
+ switch (MI.getOpcode()) {
+ case ARM::tBcc:
+ case ARM::t2Bcc:
+ return;
+ default:
+ break;
+ }
+
+ // If we're in an IT block, base the predicate on that. Otherwise,
+ // assume a predicate of AL.
+ unsigned CC;
+ if (ITBlock.size()) {
+ CC = ITBlock.back();
+ ITBlock.pop_back();
+ } else
+ CC = ARMCC::AL;
+
+ const MCOperandInfo *OpInfo = ARMInsts[MI.getOpcode()].OpInfo;
+ MCInst::iterator I = MI.begin();
+ for (unsigned i = 0; i < MI.size(); ++i, ++I) {
+ if (OpInfo[i].isPredicate()) {
+ I = MI.insert(I, MCOperand::CreateImm(CC));
+ ++I;
+ if (CC == ARMCC::AL)
+ MI.insert(I, MCOperand::CreateReg(0));
+ else
+ MI.insert(I, MCOperand::CreateReg(ARM::CPSR));
+ return;
+ }
+ }
+
+ MI.insert(MI.end(), MCOperand::CreateImm(CC));
+ if (CC == ARMCC::AL)
+ MI.insert(MI.end(), MCOperand::CreateReg(0));
+ else
+ MI.insert(MI.end(), MCOperand::CreateReg(ARM::CPSR));
+}
+
+// Thumb VFP instructions are a special case. Because we share their
+// encodings between ARM and Thumb modes, and they are predicable in ARM
+// mode, the auto-generated decoder will give them an (incorrect)
+// predicate operand. We need to rewrite these operands based on the IT
+// context as a post-pass.
+void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const {
+ unsigned CC;
+ if (ITBlock.size()) {
+ CC = ITBlock.back();
+ ITBlock.pop_back();
+ } else
+ CC = ARMCC::AL;
+
+ const MCOperandInfo *OpInfo = ARMInsts[MI.getOpcode()].OpInfo;
+ MCInst::iterator I = MI.begin();
+ for (unsigned i = 0; i < MI.size(); ++i, ++I) {
+ if (OpInfo[i].isPredicate() ) {
+ I->setImm(CC);
+ ++I;
+ if (CC == ARMCC::AL)
+ I->setReg(0);
+ else
+ I->setReg(ARM::CPSR);
+ return;
+ }
+ }
+}
+
+
+bool ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
+ const MemoryObject &Region,
+ uint64_t Address,raw_ostream &os) const {
+ uint8_t bytes[4];
+
+ // We want to read exactly 2 bytes of data.
+ if (Region.readBytes(Address, 2, (uint8_t*)bytes, NULL) == -1)
+ return false;
+
+ uint16_t insn16 = (bytes[1] << 8) | bytes[0];
+ bool result = decodeThumbInstruction16(MI, insn16, Address, this);
+ if (result) {
+ Size = 2;
+ bool InITBlock = ITBlock.size();
+ AddThumbPredicate(MI);
+ AddThumb1SBit(MI, InITBlock);
+ return true;
+ }
+
+ MI.clear();
+ result = decodeThumb2Instruction16(MI, insn16, Address, this);
+ if (result) {
+ Size = 2;
+ AddThumbPredicate(MI);
+
+ // If we find an IT instruction, we need to parse its condition
+ // code and mask operands so that we can apply them correctly
+ // to the subsequent instructions.
+ if (MI.getOpcode() == ARM::t2IT) {
+ unsigned firstcond = MI.getOperand(0).getImm();
+ uint32_t mask = MI.getOperand(1).getImm();
+ unsigned zeros = CountTrailingZeros_32(mask);
+ mask >>= zeros+1;
+
+ for (unsigned i = 0; i < 4 - (zeros+1); ++i) {
+ if (firstcond ^ (mask & 1))
+ ITBlock.push_back(firstcond ^ 1);
+ else
+ ITBlock.push_back(firstcond);
+ mask >>= 1;
}
+ ITBlock.push_back(firstcond);
+ }
+
+ return true;
+ }
+
+ // We want to read exactly 4 bytes of data.
+ if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1)
+ return false;
+
+ uint32_t insn32 = (bytes[3] << 8) |
+ (bytes[2] << 0) |
+ (bytes[1] << 24) |
+ (bytes[0] << 16);
+ MI.clear();
+ result = decodeThumbInstruction32(MI, insn32, Address, this);
+ if (result) {
+ Size = 4;
+ bool InITBlock = ITBlock.size();
+ AddThumbPredicate(MI);
+ AddThumb1SBit(MI, InITBlock);
+ return true;
+ }
+
+ MI.clear();
+ result = decodeThumb2Instruction32(MI, insn32, Address, this);
+ if (result) {
+ Size = 4;
+ AddThumbPredicate(MI);
+ return true;
+ }
+
+ MI.clear();
+ result = decodeVFPInstruction32(MI, insn32, Address, this);
+ if (result) {
+ Size = 4;
+ UpdateThumbVFPPredicate(MI);
+ return true;
+ }
+
+ MI.clear();
+ result = decodeCommonInstruction32(MI, insn32, Address, this);
+ if (result) {
+ Size = 4;
+ AddThumbPredicate(MI);
+ return true;
+ }
+
+ return false;
+}
+
+
+extern "C" void LLVMInitializeARMDisassembler() {
+ TargetRegistry::RegisterMCDisassembler(TheARMTarget,
+ createARMDisassembler);
+ TargetRegistry::RegisterMCDisassembler(TheThumbTarget,
+ createThumbDisassembler);
+}
+
+static const unsigned GPRDecoderTable[] = {
+ ARM::R0, ARM::R1, ARM::R2, ARM::R3,
+ ARM::R4, ARM::R5, ARM::R6, ARM::R7,
+ ARM::R8, ARM::R9, ARM::R10, ARM::R11,
+ ARM::R12, ARM::SP, ARM::LR, ARM::PC
+};
+
+static bool DecodeGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 15)
+ return false;
+
+ unsigned Register = GPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Register));
+ return true;
+}
+
+static bool DecodetGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 7)
+ return false;
+ return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static bool DecodetcGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ unsigned Register = 0;
+ switch (RegNo) {
+ case 0:
+ Register = ARM::R0;
+ break;
+ case 1:
+ Register = ARM::R1;
+ break;
+ case 2:
+ Register = ARM::R2;
break;
case 3:
- switch (slice(insn, 7, 4)) {
- case 11:
- return slice(insn, 22, 22) ? ARM::LDRHTi : ARM::LDRHTr;
- case 13:
- return slice(insn, 22, 22) ? ARM::LDRSBTi : ARM::LDRSBTr;
- case 15:
- return slice(insn, 22, 22) ? ARM::LDRSHTi : ARM::LDRSHTr;
- default:
- break; // fallthrough
- }
+ Register = ARM::R3;
+ break;
+ case 9:
+ Register = ARM::R9;
+ break;
+ case 12:
+ Register = ARM::R12;
break;
default:
- break; // fallthrough
+ return false;
}
+
+ Inst.addOperand(MCOperand::CreateReg(Register));
+ return true;
+}
+
+static bool DecoderGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo == 13 || RegNo == 15) return false;
+ return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static const unsigned SPRDecoderTable[] = {
+ ARM::S0, ARM::S1, ARM::S2, ARM::S3,
+ ARM::S4, ARM::S5, ARM::S6, ARM::S7,
+ ARM::S8, ARM::S9, ARM::S10, ARM::S11,
+ ARM::S12, ARM::S13, ARM::S14, ARM::S15,
+ ARM::S16, ARM::S17, ARM::S18, ARM::S19,
+ ARM::S20, ARM::S21, ARM::S22, ARM::S23,
+ ARM::S24, ARM::S25, ARM::S26, ARM::S27,
+ ARM::S28, ARM::S29, ARM::S30, ARM::S31
+};
+
+static bool DecodeSPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 31)
+ return false;
+
+ unsigned Register = SPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Register));
+ return true;
+}
+
+static const unsigned DPRDecoderTable[] = {
+ ARM::D0, ARM::D1, ARM::D2, ARM::D3,
+ ARM::D4, ARM::D5, ARM::D6, ARM::D7,
+ ARM::D8, ARM::D9, ARM::D10, ARM::D11,
+ ARM::D12, ARM::D13, ARM::D14, ARM::D15,
+ ARM::D16, ARM::D17, ARM::D18, ARM::D19,
+ ARM::D20, ARM::D21, ARM::D22, ARM::D23,
+ ARM::D24, ARM::D25, ARM::D26, ARM::D27,
+ ARM::D28, ARM::D29, ARM::D30, ARM::D31
+};
+
+static bool DecodeDPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 31)
+ return false;
+
+ unsigned Register = DPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Register));
+ return true;
+}
+
+static bool DecodeDPR_8RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 7)
+ return false;
+ return DecodeDPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static bool DecodeDPR_VFP2RegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 15)
+ return false;
+ return DecodeDPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static const unsigned QPRDecoderTable[] = {
+ ARM::Q0, ARM::Q1, ARM::Q2, ARM::Q3,
+ ARM::Q4, ARM::Q5, ARM::Q6, ARM::Q7,
+ ARM::Q8, ARM::Q9, ARM::Q10, ARM::Q11,
+ ARM::Q12, ARM::Q13, ARM::Q14, ARM::Q15
+};
+
+
+static bool DecodeQPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 31)
+ return false;
+ RegNo >>= 1;
+
+ unsigned Register = QPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Register));
+ return true;
+}
+
+static bool DecodePredicateOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ if (Val == 0xF) return false;
+ Inst.addOperand(MCOperand::CreateImm(Val));
+ if (Val == ARMCC::AL) {
+ Inst.addOperand(MCOperand::CreateReg(0));
+ } else
+ Inst.addOperand(MCOperand::CreateReg(ARM::CPSR));
+ return true;
+}
+
+static bool DecodeCCOutOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ if (Val)
+ Inst.addOperand(MCOperand::CreateReg(ARM::CPSR));
+ else
+ Inst.addOperand(MCOperand::CreateReg(0));
+ return true;
+}
+
+static bool DecodeSOImmOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ uint32_t imm = Val & 0xFF;
+ uint32_t rot = (Val & 0xF00) >> 7;
+ uint32_t rot_imm = (imm >> rot) | (imm << (32-rot));
+ Inst.addOperand(MCOperand::CreateImm(rot_imm));
+ return true;
+}
+
+static bool DecodeBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Val <<= 2;
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<26>(Val)));
+ return true;
+}
+
+static bool DecodeSORegImmOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+
+ unsigned Rm = fieldFromInstruction32(Val, 0, 4);
+ unsigned type = fieldFromInstruction32(Val, 5, 2);
+ unsigned imm = fieldFromInstruction32(Val, 7, 5);
+
+ // Register-immediate
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ ARM_AM::ShiftOpc Shift = ARM_AM::lsl;
+ switch (type) {
+ case 0:
+ Shift = ARM_AM::lsl;
+ break;
+ case 1:
+ Shift = ARM_AM::lsr;
+ break;
+ case 2:
+ Shift = ARM_AM::asr;
+ break;
+ case 3:
+ Shift = ARM_AM::ror;
+ break;
}
- // Ditto for SBCrs, which is a super-instruction for A8.6.152 & A8.6.153.
- // As a result, the decoder fails to decode STRH_Post/LDRD_POST/STRD_POST
- // properly.
- if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 0) {
- unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21);
- switch (slice(insn, 7, 4)) {
- case 11:
- switch (PW) {
- case 2: // Offset
- return ARM::STRH;
- case 3: // Pre-indexed
- return ARM::STRH_PRE;
- case 0: // Post-indexed
- return ARM::STRH_POST;
- default:
- break; // fallthrough
- }
+ if (Shift == ARM_AM::ror && imm == 0)
+ Shift = ARM_AM::rrx;
+
+ unsigned Op = Shift | (imm << 3);
+ Inst.addOperand(MCOperand::CreateImm(Op));
+
+ return true;
+}
+
+static bool DecodeSORegRegOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+
+ unsigned Rm = fieldFromInstruction32(Val, 0, 4);
+ unsigned type = fieldFromInstruction32(Val, 5, 2);
+ unsigned Rs = fieldFromInstruction32(Val, 8, 4);
+
+ // Register-register
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Rs, Address, Decoder);
+
+ ARM_AM::ShiftOpc Shift = ARM_AM::lsl;
+ switch (type) {
+ case 0:
+ Shift = ARM_AM::lsl;
break;
- case 13:
- switch (PW) {
- case 2: // Offset
- return ARM::LDRD;
- case 3: // Pre-indexed
- return ARM::LDRD_PRE;
- case 0: // Post-indexed
- return ARM::LDRD_POST;
- default:
- break; // fallthrough
- }
+ case 1:
+ Shift = ARM_AM::lsr;
break;
- case 15:
- switch (PW) {
- case 2: // Offset
- return ARM::STRD;
- case 3: // Pre-indexed
- return ARM::STRD_PRE;
- case 0: // Post-indexed
- return ARM::STRD_POST;
- default:
- break; // fallthrough
- }
+ case 2:
+ Shift = ARM_AM::asr;
+ break;
+ case 3:
+ Shift = ARM_AM::ror;
+ break;
+ }
+
+ Inst.addOperand(MCOperand::CreateImm(Shift));
+
+ return true;
+}
+
+static bool DecodeRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ for (unsigned i = 0; i < 16; ++i) {
+ if (Val & (1 << i))
+ DecodeGPRRegisterClass(Inst, i, Address, Decoder);
+ }
+
+ return true;
+}
+
+static bool DecodeSPRRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Vd = fieldFromInstruction32(Val, 8, 4);
+ unsigned regs = Val & 0xFF;
+
+ DecodeSPRRegisterClass(Inst, Vd, Address, Decoder);
+ for (unsigned i = 0; i < (regs - 1); ++i)
+ DecodeSPRRegisterClass(Inst, ++Vd, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeDPRRegListOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Vd = fieldFromInstruction32(Val, 8, 4);
+ unsigned regs = (Val & 0xFF) / 2;
+
+ DecodeDPRRegisterClass(Inst, Vd, Address, Decoder);
+ for (unsigned i = 0; i < (regs - 1); ++i)
+ DecodeDPRRegisterClass(Inst, ++Vd, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeBitfieldMaskOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned msb = fieldFromInstruction32(Val, 5, 5);
+ unsigned lsb = fieldFromInstruction32(Val, 0, 5);
+ uint32_t msb_mask = (1 << (msb+1)) - 1;
+ uint32_t lsb_mask = (1 << lsb) - 1;
+ Inst.addOperand(MCOperand::CreateImm(~(msb_mask ^ lsb_mask)));
+ return true;
+}
+
+static bool DecodeCopMemInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+ unsigned CRd = fieldFromInstruction32(Insn, 12, 4);
+ unsigned coproc = fieldFromInstruction32(Insn, 8, 4);
+ unsigned imm = fieldFromInstruction32(Insn, 0, 8);
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned U = fieldFromInstruction32(Insn, 23, 1);
+
+ switch (Inst.getOpcode()) {
+ case ARM::LDC_OFFSET:
+ case ARM::LDC_PRE:
+ case ARM::LDC_POST:
+ case ARM::LDC_OPTION:
+ case ARM::LDCL_OFFSET:
+ case ARM::LDCL_PRE:
+ case ARM::LDCL_POST:
+ case ARM::LDCL_OPTION:
+ case ARM::STC_OFFSET:
+ case ARM::STC_PRE:
+ case ARM::STC_POST:
+ case ARM::STC_OPTION:
+ case ARM::STCL_OFFSET:
+ case ARM::STCL_PRE:
+ case ARM::STCL_POST:
+ case ARM::STCL_OPTION:
+ if (coproc == 0xA || coproc == 0xB)
+ return false;
break;
default:
- break; // fallthrough
- }
+ break;
}
- // Ditto for SBCSSrs, which is a super-instruction for A8.6.152 & A8.6.153.
- // As a result, the decoder fails to decode LDRH_POST/LDRSB_POST/LDRSH_POST
- // properly.
- if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 1) {
- unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21);
- switch (slice(insn, 7, 4)) {
- case 11:
- switch (PW) {
- case 2: // Offset
- return ARM::LDRH;
- case 3: // Pre-indexed
- return ARM::LDRH_PRE;
- case 0: // Post-indexed
- return ARM::LDRH_POST;
- default:
- break; // fallthrough
- }
+ Inst.addOperand(MCOperand::CreateImm(coproc));
+ Inst.addOperand(MCOperand::CreateImm(CRd));
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ switch (Inst.getOpcode()) {
+ case ARM::LDC_OPTION:
+ case ARM::LDCL_OPTION:
+ case ARM::LDC2_OPTION:
+ case ARM::LDC2L_OPTION:
+ case ARM::STC_OPTION:
+ case ARM::STCL_OPTION:
+ case ARM::STC2_OPTION:
+ case ARM::STC2L_OPTION:
+ case ARM::LDCL_POST:
+ case ARM::STCL_POST:
break;
- case 13:
- switch (PW) {
- case 2: // Offset
- return ARM::LDRSB;
- case 3: // Pre-indexed
- return ARM::LDRSB_PRE;
- case 0: // Post-indexed
- return ARM::LDRSB_POST;
- default:
- break; // fallthrough
- }
+ default:
+ Inst.addOperand(MCOperand::CreateReg(0));
break;
- case 15:
- switch (PW) {
- case 2: // Offset
- return ARM::LDRSH;
- case 3: // Pre-indexed
- return ARM::LDRSH_PRE;
- case 0: // Post-indexed
- return ARM::LDRSH_POST;
- default:
- break; // fallthrough
- }
+ }
+
+ unsigned P = fieldFromInstruction32(Insn, 24, 1);
+ unsigned W = fieldFromInstruction32(Insn, 21, 1);
+
+ bool writeback = (P == 0) || (W == 1);
+ unsigned idx_mode = 0;
+ if (P && writeback)
+ idx_mode = ARMII::IndexModePre;
+ else if (!P && writeback)
+ idx_mode = ARMII::IndexModePost;
+
+ switch (Inst.getOpcode()) {
+ case ARM::LDCL_POST:
+ case ARM::STCL_POST:
+ imm |= U << 8;
+ case ARM::LDC_OPTION:
+ case ARM::LDCL_OPTION:
+ case ARM::LDC2_OPTION:
+ case ARM::LDC2L_OPTION:
+ case ARM::STC_OPTION:
+ case ARM::STCL_OPTION:
+ case ARM::STC2_OPTION:
+ case ARM::STC2L_OPTION:
+ Inst.addOperand(MCOperand::CreateImm(imm));
break;
default:
- break; // fallthrough
- }
+ if (U)
+ Inst.addOperand(MCOperand::CreateImm(
+ ARM_AM::getAM2Opc(ARM_AM::add, imm, ARM_AM::lsl, idx_mode)));
+ else
+ Inst.addOperand(MCOperand::CreateImm(
+ ARM_AM::getAM2Opc(ARM_AM::sub, imm, ARM_AM::lsl, idx_mode)));
+ break;
}
-AutoGenedDecoder:
- // Calling the auto-generated decoder function.
- return decodeInstruction(insn);
-}
-
-// Helper function for special case handling of LDR (literal) and friends.
-// See, for example, A6.3.7 Load word: Table A6-18 Load word.
-// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode
-// before returning it.
-static unsigned T2Morph2LoadLiteral(unsigned Opcode) {
- switch (Opcode) {
- default:
- return Opcode; // Return unmorphed opcode.
-
- case ARM::t2LDR_POST: case ARM::t2LDR_PRE:
- case ARM::t2LDRi12: case ARM::t2LDRi8:
- case ARM::t2LDRs: case ARM::t2LDRT:
- return ARM::t2LDRpci;
-
- case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE:
- case ARM::t2LDRBi12: case ARM::t2LDRBi8:
- case ARM::t2LDRBs: case ARM::t2LDRBT:
- return ARM::t2LDRBpci;
-
- case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE:
- case ARM::t2LDRHi12: case ARM::t2LDRHi8:
- case ARM::t2LDRHs: case ARM::t2LDRHT:
- return ARM::t2LDRHpci;
-
- case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE:
- case ARM::t2LDRSBi12: case ARM::t2LDRSBi8:
- case ARM::t2LDRSBs: case ARM::t2LDRSBT:
- return ARM::t2LDRSBpci;
-
- case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE:
- case ARM::t2LDRSHi12: case ARM::t2LDRSHi8:
- case ARM::t2LDRSHs: case ARM::t2LDRSHT:
- return ARM::t2LDRSHpci;
- }
-}
-
-// Helper function for special case handling of PLD (literal) and friends.
-// See A8.6.117 T1 & T2 and friends for why we morphed the opcode
-// before returning it.
-static unsigned T2Morph2PLDLiteral(unsigned Opcode) {
- switch (Opcode) {
- default:
- return Opcode; // Return unmorphed opcode.
-
- case ARM::t2PLDi8: case ARM::t2PLDs:
- case ARM::t2PLDWi12: case ARM::t2PLDWi8:
- case ARM::t2PLDWs:
- return ARM::t2PLDi12;
-
- case ARM::t2PLIi8: case ARM::t2PLIs:
- return ARM::t2PLIi12;
- }
-}
-
-/// decodeThumbSideEffect is a decorator function which can potentially twiddle
-/// the instruction or morph the returned opcode under Thumb2.
-///
-/// First it checks whether the insn is a NEON or VFP instr; if true, bit
-/// twiddling could be performed on insn to turn it into an ARM NEON/VFP
-/// equivalent instruction and decodeInstruction is called with the transformed
-/// insn.
-///
-/// Next, there is special handling for Load byte/halfword/word instruction by
-/// checking whether Rn=0b1111 and call T2Morph2LoadLiteral() on the decoded
-/// Thumb2 instruction. See comments below for further details.
-///
-/// Finally, one last check is made to see whether the insn is a NEON/VFP and
-/// decodeInstruction(insn) is invoked on the original insn.
-///
-/// Otherwise, decodeThumbInstruction is called with the original insn.
-static unsigned decodeThumbSideEffect(bool IsThumb2, unsigned &insn) {
- if (IsThumb2) {
- uint16_t op1 = slice(insn, 28, 27);
- uint16_t op2 = slice(insn, 26, 20);
-
- // A6.3 32-bit Thumb instruction encoding
- // Table A6-9 32-bit Thumb instruction encoding
-
- // The coprocessor instructions of interest are transformed to their ARM
- // equivalents.
-
- // --------- Transform Begin Marker ---------
- if ((op1 == 1 || op1 == 3) && slice(op2, 6, 4) == 7) {
- // A7.4 Advanced SIMD data-processing instructions
- // U bit of Thumb corresponds to Inst{24} of ARM.
- uint16_t U = slice(op1, 1, 1);
-
- // Inst{28-24} of ARM = {1,0,0,1,U};
- uint16_t bits28_24 = 9 << 1 | U;
- DEBUG(showBitVector(errs(), insn));
- setSlice(insn, 28, 24, bits28_24);
- return decodeInstruction(insn);
+ switch (Inst.getOpcode()) {
+ case ARM::LDC_OFFSET:
+ case ARM::LDC_PRE:
+ case ARM::LDC_POST:
+ case ARM::LDC_OPTION:
+ case ARM::LDCL_OFFSET:
+ case ARM::LDCL_PRE:
+ case ARM::LDCL_POST:
+ case ARM::LDCL_OPTION:
+ case ARM::STC_OFFSET:
+ case ARM::STC_PRE:
+ case ARM::STC_POST:
+ case ARM::STC_OPTION:
+ case ARM::STCL_OFFSET:
+ case ARM::STCL_PRE:
+ case ARM::STCL_POST:
+ case ARM::STCL_OPTION:
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder)) return false;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool DecodeAddrMode2IdxInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned imm = fieldFromInstruction32(Insn, 0, 12);
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+ unsigned reg = fieldFromInstruction32(Insn, 25, 1);
+ unsigned P = fieldFromInstruction32(Insn, 24, 1);
+ unsigned W = fieldFromInstruction32(Insn, 21, 1);
+
+ // On stores, the writeback operand precedes Rt.
+ switch (Inst.getOpcode()) {
+ case ARM::STR_POST_IMM:
+ case ARM::STR_POST_REG:
+ case ARM::STRTr:
+ case ARM::STRTi:
+ case ARM::STRBTr:
+ case ARM::STRBTi:
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ DecodeGPRRegisterClass(Inst, Rt, Address, Decoder);
+
+ // On loads, the writeback operand comes after Rt.
+ switch (Inst.getOpcode()) {
+ case ARM::LDR_POST_IMM:
+ case ARM::LDR_POST_REG:
+ case ARM::LDR_PRE:
+ case ARM::LDRBT_POST_REG:
+ case ARM::LDRBT_POST_IMM:
+ case ARM::LDRTr:
+ case ARM::LDRTi:
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ ARM_AM::AddrOpc Op = ARM_AM::add;
+ if (!fieldFromInstruction32(Insn, 23, 1))
+ Op = ARM_AM::sub;
+
+ bool writeback = (P == 0) || (W == 1);
+ unsigned idx_mode = 0;
+ if (P && writeback)
+ idx_mode = ARMII::IndexModePre;
+ else if (!P && writeback)
+ idx_mode = ARMII::IndexModePost;
+
+ if (reg) {
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ ARM_AM::ShiftOpc Opc = ARM_AM::lsl;
+ switch( fieldFromInstruction32(Insn, 5, 2)) {
+ case 0:
+ Opc = ARM_AM::lsl;
+ break;
+ case 1:
+ Opc = ARM_AM::lsr;
+ break;
+ case 2:
+ Opc = ARM_AM::asr;
+ break;
+ case 3:
+ Opc = ARM_AM::ror;
+ break;
+ default:
+ return false;
}
+ unsigned amt = fieldFromInstruction32(Insn, 7, 5);
+ unsigned imm = ARM_AM::getAM2Opc(Op, amt, Opc, idx_mode);
+
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ } else {
+ Inst.addOperand(MCOperand::CreateReg(0));
+ unsigned tmp = ARM_AM::getAM2Opc(Op, imm, ARM_AM::lsl, idx_mode);
+ Inst.addOperand(MCOperand::CreateImm(tmp));
+ }
+
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder)) return false;
+
+ return true;
+}
- if (op1 == 3 && slice(op2, 6, 4) == 1 && slice(op2, 0, 0) == 0) {
- // A7.7 Advanced SIMD element or structure load/store instructions
- // Inst{27-24} of Thumb = 0b1001
- // Inst{27-24} of ARM = 0b0100
- DEBUG(showBitVector(errs(), insn));
- setSlice(insn, 27, 24, 4);
- return decodeInstruction(insn);
+static bool DecodeSORegMemOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 13, 4);
+ unsigned Rm = fieldFromInstruction32(Val, 0, 4);
+ unsigned type = fieldFromInstruction32(Val, 5, 2);
+ unsigned imm = fieldFromInstruction32(Val, 7, 5);
+ unsigned U = fieldFromInstruction32(Val, 12, 1);
+
+ ARM_AM::ShiftOpc ShOp;
+ switch (type) {
+ case 0:
+ ShOp = ARM_AM::lsl;
+ break;
+ case 1:
+ ShOp = ARM_AM::lsr;
+ break;
+ case 2:
+ ShOp = ARM_AM::asr;
+ break;
+ case 3:
+ ShOp = ARM_AM::ror;
+ break;
+ }
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ unsigned shift;
+ if (U)
+ shift = ARM_AM::getAM2Opc(ARM_AM::add, imm, ShOp);
+ else
+ shift = ARM_AM::getAM2Opc(ARM_AM::sub, imm, ShOp);
+ Inst.addOperand(MCOperand::CreateImm(shift));
+
+ return true;
+}
+
+static bool DecodeAddrMode3Instruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned type = fieldFromInstruction32(Insn, 22, 1);
+ unsigned imm = fieldFromInstruction32(Insn, 8, 4);
+ unsigned U = ((~fieldFromInstruction32(Insn, 23, 1)) & 1) << 8;
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+ unsigned W = fieldFromInstruction32(Insn, 21, 1);
+ unsigned P = fieldFromInstruction32(Insn, 24, 1);
+
+ bool writeback = (W == 1) | (P == 0);
+ if (writeback) { // Writeback
+ if (P)
+ U |= ARMII::IndexModePre << 9;
+ else
+ U |= ARMII::IndexModePost << 9;
+
+ // On stores, the writeback operand precedes Rt.
+ switch (Inst.getOpcode()) {
+ case ARM::STRD:
+ case ARM::STRD_PRE:
+ case ARM::STRD_POST:
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ break;
+ default:
+ break;
}
- // --------- Transform End Marker ---------
-
- unsigned unmorphed = decodeThumbInstruction(insn);
-
- // See, for example, A6.3.7 Load word: Table A6-18 Load word.
- // See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode
- // before returning it to our caller.
- if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1
- && slice(insn, 19, 16) == 15) {
- unsigned morphed = T2Morph2LoadLiteral(unmorphed);
- if (morphed != unmorphed)
- return morphed;
+ }
+
+ DecodeGPRRegisterClass(Inst, Rt, Address, Decoder);
+ switch (Inst.getOpcode()) {
+ case ARM::STRD:
+ case ARM::STRD_PRE:
+ case ARM::STRD_POST:
+ case ARM::LDRD:
+ case ARM::LDRD_PRE:
+ case ARM::LDRD_POST:
+ DecodeGPRRegisterClass(Inst, Rt+1, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ if (writeback) {
+ // On loads, the writeback operand comes after Rt.
+ switch (Inst.getOpcode()) {
+ case ARM::LDRD:
+ case ARM::LDRD_PRE:
+ case ARM::LDRD_POST:
+ case ARM::LDRHTr:
+ case ARM::LDRSBTr:
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ break;
+ default:
+ break;
}
+ }
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ if (type) {
+ Inst.addOperand(MCOperand::CreateReg(0));
+ Inst.addOperand(MCOperand::CreateImm(U | (imm << 4) | Rm));
+ } else {
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(U));
+ }
+
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder)) return false;
+
+ return true;
+}
+
+static bool DecodeRFEInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned mode = fieldFromInstruction32(Insn, 23, 2);
+
+ switch (mode) {
+ case 0:
+ mode = ARM_AM::da;
+ break;
+ case 1:
+ mode = ARM_AM::ia;
+ break;
+ case 2:
+ mode = ARM_AM::db;
+ break;
+ case 3:
+ mode = ARM_AM::ib;
+ break;
+ }
+
+ Inst.addOperand(MCOperand::CreateImm(mode));
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeMemMultipleWritebackInstruction(llvm::MCInst &Inst,
+ unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+ unsigned reglist = fieldFromInstruction32(Insn, 0, 16);
+
+ if (pred == 0xF) {
+ switch (Inst.getOpcode()) {
+ case ARM::STMDA:
+ Inst.setOpcode(ARM::RFEDA);
+ break;
+ case ARM::STMDA_UPD:
+ Inst.setOpcode(ARM::RFEDA_UPD);
+ break;
+ case ARM::STMDB:
+ Inst.setOpcode(ARM::RFEDB);
+ break;
+ case ARM::STMDB_UPD:
+ Inst.setOpcode(ARM::RFEDB_UPD);
+ break;
+ case ARM::STMIA:
+ Inst.setOpcode(ARM::RFEIA);
+ break;
+ case ARM::STMIA_UPD:
+ Inst.setOpcode(ARM::RFEIA_UPD);
+ break;
+ case ARM::STMIB:
+ Inst.setOpcode(ARM::RFEIB);
+ break;
+ case ARM::STMIB_UPD:
+ Inst.setOpcode(ARM::RFEIB_UPD);
+ break;
- // See, for example, A8.6.117 PLD,PLDW (immediate) T1 & T2, and friends for
- // why we morphed the opcode before returning it to our caller.
- if (slice(insn, 31, 25) == 0x7C && slice(insn, 15, 12) == 0xF
- && slice(insn, 22, 22) == 0 && slice(insn, 20, 20) == 1
- && slice(insn, 19, 16) == 15) {
- unsigned morphed = T2Morph2PLDLiteral(unmorphed);
- if (morphed != unmorphed)
- return morphed;
}
+ return DecodeRFEInstruction(Inst, Insn, Address, Decoder);
+ }
- // One last check for NEON/VFP instructions.
- if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1)
- return decodeInstruction(insn);
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder); // Tied
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder)) return false;
+ DecodeRegListOperand(Inst, reglist, Address, Decoder);
- // Fall through.
+ return true;
+}
+
+static bool DecodeCPSInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned imod = fieldFromInstruction32(Insn, 18, 2);
+ unsigned M = fieldFromInstruction32(Insn, 17, 1);
+ unsigned iflags = fieldFromInstruction32(Insn, 6, 3);
+ unsigned mode = fieldFromInstruction32(Insn, 0, 5);
+
+ if (M && mode && imod && iflags) {
+ Inst.setOpcode(ARM::CPS3p);
+ Inst.addOperand(MCOperand::CreateImm(imod));
+ Inst.addOperand(MCOperand::CreateImm(iflags));
+ Inst.addOperand(MCOperand::CreateImm(mode));
+ return true;
+ } else if (!mode && !M) {
+ Inst.setOpcode(ARM::CPS2p);
+ Inst.addOperand(MCOperand::CreateImm(imod));
+ Inst.addOperand(MCOperand::CreateImm(iflags));
+ return true;
+ } else if (!imod && !iflags && M) {
+ Inst.setOpcode(ARM::CPS1p);
+ Inst.addOperand(MCOperand::CreateImm(mode));
+ return true;
}
- return decodeThumbInstruction(insn);
+ return false;
}
-//
-// Public interface for the disassembler
-//
+static bool DecodeSMLAInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rn = fieldFromInstruction32(Insn, 0, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 8, 4);
+ unsigned Ra = fieldFromInstruction32(Insn, 12, 4);
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
-bool ARMDisassembler::getInstruction(MCInst &MI,
- uint64_t &Size,
- const MemoryObject &Region,
- uint64_t Address,
- raw_ostream &os) const {
- // The machine instruction.
- uint32_t insn;
- uint8_t bytes[4];
+ if (pred == 0xF)
+ return DecodeCPSInstruction(Inst, Insn, Address, Decoder);
- // We want to read exactly 4 bytes of data.
- if (Region.readBytes(Address, 4, (uint8_t*)bytes, NULL) == -1)
- return false;
+ DecodeGPRRegisterClass(Inst, Rd, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, Ra, Address, Decoder);
- // Encoded as a small-endian 32-bit word in the stream.
- insn = (bytes[3] << 24) |
- (bytes[2] << 16) |
- (bytes[1] << 8) |
- (bytes[0] << 0);
-
- unsigned Opcode = decodeARMInstruction(insn);
- ARMFormat Format = ARMFormats[Opcode];
- Size = 4;
-
- DEBUG({
- errs() << "\nOpcode=" << Opcode << " Name=" <<ARMUtils::OpcodeName(Opcode)
- << " Format=" << stringForARMFormat(Format) << '(' << (int)Format
- << ")\n";
- showBitVector(errs(), insn);
- });
-
- OwningPtr<ARMBasicMCBuilder> Builder(CreateMCBuilder(Opcode, Format));
- if (!Builder)
- return false;
+ return true;
+}
- Builder->setupBuilderForSymbolicDisassembly(getLLVMOpInfoCallback(),
- getDisInfoBlock(), getMCContext(),
- Address);
+static bool DecodeAddrModeImm12Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned add = fieldFromInstruction32(Val, 12, 1);
+ unsigned imm = fieldFromInstruction32(Val, 0, 12);
+ unsigned Rn = fieldFromInstruction32(Val, 13, 4);
- if (!Builder->Build(MI, insn))
- return false;
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ if (!add) imm *= -1;
+ if (imm == 0 && !add) imm = INT32_MIN;
+ Inst.addOperand(MCOperand::CreateImm(imm));
return true;
}
-bool ThumbDisassembler::getInstruction(MCInst &MI,
- uint64_t &Size,
- const MemoryObject &Region,
- uint64_t Address,
- raw_ostream &os) const {
- // The Thumb instruction stream is a sequence of halfwords.
-
- // This represents the first halfword as well as the machine instruction
- // passed to decodeThumbInstruction(). For 16-bit Thumb instruction, the top
- // halfword of insn is 0x00 0x00; otherwise, the first halfword is moved to
- // the top half followed by the second halfword.
- unsigned insn = 0;
- // Possible second halfword.
- uint16_t insn1 = 0;
-
- // A6.1 Thumb instruction set encoding
- //
- // If bits [15:11] of the halfword being decoded take any of the following
- // values, the halfword is the first halfword of a 32-bit instruction:
- // o 0b11101
- // o 0b11110
- // o 0b11111.
- //
- // Otherwise, the halfword is a 16-bit instruction.
-
- // Read 2 bytes of data first.
- uint8_t bytes[2];
- if (Region.readBytes(Address, 2, (uint8_t*)bytes, NULL) == -1)
- return false;
+static bool DecodeAddrMode5Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 9, 4);
+ unsigned U = fieldFromInstruction32(Val, 8, 1);
+ unsigned imm = fieldFromInstruction32(Val, 0, 8);
- // Encoded as a small-endian 16-bit halfword in the stream.
- insn = (bytes[1] << 8) | bytes[0];
- unsigned bits15_11 = slice(insn, 15, 11);
- bool IsThumb2 = false;
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
- // 32-bit instructions if the bits [15:11] of the halfword matches
- // { 0b11101 /* 0x1D */, 0b11110 /* 0x1E */, ob11111 /* 0x1F */ }.
- if (bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) {
- IsThumb2 = true;
- if (Region.readBytes(Address + 2, 2, (uint8_t*)bytes, NULL) == -1)
- return false;
- // Encoded as a small-endian 16-bit halfword in the stream.
- insn1 = (bytes[1] << 8) | bytes[0];
- insn = (insn << 16 | insn1);
- }
-
- // The insn could potentially be bit-twiddled in order to be decoded as an ARM
- // NEON/VFP opcode. In such case, the modified insn is later disassembled as
- // an ARM NEON/VFP instruction.
- //
- // This is a short term solution for lack of encoding bits specified for the
- // Thumb2 NEON/VFP instructions. The long term solution could be adding some
- // infrastructure to have each instruction support more than one encodings.
- // Which encoding is used would be based on which subtarget the compiler/
- // disassembler is working with at the time. This would allow the sharing of
- // the NEON patterns between ARM and Thumb2, as well as potential greater
- // sharing between the regular ARM instructions and the 32-bit wide Thumb2
- // instructions as well.
- unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn);
-
- ARMFormat Format = ARMFormats[Opcode];
- Size = IsThumb2 ? 4 : 2;
-
- DEBUG({
- errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode)
- << " Format=" << stringForARMFormat(Format) << '(' << (int)Format
- << ")\n";
- showBitVector(errs(), insn);
- });
-
- OwningPtr<ARMBasicMCBuilder> Builder(CreateMCBuilder(Opcode, Format));
- if (!Builder)
- return false;
+ if (U)
+ Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add, imm)));
+ else
+ Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub, imm)));
+
+ return true;
+}
- Builder->SetSession(const_cast<Session *>(&SO));
+static bool DecodeAddrMode7Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ return DecodeGPRRegisterClass(Inst, Val, Address, Decoder);
+}
- Builder->setupBuilderForSymbolicDisassembly(getLLVMOpInfoCallback(),
- getDisInfoBlock(), getMCContext(),
- Address);
+static bool DecodeBranchImmInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned pred = fieldFromInstruction32(Insn, 28, 4);
+ unsigned imm = fieldFromInstruction32(Insn, 0, 24) << 2;
- if (!Builder->Build(MI, insn))
- return false;
+ if (pred == 0xF) {
+ Inst.setOpcode(ARM::BLXi);
+ imm |= fieldFromInstruction32(Insn, 24, 1) << 1;
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ return true;
+ }
+
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder)) return false;
return true;
}
-// A8.6.50
-// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
-static unsigned short CountITSize(unsigned ITMask) {
- // First count the trailing zeros of the IT mask.
- unsigned TZ = CountTrailingZeros_32(ITMask);
- if (TZ > 3) {
- DEBUG(errs() << "Encoding error: IT Mask '0000'");
- return 0;
+
+static bool DecodeVCVTImmOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(64 - Val));
+ return true;
+}
+
+static bool DecodeAddrMode6Operand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rm = fieldFromInstruction32(Val, 0, 4);
+ unsigned align = fieldFromInstruction32(Val, 4, 2);
+
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ if (!align)
+ Inst.addOperand(MCOperand::CreateImm(0));
+ else
+ Inst.addOperand(MCOperand::CreateImm(4 << align));
+
+ return true;
+}
+
+static bool DecodeVLDInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned wb = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ Rn |= fieldFromInstruction32(Insn, 4, 2) << 4;
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+
+ // First output register
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+
+ // Second output register
+ switch (Inst.getOpcode()) {
+ case ARM::VLD1q8:
+ case ARM::VLD1q16:
+ case ARM::VLD1q32:
+ case ARM::VLD1q64:
+ case ARM::VLD1q8_UPD:
+ case ARM::VLD1q16_UPD:
+ case ARM::VLD1q32_UPD:
+ case ARM::VLD1q64_UPD:
+ case ARM::VLD1d8T:
+ case ARM::VLD1d16T:
+ case ARM::VLD1d32T:
+ case ARM::VLD1d64T:
+ case ARM::VLD1d8T_UPD:
+ case ARM::VLD1d16T_UPD:
+ case ARM::VLD1d32T_UPD:
+ case ARM::VLD1d64T_UPD:
+ case ARM::VLD1d8Q:
+ case ARM::VLD1d16Q:
+ case ARM::VLD1d32Q:
+ case ARM::VLD1d64Q:
+ case ARM::VLD1d8Q_UPD:
+ case ARM::VLD1d16Q_UPD:
+ case ARM::VLD1d32Q_UPD:
+ case ARM::VLD1d64Q_UPD:
+ case ARM::VLD2d8:
+ case ARM::VLD2d16:
+ case ARM::VLD2d32:
+ case ARM::VLD2d8_UPD:
+ case ARM::VLD2d16_UPD:
+ case ARM::VLD2d32_UPD:
+ case ARM::VLD2q8:
+ case ARM::VLD2q16:
+ case ARM::VLD2q32:
+ case ARM::VLD2q8_UPD:
+ case ARM::VLD2q16_UPD:
+ case ARM::VLD2q32_UPD:
+ case ARM::VLD3d8:
+ case ARM::VLD3d16:
+ case ARM::VLD3d32:
+ case ARM::VLD3d8_UPD:
+ case ARM::VLD3d16_UPD:
+ case ARM::VLD3d32_UPD:
+ case ARM::VLD4d8:
+ case ARM::VLD4d16:
+ case ARM::VLD4d32:
+ case ARM::VLD4d8_UPD:
+ case ARM::VLD4d16_UPD:
+ case ARM::VLD4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+1)%32, Address, Decoder);
+ break;
+ case ARM::VLD2b8:
+ case ARM::VLD2b16:
+ case ARM::VLD2b32:
+ case ARM::VLD2b8_UPD:
+ case ARM::VLD2b16_UPD:
+ case ARM::VLD2b32_UPD:
+ case ARM::VLD3q8:
+ case ARM::VLD3q16:
+ case ARM::VLD3q32:
+ case ARM::VLD3q8_UPD:
+ case ARM::VLD3q16_UPD:
+ case ARM::VLD3q32_UPD:
+ case ARM::VLD4q8:
+ case ARM::VLD4q16:
+ case ARM::VLD4q32:
+ case ARM::VLD4q8_UPD:
+ case ARM::VLD4q16_UPD:
+ case ARM::VLD4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+2)%32, Address, Decoder);
+ default:
+ break;
+ }
+
+ // Third output register
+ switch(Inst.getOpcode()) {
+ case ARM::VLD1d8T:
+ case ARM::VLD1d16T:
+ case ARM::VLD1d32T:
+ case ARM::VLD1d64T:
+ case ARM::VLD1d8T_UPD:
+ case ARM::VLD1d16T_UPD:
+ case ARM::VLD1d32T_UPD:
+ case ARM::VLD1d64T_UPD:
+ case ARM::VLD1d8Q:
+ case ARM::VLD1d16Q:
+ case ARM::VLD1d32Q:
+ case ARM::VLD1d64Q:
+ case ARM::VLD1d8Q_UPD:
+ case ARM::VLD1d16Q_UPD:
+ case ARM::VLD1d32Q_UPD:
+ case ARM::VLD1d64Q_UPD:
+ case ARM::VLD2q8:
+ case ARM::VLD2q16:
+ case ARM::VLD2q32:
+ case ARM::VLD2q8_UPD:
+ case ARM::VLD2q16_UPD:
+ case ARM::VLD2q32_UPD:
+ case ARM::VLD3d8:
+ case ARM::VLD3d16:
+ case ARM::VLD3d32:
+ case ARM::VLD3d8_UPD:
+ case ARM::VLD3d16_UPD:
+ case ARM::VLD3d32_UPD:
+ case ARM::VLD4d8:
+ case ARM::VLD4d16:
+ case ARM::VLD4d32:
+ case ARM::VLD4d8_UPD:
+ case ARM::VLD4d16_UPD:
+ case ARM::VLD4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+2)%32, Address, Decoder);
+ break;
+ case ARM::VLD3q8:
+ case ARM::VLD3q16:
+ case ARM::VLD3q32:
+ case ARM::VLD3q8_UPD:
+ case ARM::VLD3q16_UPD:
+ case ARM::VLD3q32_UPD:
+ case ARM::VLD4q8:
+ case ARM::VLD4q16:
+ case ARM::VLD4q32:
+ case ARM::VLD4q8_UPD:
+ case ARM::VLD4q16_UPD:
+ case ARM::VLD4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+4)%32, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ // Fourth output register
+ switch (Inst.getOpcode()) {
+ case ARM::VLD1d8Q:
+ case ARM::VLD1d16Q:
+ case ARM::VLD1d32Q:
+ case ARM::VLD1d64Q:
+ case ARM::VLD1d8Q_UPD:
+ case ARM::VLD1d16Q_UPD:
+ case ARM::VLD1d32Q_UPD:
+ case ARM::VLD1d64Q_UPD:
+ case ARM::VLD2q8:
+ case ARM::VLD2q16:
+ case ARM::VLD2q32:
+ case ARM::VLD2q8_UPD:
+ case ARM::VLD2q16_UPD:
+ case ARM::VLD2q32_UPD:
+ case ARM::VLD4d8:
+ case ARM::VLD4d16:
+ case ARM::VLD4d32:
+ case ARM::VLD4d8_UPD:
+ case ARM::VLD4d16_UPD:
+ case ARM::VLD4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+3)%32, Address, Decoder);
+ break;
+ case ARM::VLD4q8:
+ case ARM::VLD4q16:
+ case ARM::VLD4q32:
+ case ARM::VLD4q8_UPD:
+ case ARM::VLD4q16_UPD:
+ case ARM::VLD4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+6)%32, Address, Decoder);
+ break;
+ default:
+ break;
}
- return (4 - TZ);
+
+ // Writeback operand
+ switch (Inst.getOpcode()) {
+ case ARM::VLD1d8_UPD:
+ case ARM::VLD1d16_UPD:
+ case ARM::VLD1d32_UPD:
+ case ARM::VLD1d64_UPD:
+ case ARM::VLD1q8_UPD:
+ case ARM::VLD1q16_UPD:
+ case ARM::VLD1q32_UPD:
+ case ARM::VLD1q64_UPD:
+ case ARM::VLD1d8T_UPD:
+ case ARM::VLD1d16T_UPD:
+ case ARM::VLD1d32T_UPD:
+ case ARM::VLD1d64T_UPD:
+ case ARM::VLD1d8Q_UPD:
+ case ARM::VLD1d16Q_UPD:
+ case ARM::VLD1d32Q_UPD:
+ case ARM::VLD1d64Q_UPD:
+ case ARM::VLD2d8_UPD:
+ case ARM::VLD2d16_UPD:
+ case ARM::VLD2d32_UPD:
+ case ARM::VLD2q8_UPD:
+ case ARM::VLD2q16_UPD:
+ case ARM::VLD2q32_UPD:
+ case ARM::VLD2b8_UPD:
+ case ARM::VLD2b16_UPD:
+ case ARM::VLD2b32_UPD:
+ case ARM::VLD3d8_UPD:
+ case ARM::VLD3d16_UPD:
+ case ARM::VLD3d32_UPD:
+ case ARM::VLD3q8_UPD:
+ case ARM::VLD3q16_UPD:
+ case ARM::VLD3q32_UPD:
+ case ARM::VLD4d8_UPD:
+ case ARM::VLD4d16_UPD:
+ case ARM::VLD4d32_UPD:
+ case ARM::VLD4q8_UPD:
+ case ARM::VLD4q16_UPD:
+ case ARM::VLD4q32_UPD:
+ DecodeGPRRegisterClass(Inst, wb, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ // AddrMode6 Base (register+alignment)
+ DecodeAddrMode6Operand(Inst, Rn, Address, Decoder);
+
+ // AddrMode6 Offset (register)
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
}
-/// Init ITState. Note that at least one bit is always 1 in mask.
-bool Session::InitIT(unsigned short bits7_0) {
- ITCounter = CountITSize(slice(bits7_0, 3, 0));
- if (ITCounter == 0)
- return false;
+static bool DecodeVSTInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned wb = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ Rn |= fieldFromInstruction32(Insn, 4, 2) << 4;
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+
+ // Writeback Operand
+ switch (Inst.getOpcode()) {
+ case ARM::VST1d8_UPD:
+ case ARM::VST1d16_UPD:
+ case ARM::VST1d32_UPD:
+ case ARM::VST1d64_UPD:
+ case ARM::VST1q8_UPD:
+ case ARM::VST1q16_UPD:
+ case ARM::VST1q32_UPD:
+ case ARM::VST1q64_UPD:
+ case ARM::VST1d8T_UPD:
+ case ARM::VST1d16T_UPD:
+ case ARM::VST1d32T_UPD:
+ case ARM::VST1d64T_UPD:
+ case ARM::VST1d8Q_UPD:
+ case ARM::VST1d16Q_UPD:
+ case ARM::VST1d32Q_UPD:
+ case ARM::VST1d64Q_UPD:
+ case ARM::VST2d8_UPD:
+ case ARM::VST2d16_UPD:
+ case ARM::VST2d32_UPD:
+ case ARM::VST2q8_UPD:
+ case ARM::VST2q16_UPD:
+ case ARM::VST2q32_UPD:
+ case ARM::VST2b8_UPD:
+ case ARM::VST2b16_UPD:
+ case ARM::VST2b32_UPD:
+ case ARM::VST3d8_UPD:
+ case ARM::VST3d16_UPD:
+ case ARM::VST3d32_UPD:
+ case ARM::VST3q8_UPD:
+ case ARM::VST3q16_UPD:
+ case ARM::VST3q32_UPD:
+ case ARM::VST4d8_UPD:
+ case ARM::VST4d16_UPD:
+ case ARM::VST4d32_UPD:
+ case ARM::VST4q8_UPD:
+ case ARM::VST4q16_UPD:
+ case ARM::VST4q32_UPD:
+ DecodeGPRRegisterClass(Inst, wb, Address, Decoder);
+ break;
+ default:
+ break;
+ }
- // A8.6.50 IT
- unsigned short FirstCond = slice(bits7_0, 7, 4);
- if (FirstCond == 0xF) {
- DEBUG(errs() << "Encoding error: IT FirstCond '1111'");
- return false;
+ // AddrMode6 Base (register+alignment)
+ DecodeAddrMode6Operand(Inst, Rn, Address, Decoder);
+
+ // AddrMode6 Offset (register)
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ // First input register
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+
+ // Second input register
+ switch (Inst.getOpcode()) {
+ case ARM::VST1q8:
+ case ARM::VST1q16:
+ case ARM::VST1q32:
+ case ARM::VST1q64:
+ case ARM::VST1q8_UPD:
+ case ARM::VST1q16_UPD:
+ case ARM::VST1q32_UPD:
+ case ARM::VST1q64_UPD:
+ case ARM::VST1d8T:
+ case ARM::VST1d16T:
+ case ARM::VST1d32T:
+ case ARM::VST1d64T:
+ case ARM::VST1d8T_UPD:
+ case ARM::VST1d16T_UPD:
+ case ARM::VST1d32T_UPD:
+ case ARM::VST1d64T_UPD:
+ case ARM::VST1d8Q:
+ case ARM::VST1d16Q:
+ case ARM::VST1d32Q:
+ case ARM::VST1d64Q:
+ case ARM::VST1d8Q_UPD:
+ case ARM::VST1d16Q_UPD:
+ case ARM::VST1d32Q_UPD:
+ case ARM::VST1d64Q_UPD:
+ case ARM::VST2d8:
+ case ARM::VST2d16:
+ case ARM::VST2d32:
+ case ARM::VST2d8_UPD:
+ case ARM::VST2d16_UPD:
+ case ARM::VST2d32_UPD:
+ case ARM::VST2q8:
+ case ARM::VST2q16:
+ case ARM::VST2q32:
+ case ARM::VST2q8_UPD:
+ case ARM::VST2q16_UPD:
+ case ARM::VST2q32_UPD:
+ case ARM::VST3d8:
+ case ARM::VST3d16:
+ case ARM::VST3d32:
+ case ARM::VST3d8_UPD:
+ case ARM::VST3d16_UPD:
+ case ARM::VST3d32_UPD:
+ case ARM::VST4d8:
+ case ARM::VST4d16:
+ case ARM::VST4d32:
+ case ARM::VST4d8_UPD:
+ case ARM::VST4d16_UPD:
+ case ARM::VST4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+1)%32, Address, Decoder);
+ break;
+ case ARM::VST2b8:
+ case ARM::VST2b16:
+ case ARM::VST2b32:
+ case ARM::VST2b8_UPD:
+ case ARM::VST2b16_UPD:
+ case ARM::VST2b32_UPD:
+ case ARM::VST3q8:
+ case ARM::VST3q16:
+ case ARM::VST3q32:
+ case ARM::VST3q8_UPD:
+ case ARM::VST3q16_UPD:
+ case ARM::VST3q32_UPD:
+ case ARM::VST4q8:
+ case ARM::VST4q16:
+ case ARM::VST4q32:
+ case ARM::VST4q8_UPD:
+ case ARM::VST4q16_UPD:
+ case ARM::VST4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+2)%32, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ // Third input register
+ switch (Inst.getOpcode()) {
+ case ARM::VST1d8T:
+ case ARM::VST1d16T:
+ case ARM::VST1d32T:
+ case ARM::VST1d64T:
+ case ARM::VST1d8T_UPD:
+ case ARM::VST1d16T_UPD:
+ case ARM::VST1d32T_UPD:
+ case ARM::VST1d64T_UPD:
+ case ARM::VST1d8Q:
+ case ARM::VST1d16Q:
+ case ARM::VST1d32Q:
+ case ARM::VST1d64Q:
+ case ARM::VST1d8Q_UPD:
+ case ARM::VST1d16Q_UPD:
+ case ARM::VST1d32Q_UPD:
+ case ARM::VST1d64Q_UPD:
+ case ARM::VST2q8:
+ case ARM::VST2q16:
+ case ARM::VST2q32:
+ case ARM::VST2q8_UPD:
+ case ARM::VST2q16_UPD:
+ case ARM::VST2q32_UPD:
+ case ARM::VST3d8:
+ case ARM::VST3d16:
+ case ARM::VST3d32:
+ case ARM::VST3d8_UPD:
+ case ARM::VST3d16_UPD:
+ case ARM::VST3d32_UPD:
+ case ARM::VST4d8:
+ case ARM::VST4d16:
+ case ARM::VST4d32:
+ case ARM::VST4d8_UPD:
+ case ARM::VST4d16_UPD:
+ case ARM::VST4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+2)%32, Address, Decoder);
+ break;
+ case ARM::VST3q8:
+ case ARM::VST3q16:
+ case ARM::VST3q32:
+ case ARM::VST3q8_UPD:
+ case ARM::VST3q16_UPD:
+ case ARM::VST3q32_UPD:
+ case ARM::VST4q8:
+ case ARM::VST4q16:
+ case ARM::VST4q32:
+ case ARM::VST4q8_UPD:
+ case ARM::VST4q16_UPD:
+ case ARM::VST4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+4)%32, Address, Decoder);
+ break;
+ default:
+ break;
}
- if (FirstCond == 0xE && ITCounter != 1) {
- DEBUG(errs() << "Encoding error: IT FirstCond '1110' && Mask != '1000'");
+
+ // Fourth input register
+ switch (Inst.getOpcode()) {
+ case ARM::VST1d8Q:
+ case ARM::VST1d16Q:
+ case ARM::VST1d32Q:
+ case ARM::VST1d64Q:
+ case ARM::VST1d8Q_UPD:
+ case ARM::VST1d16Q_UPD:
+ case ARM::VST1d32Q_UPD:
+ case ARM::VST1d64Q_UPD:
+ case ARM::VST2q8:
+ case ARM::VST2q16:
+ case ARM::VST2q32:
+ case ARM::VST2q8_UPD:
+ case ARM::VST2q16_UPD:
+ case ARM::VST2q32_UPD:
+ case ARM::VST4d8:
+ case ARM::VST4d16:
+ case ARM::VST4d32:
+ case ARM::VST4d8_UPD:
+ case ARM::VST4d16_UPD:
+ case ARM::VST4d32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+3)%32, Address, Decoder);
+ break;
+ case ARM::VST4q8:
+ case ARM::VST4q16:
+ case ARM::VST4q32:
+ case ARM::VST4q8_UPD:
+ case ARM::VST4q16_UPD:
+ case ARM::VST4q32_UPD:
+ DecodeDPRRegisterClass(Inst, (Rd+6)%32, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool DecodeVLD1DupInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned align = fieldFromInstruction32(Insn, 4, 1);
+ unsigned size = fieldFromInstruction32(Insn, 6, 2);
+ unsigned regs = fieldFromInstruction32(Insn, 5, 1) + 1;
+
+ align *= (1 << size);
+
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ if (regs == 2) DecodeDPRRegisterClass(Inst, (Rd+1)%32, Address, Decoder);
+ if (Rm == 0xD) DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(align));
+
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeVLD2DupInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned align = fieldFromInstruction32(Insn, 4, 1);
+ unsigned size = 1 << fieldFromInstruction32(Insn, 6, 2);
+ unsigned inc = fieldFromInstruction32(Insn, 5, 1) + 1;
+ align *= 2*size;
+
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+inc)%32, Address, Decoder);
+ if (Rm == 0xD) DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(align));
+
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeVLD3DupInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned inc = fieldFromInstruction32(Insn, 5, 1) + 1;
+
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+inc)%32, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+2*inc)%32, Address, Decoder);
+ if (Rm == 0xD) DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(0));
+
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeVLD4DupInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned size = fieldFromInstruction32(Insn, 6, 2);
+ unsigned inc = fieldFromInstruction32(Insn, 5, 1) + 1;
+ unsigned align = fieldFromInstruction32(Insn, 4, 1);
+
+ if (size == 0x3) {
+ size = 4;
+ align = 16;
+ } else {
+ if (size == 2) {
+ size = 1 << size;
+ align *= 8;
+ } else {
+ size = 1 << size;
+ align *= 4*size;
+ }
+ }
+
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+inc)%32, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+2*inc)%32, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, (Rd+3*inc)%32, Address, Decoder);
+ if (Rm == 0xD) DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(align));
+
+ if (Rm == 0xD)
+ Inst.addOperand(MCOperand::CreateReg(0));
+ else if (Rm != 0xF)
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeNEONModImmInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned imm = fieldFromInstruction32(Insn, 0, 4);
+ imm |= fieldFromInstruction32(Insn, 16, 3) << 4;
+ imm |= fieldFromInstruction32(Insn, 24, 1) << 7;
+ imm |= fieldFromInstruction32(Insn, 8, 4) << 8;
+ imm |= fieldFromInstruction32(Insn, 5, 1) << 12;
+ unsigned Q = fieldFromInstruction32(Insn, 6, 1);
+
+ if (Q)
+ DecodeQPRRegisterClass(Inst, Rd, Address, Decoder);
+ else
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ switch (Inst.getOpcode()) {
+ case ARM::VORRiv4i16:
+ case ARM::VORRiv2i32:
+ case ARM::VBICiv4i16:
+ case ARM::VBICiv2i32:
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ break;
+ case ARM::VORRiv8i16:
+ case ARM::VORRiv4i32:
+ case ARM::VBICiv8i16:
+ case ARM::VBICiv4i32:
+ DecodeQPRRegisterClass(Inst, Rd, Address, Decoder);
+ break;
+ default:
+ break;
+ }
+
+
+ return true;
+}
+
+static bool DecodeVSHLMaxInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ Rm |= fieldFromInstruction32(Insn, 5, 1) << 4;
+ unsigned size = fieldFromInstruction32(Insn, 18, 2);
+
+ DecodeQPRRegisterClass(Inst, Rd, Address, Decoder);
+ DecodeDPRRegisterClass(Inst, Rm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(8 << size));
+
+ return true;
+}
+
+static bool DecodeShiftRight8Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(8 - Val));
+ return true;
+}
+
+static bool DecodeShiftRight16Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(16 - Val));
+ return true;
+}
+
+static bool DecodeShiftRight32Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(32 - Val));
+ return true;
+}
+
+static bool DecodeShiftRight64Imm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(64 - Val));
+ return true;
+}
+
+static bool DecodeTBLInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rd = fieldFromInstruction32(Insn, 12, 4);
+ Rd |= fieldFromInstruction32(Insn, 22, 1) << 4;
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ Rn |= fieldFromInstruction32(Insn, 7, 1) << 4;
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ Rm |= fieldFromInstruction32(Insn, 5, 1) << 4;
+ unsigned op = fieldFromInstruction32(Insn, 6, 1);
+ unsigned length = fieldFromInstruction32(Insn, 8, 2) + 1;
+
+ DecodeDPRRegisterClass(Inst, Rd, Address, Decoder);
+ if (op) DecodeDPRRegisterClass(Inst, Rd, Address, Decoder); // Writeback
+
+ for (unsigned i = 0; i < length; ++i)
+ DecodeDPRRegisterClass(Inst, (Rn+i)%32, Address, Decoder);
+
+ DecodeDPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeVFPfpImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ // The immediate needs to be a fully instantiated float. However, the
+ // auto-generated decoder is only able to fill in some of the bits
+ // necessary. For instance, the 'b' bit is replicated multiple times,
+ // and is even present in inverted form in one bit. We do a little
+ // binary parsing here to fill in those missing bits, and then
+ // reinterpret it all as a float.
+ union {
+ uint32_t integer;
+ float fp;
+ } fp_conv;
+
+ fp_conv.integer = Val;
+ uint32_t b = fieldFromInstruction32(Val, 25, 1);
+ fp_conv.integer |= b << 26;
+ fp_conv.integer |= b << 27;
+ fp_conv.integer |= b << 28;
+ fp_conv.integer |= b << 29;
+ fp_conv.integer |= (~b & 0x1) << 30;
+
+ Inst.addOperand(MCOperand::CreateFPImm(fp_conv.fp));
+ return true;
+}
+
+static bool DecodeThumbAddSpecialReg(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned dst = fieldFromInstruction16(Insn, 8, 3);
+ unsigned imm = fieldFromInstruction16(Insn, 0, 8);
+
+ DecodetGPRRegisterClass(Inst, dst, Address, Decoder);
+
+ if (Inst.getOpcode() == ARM::tADR)
+ Inst.addOperand(MCOperand::CreateReg(ARM::PC));
+ else if (Inst.getOpcode() == ARM::tADDrSPi)
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ else
return false;
+
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ return true;
+}
+
+static bool DecodeThumbBROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<12>(Val << 1)));
+ return true;
+}
+
+static bool DecodeT2BROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<21>(Val)));
+ return true;
+}
+
+static bool DecodeThumbCmpBROperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<7>(Val << 1)));
+ return true;
+}
+
+static bool DecodeThumbAddrModeRR(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 0, 3);
+ unsigned Rm = fieldFromInstruction32(Val, 3, 3);
+
+ DecodetGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodetGPRRegisterClass(Inst, Rm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeThumbAddrModeIS(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 0, 3);
+ unsigned imm = fieldFromInstruction32(Val, 3, 5);
+
+ DecodetGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ return true;
+}
+
+static bool DecodeThumbAddrModePC(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(Val << 2));
+
+ return true;
+}
+
+static bool DecodeThumbAddrModeSP(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ Inst.addOperand(MCOperand::CreateImm(Val << 2));
+
+ return true;
+}
+
+static bool DecodeT2AddrModeSOReg(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 6, 4);
+ unsigned Rm = fieldFromInstruction32(Val, 2, 4);
+ unsigned imm = fieldFromInstruction32(Val, 0, 2);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecoderGPRRegisterClass(Inst, Rm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ return true;
+}
+
+static bool DecodeT2LoadShift(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ if (Inst.getOpcode() != ARM::t2PLDs) {
+ unsigned Rt = fieldFromInstruction32(Insn, 12, 4);
+ DecodeGPRRegisterClass(Inst, Rt, Address, Decoder);
+ }
+
+ unsigned Rn = fieldFromInstruction32(Insn, 16, 4);
+ if (Rn == 0xF) {
+ switch (Inst.getOpcode()) {
+ case ARM::t2LDRBs:
+ Inst.setOpcode(ARM::t2LDRBpci);
+ break;
+ case ARM::t2LDRHs:
+ Inst.setOpcode(ARM::t2LDRHpci);
+ break;
+ case ARM::t2LDRSHs:
+ Inst.setOpcode(ARM::t2LDRSHpci);
+ break;
+ case ARM::t2LDRSBs:
+ Inst.setOpcode(ARM::t2LDRSBpci);
+ break;
+ case ARM::t2PLDs:
+ Inst.setOpcode(ARM::t2PLDi12);
+ Inst.addOperand(MCOperand::CreateReg(ARM::PC));
+ break;
+ default:
+ return false;
+ }
+
+ int imm = fieldFromInstruction32(Insn, 0, 12);
+ if (!fieldFromInstruction32(Insn, 23, 1)) imm *= -1;
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ return true;
+ }
+
+ unsigned addrmode = fieldFromInstruction32(Insn, 4, 2);
+ addrmode |= fieldFromInstruction32(Insn, 0, 4) << 2;
+ addrmode |= fieldFromInstruction32(Insn, 16, 4) << 6;
+ DecodeT2AddrModeSOReg(Inst, addrmode, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeT2Imm8S4(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ int imm = Val & 0xFF;
+ if (!(Val & 0x100)) imm *= -1;
+ Inst.addOperand(MCOperand::CreateImm(imm << 2));
+
+ return true;
+}
+
+static bool DecodeT2AddrModeImm8s4(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 9, 4);
+ unsigned imm = fieldFromInstruction32(Val, 0, 9);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodeT2Imm8S4(Inst, imm, Address, Decoder);
+
+ return true;
+}
+
+static bool DecodeT2Imm8(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ int imm = Val & 0xFF;
+ if (!(Val & 0x100)) imm *= -1;
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ return true;
+}
+
+
+static bool DecodeT2AddrModeImm8(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 9, 4);
+ unsigned imm = fieldFromInstruction32(Val, 0, 9);
+
+ // Some instructions always use an additive offset.
+ switch (Inst.getOpcode()) {
+ case ARM::t2LDRT:
+ case ARM::t2LDRBT:
+ case ARM::t2LDRHT:
+ case ARM::t2LDRSBT:
+ case ARM::t2LDRSHT:
+ imm |= 0x100;
+ break;
+ default:
+ break;
}
- ITState = bits7_0;
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ DecodeT2Imm8(Inst, imm, Address, Decoder);
+
+ return true;
+}
+
+
+static bool DecodeT2AddrModeImm12(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rn = fieldFromInstruction32(Val, 13, 4);
+ unsigned imm = fieldFromInstruction32(Val, 0, 12);
+
+ DecodeGPRRegisterClass(Inst, Rn, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(imm));
+
+ return true;
+}
+
+
+static bool DecodeThumbAddSPImm(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned imm = fieldFromInstruction16(Insn, 0, 7);
+
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ Inst.addOperand(MCOperand::CreateImm(imm));
return true;
}
-/// Update ITState if necessary.
-void Session::UpdateIT() {
- assert(ITCounter);
- --ITCounter;
- if (ITCounter == 0)
- ITState = 0;
- else {
- unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1;
- setSlice(ITState, 4, 0, NewITState4_0);
+static bool DecodeThumbAddSPReg(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder) {
+ if (Inst.getOpcode() == ARM::tADDrSP) {
+ unsigned Rdm = fieldFromInstruction16(Insn, 0, 3);
+ Rdm |= fieldFromInstruction16(Insn, 7, 1) << 3;
+
+ DecodeGPRRegisterClass(Inst, Rdm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ DecodeGPRRegisterClass(Inst, Rdm, Address, Decoder);
+ } else if (Inst.getOpcode() == ARM::tADDspr) {
+ unsigned Rm = fieldFromInstruction16(Insn, 3, 4);
+
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ Inst.addOperand(MCOperand::CreateReg(ARM::SP));
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
}
+
+ return true;
}
-static MCDisassembler *createARMDisassembler(const Target &T) {
- return new ARMDisassembler;
+static bool DecodeThumbCPS(llvm::MCInst &Inst, uint16_t Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned imod = fieldFromInstruction16(Insn, 4, 1) | 0x2;
+ unsigned flags = fieldFromInstruction16(Insn, 0, 3);
+
+ Inst.addOperand(MCOperand::CreateImm(imod));
+ Inst.addOperand(MCOperand::CreateImm(flags));
+
+ return true;
}
-static MCDisassembler *createThumbDisassembler(const Target &T) {
- return new ThumbDisassembler;
+static bool DecodePostIdxReg(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Rm = fieldFromInstruction32(Insn, 0, 4);
+ unsigned add = fieldFromInstruction32(Insn, 4, 1);
+
+ DecodeGPRRegisterClass(Inst, Rm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(add));
+
+ return true;
}
-extern "C" void LLVMInitializeARMDisassembler() {
- // Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheARMTarget,
- createARMDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheThumbTarget,
- createThumbDisassembler);
+static bool DecodeThumbBLXOffset(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<22>(Val << 1)));
+ return true;
}
-EDInstInfo *ARMDisassembler::getEDInfo() const {
- return instInfoARM;
+static bool DecodeCoprocessor(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ if (Val == 0xA || Val == 0xB)
+ return false;
+
+ Inst.addOperand(MCOperand::CreateImm(Val));
+ return true;
}
-EDInstInfo *ThumbDisassembler::getEDInfo() const {
- return instInfoARM;
+static bool DecodeThumbSRImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ if (Val == 0)
+ Inst.addOperand(MCOperand::CreateImm(32));
+ else
+ Inst.addOperand(MCOperand::CreateImm(Val));
+ return true;
+}
+
+static bool DecodeThumb2BCCInstruction(llvm::MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned pred = fieldFromInstruction32(Insn, 22, 4);
+ if (pred == 0xE || pred == 0xF) {
+ unsigned opc = fieldFromInstruction32(Insn, 4, 2);
+ switch (opc) {
+ default:
+ return false;
+ case 0:
+ Inst.setOpcode(ARM::t2DSB);
+ break;
+ case 1:
+ Inst.setOpcode(ARM::t2DMB);
+ break;
+ case 2:
+ Inst.setOpcode(ARM::t2ISB);
+ return true;
+ }
+
+ unsigned imm = fieldFromInstruction32(Insn, 0, 4);
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ return true;
+ }
+
+ unsigned brtarget = fieldFromInstruction32(Insn, 0, 11) << 1;
+ brtarget |= fieldFromInstruction32(Insn, 11, 1) << 19;
+ brtarget |= fieldFromInstruction32(Insn, 13, 1) << 18;
+ brtarget |= fieldFromInstruction32(Insn, 16, 6) << 12;
+ brtarget |= fieldFromInstruction32(Insn, 26, 1) << 20;
+
+ DecodeT2BROperand(Inst, brtarget, Address, Decoder);
+ if (!DecodePredicateOperand(Inst, pred, Address, Decoder))
+ return false;
+
+ return true;
+}
+
+// Decode a shifted immediate operand. These basically consist
+// of an 8-bit value, and a 4-bit directive that specifies either
+// a splat operation or a rotation.
+static bool DecodeT2SOImm(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ unsigned ctrl = fieldFromInstruction32(Val, 10, 2);
+ if (ctrl == 0) {
+ unsigned byte = fieldFromInstruction32(Val, 8, 2);
+ unsigned imm = fieldFromInstruction32(Val, 0, 8);
+ switch (byte) {
+ case 0:
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ break;
+ case 1:
+ Inst.addOperand(MCOperand::CreateImm((imm << 16) | imm));
+ break;
+ case 2:
+ Inst.addOperand(MCOperand::CreateImm((imm << 24) | (imm << 8)));
+ break;
+ case 3:
+ Inst.addOperand(MCOperand::CreateImm((imm << 24) | (imm << 16) |
+ (imm << 8) | imm));
+ break;
+ }
+ } else {
+ unsigned unrot = fieldFromInstruction32(Val, 0, 7) | 0x80;
+ unsigned rot = fieldFromInstruction32(Val, 7, 5);
+ unsigned imm = (unrot >> rot) | (unrot << ((32-rot)&31));
+ Inst.addOperand(MCOperand::CreateImm(imm));
+ }
+
+ return true;
+}
+
+static bool DecodeThumbBCCTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder){
+ Inst.addOperand(MCOperand::CreateImm(Val << 1));
+ return true;
+}
+
+static bool DecodeThumbBLTargetOperand(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder){
+ Inst.addOperand(MCOperand::CreateImm(SignExtend32<22>(Val << 1)));
+ return true;
+}
+
+static bool DecodeAddrMode3Offset(llvm::MCInst &Inst, unsigned Val,
+ uint64_t Address, const void *Decoder) {
+ bool isImm = fieldFromInstruction32(Val, 9, 1);
+ bool isAdd = fieldFromInstruction32(Val, 8, 1);
+ unsigned imm = fieldFromInstruction32(Val, 0, 8);
+
+ if (!isImm) {
+ DecodeGPRRegisterClass(Inst, imm, Address, Decoder);
+ Inst.addOperand(MCOperand::CreateImm(!isAdd << 8));
+ } else {
+ Inst.addOperand(MCOperand::CreateReg(0));
+ Inst.addOperand(MCOperand::CreateImm(imm | (!isAdd << 8)));
+ }
+
+ return true;
}
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.h b/lib/Target/ARM/Disassembler/ARMDisassembler.h
index 0a74a3866e..1d7ab46352 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassembler.h
+++ b/lib/Target/ARM/Disassembler/ARMDisassembler.h
@@ -17,15 +17,16 @@
#define ARMDISASSEMBLER_H
#include "llvm/MC/MCDisassembler.h"
+#include <vector>
namespace llvm {
class MCInst;
class MemoryObject;
class raw_ostream;
-
+
struct EDInstInfo;
-
+
/// ARMDisassembler - ARM disassembler for all ARM platforms.
class ARMDisassembler : public MCDisassembler {
public:
@@ -44,38 +45,19 @@ public:
const MemoryObject &region,
uint64_t address,
raw_ostream &vStream) const;
-
+
/// getEDInfo - See MCDisassembler.
EDInstInfo *getEDInfo() const;
private:
};
-// Forward declaration.
-class ARMBasicMCBuilder;
-
-/// Session - Keep track of the IT Block progression.
-class Session {
- friend class ARMBasicMCBuilder;
-public:
- Session() : ITCounter(0), ITState(0) {}
- ~Session() {}
- /// InitIT - Initializes ITCounter/ITState.
- bool InitIT(unsigned short bits7_0);
- /// UpdateIT - Updates ITCounter/ITState as IT Block progresses.
- void UpdateIT();
-
-private:
- unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4.
- unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially.
-};
-
-/// ThumbDisassembler - Thumb disassembler for all ARM platforms.
+/// ARMDisassembler - ARM disassembler for all ARM platforms.
class ThumbDisassembler : public MCDisassembler {
public:
/// Constructor - Initializes the disassembler.
///
ThumbDisassembler() :
- MCDisassembler(), SO() {
+ MCDisassembler() {
}
~ThumbDisassembler() {
@@ -87,13 +69,16 @@ public:
const MemoryObject &region,
uint64_t address,
raw_ostream &vStream) const;
-
+
/// getEDInfo - See MCDisassembler.
EDInstInfo *getEDInfo() const;
private:
- Session SO;
+ mutable std::vector<unsigned> ITBlock;
+ void AddThumbPredicate(MCInst&) const;
+ void UpdateThumbVFPPredicate(MCInst&) const;
};
+
} // namespace llvm
-
+
#endif
diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
deleted file mode 100644
index d460ecd694..0000000000
--- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
+++ /dev/null
@@ -1,3894 +0,0 @@
-//===- ARMDisassemblerCore.cpp - ARM disassembler helpers -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is part of the ARM Disassembler.
-// It contains code to represent the core concepts of Builder and DisassembleFP
-// to solve the problem of disassembling an ARM instr.
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "arm-disassembler"
-
-#include "ARMDisassemblerCore.h"
-#include "MCTargetDesc/ARMAddressingModes.h"
-#include "MCTargetDesc/ARMMCExpr.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-//#define DEBUG(X) do { X; } while (0)
-
-/// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const
-/// MCInstrDesc ARMInsts[] definition and the MCOperandInfo[]'s describing the
-/// operand info for each ARMInsts[i].
-///
-/// Together with an instruction's encoding format, we can take advantage of the
-/// NumOperands and the OpInfo fields of the target instruction description in
-/// the quest to build out the MCOperand list for an MCInst.
-///
-/// The general guideline is that with a known format, the number of dst and src
-/// operands are well-known. The dst is built first, followed by the src
-/// operand(s). The operands not yet used at this point are for the Implicit
-/// Uses and Defs by this instr. For the Uses part, the pred:$p operand is
-/// defined with two components:
-///
-/// def pred { // Operand PredicateOperand
-/// ValueType Type = OtherVT;
-/// string PrintMethod = "printPredicateOperand";
-/// string AsmOperandLowerMethod = ?;
-/// dag MIOperandInfo = (ops i32imm, CCR);
-/// AsmOperandClass ParserMatchClass = ImmAsmOperand;
-/// dag DefaultOps = (ops (i32 14), (i32 zero_reg));
-/// }
-///
-/// which is manifested by the MCOperandInfo[] of:
-///
-/// { 0, 0|(1<<MCOI::Predicate), 0 },
-/// { ARM::CCRRegClassID, 0|(1<<MCOI::Predicate), 0 }
-///
-/// So the first predicate MCOperand corresponds to the immediate part of the
-/// ARM condition field (Inst{31-28}), and the second predicate MCOperand
-/// corresponds to a register kind of ARM::CPSR.
-///
-/// For the Defs part, in the simple case of only cc_out:$s, we have:
-///
-/// def cc_out { // Operand OptionalDefOperand
-/// ValueType Type = OtherVT;
-/// string PrintMethod = "printSBitModifierOperand";
-/// string AsmOperandLowerMethod = ?;
-/// dag MIOperandInfo = (ops CCR);
-/// AsmOperandClass ParserMatchClass = ImmAsmOperand;
-/// dag DefaultOps = (ops (i32 zero_reg));
-/// }
-///
-/// which is manifested by the one MCOperandInfo of:
-///
-/// { ARM::CCRRegClassID, 0|(1<<MCOI::OptionalDef), 0 }
-///
-
-namespace llvm {
-extern MCInstrDesc ARMInsts[];
-}
-
-using namespace llvm;
-
-const char *ARMUtils::OpcodeName(unsigned Opcode) {
- return ARMInsts[Opcode].Name;
-}
-
-// Return the register enum Based on RegClass and the raw register number.
-// FIXME: Auto-gened?
-static unsigned
-getRegisterEnum(BO B, unsigned RegClassID, unsigned RawRegister) {
- if (RegClassID == ARM::rGPRRegClassID) {
- // Check for The register numbers 13 and 15 that are not permitted for many
- // Thumb register specifiers.
- if (RawRegister == 13 || RawRegister == 15) {
- B->SetErr(-1);
- return 0;
- }
- // For this purpose, we can treat rGPR as if it were GPR.
- RegClassID = ARM::GPRRegClassID;
- }
-
- // See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm().
- // A7.3 register encoding
- // Qd -> bit[12] == 0
- // Qn -> bit[16] == 0
- // Qm -> bit[0] == 0
- //
- // If one of these bits is 1, the instruction is UNDEFINED.
- if (RegClassID == ARM::QPRRegClassID && slice(RawRegister, 0, 0) == 1) {
- B->SetErr(-1);
- return 0;
- }
- unsigned RegNum =
- RegClassID == ARM::QPRRegClassID ? RawRegister >> 1 : RawRegister;
-
- switch (RegNum) {
- default:
- break;
- case 0:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R0;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D0;
- case ARM::QPRRegClassID: case ARM::QPR_8RegClassID:
- case ARM::QPR_VFP2RegClassID:
- return ARM::Q0;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S0;
- }
- break;
- case 1:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R1;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D1;
- case ARM::QPRRegClassID: case ARM::QPR_8RegClassID:
- case ARM::QPR_VFP2RegClassID:
- return ARM::Q1;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S1;
- }
- break;
- case 2:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R2;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D2;
- case ARM::QPRRegClassID: case ARM::QPR_8RegClassID:
- case ARM::QPR_VFP2RegClassID:
- return ARM::Q2;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S2;
- }
- break;
- case 3:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R3;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D3;
- case ARM::QPRRegClassID: case ARM::QPR_8RegClassID:
- case ARM::QPR_VFP2RegClassID:
- return ARM::Q3;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S3;
- }
- break;
- case 4:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R4;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D4;
- case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q4;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S4;
- }
- break;
- case 5:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R5;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D5;
- case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q5;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S5;
- }
- break;
- case 6:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R6;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D6;
- case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q6;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S6;
- }
- break;
- case 7:
- switch (RegClassID) {
- case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R7;
- case ARM::DPRRegClassID: case ARM::DPR_8RegClassID:
- case ARM::DPR_VFP2RegClassID:
- return ARM::D7;
- case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q7;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S7;
- }
- break;
- case 8:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::R8;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D8;
- case ARM::QPRRegClassID: return ARM::Q8;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S8;
- }
- break;
- case 9:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::R9;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D9;
- case ARM::QPRRegClassID: return ARM::Q9;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S9;
- }
- break;
- case 10:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::R10;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D10;
- case ARM::QPRRegClassID: return ARM::Q10;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S10;
- }
- break;
- case 11:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::R11;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D11;
- case ARM::QPRRegClassID: return ARM::Q11;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S11;
- }
- break;
- case 12:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::R12;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D12;
- case ARM::QPRRegClassID: return ARM::Q12;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S12;
- }
- break;
- case 13:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::SP;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D13;
- case ARM::QPRRegClassID: return ARM::Q13;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S13;
- }
- break;
- case 14:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::LR;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D14;
- case ARM::QPRRegClassID: return ARM::Q14;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S14;
- }
- break;
- case 15:
- switch (RegClassID) {
- case ARM::GPRRegClassID: return ARM::PC;
- case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D15;
- case ARM::QPRRegClassID: return ARM::Q15;
- case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S15;
- }
- break;
- case 16:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D16;
- case ARM::SPRRegClassID: return ARM::S16;
- }
- break;
- case 17:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D17;
- case ARM::SPRRegClassID: return ARM::S17;
- }
- break;
- case 18:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D18;
- case ARM::SPRRegClassID: return ARM::S18;
- }
- break;
- case 19:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D19;
- case ARM::SPRRegClassID: return ARM::S19;
- }
- break;
- case 20:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D20;
- case ARM::SPRRegClassID: return ARM::S20;
- }
- break;
- case 21:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D21;
- case ARM::SPRRegClassID: return ARM::S21;
- }
- break;
- case 22:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D22;
- case ARM::SPRRegClassID: return ARM::S22;
- }
- break;
- case 23:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D23;
- case ARM::SPRRegClassID: return ARM::S23;
- }
- break;
- case 24:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D24;
- case ARM::SPRRegClassID: return ARM::S24;
- }
- break;
- case 25:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D25;
- case ARM::SPRRegClassID: return ARM::S25;
- }
- break;
- case 26:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D26;
- case ARM::SPRRegClassID: return ARM::S26;
- }
- break;
- case 27:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D27;
- case ARM::SPRRegClassID: return ARM::S27;
- }
- break;
- case 28:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D28;
- case ARM::SPRRegClassID: return ARM::S28;
- }
- break;
- case 29:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D29;
- case ARM::SPRRegClassID: return ARM::S29;
- }
- break;
- case 30:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D30;
- case ARM::SPRRegClassID: return ARM::S30;
- }
- break;
- case 31:
- switch (RegClassID) {
- case ARM::DPRRegClassID: return ARM::D31;
- case ARM::SPRRegClassID: return ARM::S31;
- }
- break;
- }
- DEBUG(errs() << "Invalid (RegClassID, RawRegister) combination\n");
- // Encoding error. Mark the builder with error code != 0.
- B->SetErr(-1);
- return 0;
-}
-
-///////////////////////////////
-// //
-// Utility Functions //
-// //
-///////////////////////////////
-
-// Extract/Decode Rd: Inst{15-12}.
-static inline unsigned decodeRd(uint32_t insn) {
- return (insn >> ARMII::RegRdShift) & ARMII::GPRRegMask;
-}
-
-// Extract/Decode Rn: Inst{19-16}.
-static inline unsigned decodeRn(uint32_t insn) {
- return (insn >> ARMII::RegRnShift) & ARMII::GPRRegMask;
-}
-
-// Extract/Decode Rm: Inst{3-0}.
-static inline unsigned decodeRm(uint32_t insn) {
- return (insn & ARMII::GPRRegMask);
-}
-
-// Extract/Decode Rs: Inst{11-8}.
-static inline unsigned decodeRs(uint32_t insn) {
- return (insn >> ARMII::RegRsShift) & ARMII::GPRRegMask;
-}
-
-static inline unsigned getCondField(uint32_t insn) {
- return (insn >> ARMII::CondShift);
-}
-
-static inline unsigned getIBit(uint32_t insn) {
- return (insn >> ARMII::I_BitShift) & 1;
-}
-
-static inline unsigned getAM3IBit(uint32_t insn) {
- return (insn >> ARMII::AM3_I_BitShift) & 1;
-}
-
-static inline unsigned getPBit(uint32_t insn) {
- return (insn >> ARMII::P_BitShift) & 1;
-}
-
-static inline unsigned getUBit(uint32_t insn) {
- return (insn >> ARMII::U_BitShift) & 1;
-}
-
-static inline unsigned getPUBits(uint32_t insn) {
- return (insn >> ARMII::U_BitShift) & 3;
-}
-
-static inline unsigned getSBit(uint32_t insn) {
- return (insn >> ARMII::S_BitShift) & 1;
-}
-
-static inline unsigned getWBit(uint32_t insn) {
- return (insn >> ARMII::W_BitShift) & 1;
-}
-
-static inline unsigned getDBit(uint32_t insn) {
- return (insn >> ARMII::D_BitShift) & 1;
-}
-
-static inline unsigned getNBit(uint32_t insn) {
- return (insn >> ARMII::N_BitShift) & 1;
-}
-
-static inline unsigned getMBit(uint32_t insn) {
- return (insn >> ARMII::M_BitShift) & 1;
-}
-
-// See A8.4 Shifts applied to a register.
-// A8.4.2 Register controlled shifts.
-//
-// getShiftOpcForBits - getShiftOpcForBits translates from the ARM encoding bits
-// into llvm enums for shift opcode. The API clients should pass in the value
-// encoded with two bits, so the assert stays to signal a wrong API usage.
-//
-// A8-12: DecodeRegShift()
-static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) {
- switch (bits) {
- default: assert(0 && "No such value"); return ARM_AM::no_shift;
- case 0: return ARM_AM::lsl;
- case 1: return ARM_AM::lsr;
- case 2: return ARM_AM::asr;
- case 3: return ARM_AM::ror;
- }
-}
-
-// See A8.4 Shifts applied to a register.
-// A8.4.1 Constant shifts.
-//
-// getImmShiftSE - getImmShiftSE translates from the raw ShiftOpc and raw Imm5
-// encodings into the intended ShiftOpc and shift amount.
-//
-// A8-11: DecodeImmShift()
-static inline void getImmShiftSE(ARM_AM::ShiftOpc &ShOp, unsigned &ShImm) {
- if (ShImm != 0)
- return;
- switch (ShOp) {
- case ARM_AM::no_shift:
- case ARM_AM::rrx:
- break;
- case ARM_AM::lsl:
- ShOp = ARM_AM::no_shift;
- break;
- case ARM_AM::lsr:
- case ARM_AM::asr:
- ShImm = 32;
- break;
- case ARM_AM::ror:
- ShOp = ARM_AM::rrx;
- break;
- }
-}
-
-// getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding
-// bits Inst{24-23} (P(24) and U(23)) into llvm enums for AMSubMode. The API
-// clients should pass in the value encoded with two bits, so the assert stays
-// to signal a wrong API usage.
-static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) {
- switch (bits) {
- default: assert(0 && "No such value"); return ARM_AM::bad_am_submode;
- case 1: return ARM_AM::ia; // P=0 U=1
- case 3: return ARM_AM::ib; // P=1 U=1
- case 0: return ARM_AM::da; // P=0 U=0
- case 2: return ARM_AM::db; // P=1 U=0
- }
-}
-
-////////////////////////////////////////////
-// //
-// Disassemble function definitions //
-// //
-////////////////////////////////////////////
-
-/// There is a separate Disassemble*Frm function entry for disassembly of an ARM
-/// instr into a list of MCOperands in the appropriate order, with possible dst,
-/// followed by possible src(s).
-///
-/// The processing of the predicate, and the 'S' modifier bit, if MI modifies
-/// the CPSR, is factored into ARMBasicMCBuilder's method named
-/// TryPredicateAndSBitModifier.
-
-static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO) {
-
- assert(0 && "Unexpected pseudo instruction!");
- return false;
-}
-
-// A8.6.94 MLA
-// if d == 15 || n == 15 || m == 15 || a == 15 then UNPREDICTABLE;
-//
-// A8.6.105 MUL
-// if d == 15 || n == 15 || m == 15 then UNPREDICTABLE;
-//
-// A8.6.246 UMULL
-// if dLo == 15 || dHi == 15 || n == 15 || m == 15 then UNPREDICTABLE;
-// if dHi == dLo then UNPREDICTABLE;
-static bool BadRegsMulFrm(unsigned Opcode, uint32_t insn) {
- unsigned R19_16 = slice(insn, 19, 16);
- unsigned R15_12 = slice(insn, 15, 12);
- unsigned R11_8 = slice(insn, 11, 8);
- unsigned R3_0 = slice(insn, 3, 0);
- switch (Opcode) {
- default:
- // Did we miss an opcode?
- DEBUG(errs() << "BadRegsMulFrm: unexpected opcode!");
- return false;
- case ARM::MLA: case ARM::MLS: case ARM::SMLABB: case ARM::SMLABT:
- case ARM::SMLATB: case ARM::SMLATT: case ARM::SMLAWB: case ARM::SMLAWT:
- case ARM::SMMLA: case ARM::SMMLAR: case ARM::SMMLS: case ARM::SMMLSR:
- case ARM::USADA8:
- if (R19_16 == 15 || R15_12 == 15 || R11_8 == 15 || R3_0 == 15)
- return true;
- return false;
- case ARM::MUL: case ARM::SMMUL: case ARM::SMMULR:
- case ARM::SMULBB: case ARM::SMULBT: case ARM::SMULTB: case ARM::SMULTT:
- case ARM::SMULWB: case ARM::SMULWT: case ARM::SMUAD: case ARM::SMUADX:
- // A8.6.167 SMLAD & A8.6.172 SMLSD
- case ARM::SMLAD: case ARM::SMLADX: case ARM::SMLSD: case ARM::SMLSDX:
- case ARM::USAD8:
- if (R19_16 == 15 || R11_8 == 15 || R3_0 == 15)
- return true;
- return false;
- case ARM::SMLAL: case ARM::SMULL: case ARM::UMAAL: case ARM::UMLAL:
- case ARM::UMULL:
- case ARM::SMLALBB: case ARM::SMLALBT: case ARM::SMLALTB: case ARM::SMLALTT:
- case ARM::SMLALD: case ARM::SMLALDX: case ARM::SMLSLD: case ARM::SMLSLDX:
- if (R19_16 == 15 || R15_12 == 15 || R11_8 == 15 || R3_0 == 15)
- return true;
- if (R19_16 == R15_12)
- return true;
- return false;;
- }
-}
-
-// Multiply Instructions.
-// MLA, MLS, SMLABB, SMLABT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMMLA, SMMLAR,
-// SMMLS, SMMLAR, SMLAD, SMLADX, SMLSD, SMLSDX, and USADA8 (for convenience):
-// Rd{19-16} Rn{3-0} Rm{11-8} Ra{15-12}
-// But note that register checking for {SMLAD, SMLADX, SMLSD, SMLSDX} is
-// only for {d, n, m}.
-//
-// MUL, SMMUL, SMMULR, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, SMULWT, SMUAD,
-// SMUADX, and USAD8 (for convenience):
-// Rd{19-16} Rn{3-0} Rm{11-8}
-//
-// SMLAL, SMULL, UMAAL, UMLAL, UMULL, SMLALBB, SMLALBT, SMLALTB, SMLALTT,
-// SMLALD, SMLADLX, SMLSLD, SMLSLDX:
-// RdLo{15-12} RdHi{19-16} Rn{3-0} Rm{11-8}
-//
-// The mapping of the multiply registers to the "regular" ARM registers, where
-// there are convenience decoder functions, is:
-//
-// Inst{15-12} => Rd
-// Inst{19-16} => Rn
-// Inst{3-0} => Rm
-// Inst{11-8} => Rs
-static bool DisassembleMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- unsigned short NumDefs = MCID.getNumDefs();
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumDefs > 0 && "NumDefs should be greater than 0 for MulFrm");
- assert(NumOps >= 3
- && OpInfo[0].RegClass == ARM::GPRRegClassID
- && OpInfo[1].RegClass == ARM::GPRRegClassID
- && OpInfo[2].RegClass == ARM::GPRRegClassID
- && "Expect three register operands");
-
- // Sanity check for the register encodings.
- if (BadRegsMulFrm(Opcode, insn))
- return false;
-
- // Instructions with two destination registers have RdLo{15-12} first.
- if (NumDefs == 2) {
- assert(NumOps >= 4 && OpInfo[3].RegClass == ARM::GPRRegClassID &&
- "Expect 4th register operand");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- // The destination register: RdHi{19-16} or Rd{19-16}.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
-
- // The two src regsiters: Rn{3-0}, then Rm{11-8}.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRs(insn))));
- OpIdx += 3;
-
- // Many multiply instructions (e.g., MLA) have three src registers.
- // The third register operand is Ra{15-12}.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- return true;
-}
-
-// Helper routines for disassembly of coprocessor instructions.
-
-static bool LdStCopOpcode(unsigned Opcode) {
- if ((Opcode >= ARM::LDC2L_OFFSET && Opcode <= ARM::LDC_PRE) ||
- (Opcode >= ARM::STC2L_OFFSET && Opcode <= ARM::STC_PRE))
- return true;
- return false;
-}
-static bool CoprocessorOpcode(unsigned Opcode) {
- if (LdStCopOpcode(Opcode))
- return true;
-
- switch (Opcode) {
- default:
- return false;
- case ARM::CDP: case ARM::CDP2:
- case ARM::MCR: case ARM::MCR2: case ARM::MRC: case ARM::MRC2:
- case ARM::MCRR: case ARM::MCRR2: case ARM::MRRC: case ARM::MRRC2:
- return true;
- }
-}
-static inline unsigned GetCoprocessor(uint32_t insn) {
- return slice(insn, 11, 8);
-}
-static inline unsigned GetCopOpc1(uint32_t insn, bool CDP) {
- return CDP ? slice(insn, 23, 20) : slice(insn, 23, 21);
-}
-static inline unsigned GetCopOpc2(uint32_t insn) {
- return slice(insn, 7, 5);
-}
-static inline unsigned GetCopOpc(uint32_t insn) {
- return slice(insn, 7, 4);
-}
-// Most of the operands are in immediate forms, except Rd and Rn, which are ARM
-// core registers.
-//
-// CDP, CDP2: cop opc1 CRd CRn CRm opc2
-//
-// MCR, MCR2, MRC, MRC2: cop opc1 Rd CRn CRm opc2
-//
-// MCRR, MCRR2, MRRC, MRRc2: cop opc Rd Rn CRm
-//
-// LDC_OFFSET, LDC_PRE, LDC_POST: cop CRd Rn R0 [+/-]imm8:00
-// and friends
-// STC_OFFSET, STC_PRE, STC_POST: cop CRd Rn R0 [+/-]imm8:00
-// and friends
-// <-- addrmode2 -->
-//
-// LDC_OPTION: cop CRd Rn imm8
-// and friends
-// STC_OPTION: cop CRd Rn imm8
-// and friends
-//
-static bool DisassembleCoprocessor(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 4 && "Num of operands >= 4 for coprocessor instr");
-
- unsigned &OpIdx = NumOpsAdded;
- // A8.6.92
- // if coproc == '101x' then SEE "Advanced SIMD and VFP"
- // But since the special instructions have more explicit encoding bits
- // specified, if coproc == 10 or 11, we should reject it as invalid.
- unsigned coproc = GetCoprocessor(insn);
- if ((Opcode == ARM::MCR || Opcode == ARM::MCRR ||
- Opcode == ARM::MRC || Opcode == ARM::MRRC) &&
- (coproc == 10 || coproc == 11)) {
- DEBUG(errs() << "Encoding error: coproc == 10 or 11 for MCR[R]/MR[R]C\n");
- return false;
- }
-
- bool OneCopOpc = (Opcode == ARM::MCRR || Opcode == ARM::MCRR2 ||
- Opcode == ARM::MRRC || Opcode == ARM::MRRC2);
-
- // CDP/CDP2 has no GPR operand; the opc1 operand is also wider (Inst{23-20}).
- bool NoGPR = (Opcode == ARM::CDP || Opcode == ARM::CDP2);
- bool LdStCop = LdStCopOpcode(Opcode);
- bool RtOut = (Opcode == ARM::MRC || Opcode == ARM::MRC2);
-
- OpIdx = 0;
-
- if (RtOut) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
- MI.addOperand(MCOperand::CreateImm(coproc));
- ++OpIdx;
-
- if (LdStCop) {
- // Unindex if P:W = 0b00 --> _OPTION variant
- unsigned PW = getPBit(insn) << 1 | getWBit(insn);
-
- MI.addOperand(MCOperand::CreateImm(decodeRd(insn)));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- OpIdx += 2;
-
- if (PW) {
- MI.addOperand(MCOperand::CreateReg(0));
- ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- unsigned IndexMode =
- (MCID.TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
- unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, slice(insn, 7, 0) << 2,
- ARM_AM::no_shift, IndexMode);
- MI.addOperand(MCOperand::CreateImm(Offset));
- OpIdx += 2;
- } else {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 0)));
- ++OpIdx;
- }
- } else {
- MI.addOperand(MCOperand::CreateImm(OneCopOpc ? GetCopOpc(insn)
- : GetCopOpc1(insn, NoGPR)));
- ++OpIdx;
-
- if (!RtOut) {
- MI.addOperand(NoGPR ? MCOperand::CreateImm(decodeRd(insn))
- : MCOperand::CreateReg(
- getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- MI.addOperand(OneCopOpc ? MCOperand::CreateReg(
- getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn)))
- : MCOperand::CreateImm(decodeRn(insn)));
-
- MI.addOperand(MCOperand::CreateImm(decodeRm(insn)));
-
- OpIdx += 2;
-
- if (!OneCopOpc) {
- MI.addOperand(MCOperand::CreateImm(GetCopOpc2(insn)));
- ++OpIdx;
- }
- }
-
- return true;
-}
-
-// Branch Instructions.
-// BL: SignExtend(Imm24:'00', 32)
-// Bcc, BL_pred: SignExtend(Imm24:'00', 32) Pred0 Pred1
-// SMC: ZeroExtend(imm4, 32)
-// SVC: ZeroExtend(Imm24, 32)
-//
-// Various coprocessor instructions are assigned BrFrm arbitrarily.
-// Delegates to DisassembleCoprocessor() helper function.
-//
-// MRS/MRSsys: Rd
-// MSR/MSRsys: Rm mask=Inst{19-16}
-// BXJ: Rm
-// MSRi/MSRsysi: so_imm
-// SRS: mode_imm
-// RFE: Rn
-static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- if (CoprocessorOpcode(Opcode))
- return DisassembleCoprocessor(MI, Opcode, insn, NumOps, NumOpsAdded, B);
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- // MRS and MRSsys take one GPR reg Rd.
- if (Opcode == ARM::MRS || Opcode == ARM::MRSsys) {
- assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- NumOpsAdded = 1;
- return true;
- }
- // BXJ takes one GPR reg Rm.
- if (Opcode == ARM::BXJ) {
- assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- NumOpsAdded = 1;
- return true;
- }
- // MSR take a mask, followed by one GPR reg Rm. The mask contains the R Bit in
- // bit 4, and the special register fields in bits 3-0.
- if (Opcode == ARM::MSR) {
- assert(NumOps >= 1 && OpInfo[1].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ |
- slice(insn, 19, 16) /* Special Reg */ ));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- NumOpsAdded = 2;
- return true;
- }
- // MSRi take a mask, followed by one so_imm operand. The mask contains the
- // R Bit in bit 4, and the special register fields in bits 3-0.
- if (Opcode == ARM::MSRi) {
- // A5.2.11 MSR (immediate), and hints & B6.1.6 MSR (immediate)
- // The hints instructions have more specific encodings, so if mask == 0,
- // we should reject this as an invalid instruction.
- if (slice(insn, 19, 16) == 0)
- return false;
- MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ |
- slice(insn, 19, 16) /* Special Reg */ ));
- // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0.
- // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}.
- // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot().
- unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF;
- unsigned Imm = insn & 0xFF;
- MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot)));
- NumOpsAdded = 2;
- return true;
- }
- if (Opcode == ARM::SRSDA || Opcode == ARM::SRSDB ||
- Opcode == ARM::SRSIA || Opcode == ARM::SRSIB ||
- Opcode == ARM::SRSDA_UPD || Opcode == ARM::SRSDB_UPD ||
- Opcode == ARM::SRSIA_UPD || Opcode == ARM::SRSIB_UPD) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));
- NumOpsAdded = 1;
- return true;
- }
- if (Opcode == ARM::RFEDA || Opcode == ARM::RFEDB ||
- Opcode == ARM::RFEIA || Opcode == ARM::RFEIB ||
- Opcode == ARM::RFEDA_UPD || Opcode == ARM::RFEDB_UPD ||
- Opcode == ARM::RFEIA_UPD || Opcode == ARM::RFEIB_UPD) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- NumOpsAdded = 1;
- return true;
- }
-
- assert((Opcode == ARM::Bcc || Opcode == ARM::BL || Opcode == ARM::BL_pred
- || Opcode == ARM::SMC || Opcode == ARM::SVC) &&
- "Unexpected Opcode");
-
- assert(NumOps >= 1 && OpInfo[0].RegClass < 0 && "Imm operand expected");
-
- int Imm32 = 0;
- if (Opcode == ARM::SMC) {
- // ZeroExtend(imm4, 32) where imm24 = Inst{3-0}.
- Imm32 = slice(insn, 3, 0);
- } else if (Opcode == ARM::SVC) {
- // ZeroExtend(imm24, 32) where imm24 = Inst{23-0}.
- Imm32 = slice(insn, 23, 0);
- } else {
- // SignExtend(imm24:'00', 32) where imm24 = Inst{23-0}.
- unsigned Imm26 = slice(insn, 23, 0) << 2;
- //Imm32 = signextend<signed int, 26>(Imm26);
- Imm32 = SignExtend32<26>(Imm26);
- }
-
- MI.addOperand(MCOperand::CreateImm(Imm32));
- NumOpsAdded = 1;
-
- return true;
-}
-
-// Misc. Branch Instructions.
-// BX_RET, MOVPCLR
-// BLX, BLX_pred, BX, BX_pred
-// BLXi
-static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // BX_RET and MOVPCLR have only two predicate operands; do an early return.
- if (Opcode == ARM::BX_RET || Opcode == ARM::MOVPCLR)
- return true;
-
- // BLX and BX take one GPR reg.
- if (Opcode == ARM::BLX || Opcode == ARM::BLX_pred ||
- Opcode == ARM::BX || Opcode == ARM::BX_pred) {
- assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- OpIdx = 1;
- return true;
- }
-
- // BLXi takes imm32 (the PC offset).
- if (Opcode == ARM::BLXi) {
- assert(NumOps >= 1 && OpInfo[0].RegClass < 0 && "Imm operand expected");
- // SignExtend(imm24:H:'0', 32) where imm24 = Inst{23-0} and H = Inst{24}.
- unsigned Imm26 = slice(insn, 23, 0) << 2 | slice(insn, 24, 24) << 1;
- int Imm32 = SignExtend32<26>(Imm26);
- MI.addOperand(MCOperand::CreateImm(Imm32));
- OpIdx = 1;
- return true;
- }
-
- return false;
-}
-
-static inline bool getBFCInvMask(uint32_t insn, uint32_t &mask) {
- uint32_t lsb = slice(insn, 11, 7);
- uint32_t msb = slice(insn, 20, 16);
- uint32_t Val = 0;
- if (msb < lsb) {
- DEBUG(errs() << "Encoding error: msb < lsb\n");
- return false;
- }
-
- for (uint32_t i = lsb; i <= msb; ++i)
- Val |= (1 << i);
- mask = ~Val;
- return true;
-}
-
-// Standard data-processing instructions allow PC as a register specifier,
-// but we should reject other DPFrm instructions with PC as registers.
-static bool BadRegsDPFrm(unsigned Opcode, uint32_t insn) {
- switch (Opcode) {
- default:
- // Did we miss an opcode?
- if (decodeRd(insn) == 15 || decodeRn(insn) == 15 || decodeRm(insn) == 15) {
- DEBUG(errs() << "DPFrm with bad reg specifier(s)\n");
- return true;
- }
- case ARM::ADCrr: case ARM::ADDSrr: case ARM::ADDrr: case ARM::ANDrr:
- case ARM::BICrr: case ARM::CMNzrr: case ARM::CMPrr: case ARM::EORrr:
- case ARM::ORRrr: case ARM::RSBrr: case ARM::RSCrr: case ARM::SBCrr:
- case ARM::SUBSrr: case ARM::SUBrr: case ARM::TEQrr: case ARM::TSTrr:
- return false;
- }
-}
-
-// A major complication is the fact that some of the saturating add/subtract
-// operations have Rd Rm Rn, instead of the "normal" Rd Rn Rm.
-// They are QADD, QDADD, QDSUB, and QSUB.
-static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- unsigned short NumDefs = MCID.getNumDefs();
- bool isUnary = isUnaryDP(MCID.TSFlags);
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // Disassemble register def if there is one.
- if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- // Now disassemble the src operands.
- if (OpIdx >= NumOps)
- return false;
-
- // Special-case handling of BFC/BFI/SBFX/UBFX.
- if (Opcode == ARM::BFC || Opcode == ARM::BFI) {
- // A8.6.17 BFC & A8.6.18 BFI
- // Sanity check Rd.
- if (decodeRd(insn) == 15)
- return false;
- MI.addOperand(MCOperand::CreateReg(0));
- if (Opcode == ARM::BFI) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- ++OpIdx;
- }
- uint32_t mask = 0;
- if (!getBFCInvMask(insn, mask))
- return false;
-
- MI.addOperand(MCOperand::CreateImm(mask));
- OpIdx += 2;
- return true;
- }
- if (Opcode == ARM::SBFX || Opcode == ARM::UBFX) {
- // Sanity check Rd and Rm.
- if (decodeRd(insn) == 15 || decodeRm(insn) == 15)
- return false;
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 7)));
- MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 16)));
- OpIdx += 3;
- return true;
- }
-
- bool RmRn = (Opcode == ARM::QADD || Opcode == ARM::QDADD ||
- Opcode == ARM::QDSUB || Opcode == ARM::QSUB);
-
- // BinaryDP has an Rn operand.
- if (!isUnary) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::GPRRegClassID,
- RmRn ? decodeRm(insn) : decodeRn(insn))));
- ++OpIdx;
- }
-
- // If this is a two-address operand, skip it, e.g., MOVCCr operand 1.
- if (isUnary && (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)) {
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Now disassemble operand 2.
- if (OpIdx >= NumOps)
- return false;
-
- if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) {
- // We have a reg/reg form.
- // Assert disabled because saturating operations, e.g., A8.6.127 QASX, are
- // routed here as well.
- // assert(getIBit(insn) == 0 && "I_Bit != '0' reg/reg form");
- if (BadRegsDPFrm(Opcode, insn))
- return false;
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::GPRRegClassID,
- RmRn? decodeRn(insn) : decodeRm(insn))));
- ++OpIdx;
- } else if (Opcode == ARM::MOVi16 || Opcode == ARM::MOVTi16) {
- // These two instructions don't allow d as 15.
- if (decodeRd(insn) == 15)
- return false;
- // We have an imm16 = imm4:imm12 (imm4=Inst{19:16}, imm12 = Inst{11:0}).
- assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form");
- unsigned Imm16 = slice(insn, 19, 16) << 12 | slice(insn, 11, 0);
- if (!B->tryAddingSymbolicOperand(Imm16, 4, MI))
- MI.addOperand(MCOperand::CreateImm(Imm16));
- ++OpIdx;
- } else {
- // We have a reg/imm form.
- // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0.
- // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}.
- // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot().
- assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form");
- unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF;
- unsigned Imm = insn & 0xFF;
- MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot)));
- ++OpIdx;
- }
-
- return true;
-}
-
-static bool DisassembleDPSoRegRegFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- unsigned short NumDefs = MCID.getNumDefs();
- bool isUnary = isUnaryDP(MCID.TSFlags);
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // Disassemble register def if there is one.
- if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- // Disassemble the src operands.
- if (OpIdx >= NumOps)
- return false;
-
- // BinaryDP has an Rn operand.
- if (!isUnary) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // If this is a two-address operand, skip it, e.g., MOVCCs operand 1.
- if (isUnary && (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)) {
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Disassemble operand 2, which consists of three components.
- if (OpIdx + 2 >= NumOps)
- return false;
-
- assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) &&
- (OpInfo[OpIdx+1].RegClass == ARM::GPRRegClassID) &&
- (OpInfo[OpIdx+2].RegClass < 0) &&
- "Expect 3 reg operands");
-
- // Register-controlled shifts have Inst{7} = 0 and Inst{4} = 1.
- unsigned Rs = slice(insn, 4, 4);
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- if (Rs) {
- // If Inst{7} != 0, we should reject this insn as an invalid encoding.
- if (slice(insn, 7, 7))
- return false;
-
- // A8.6.3 ADC (register-shifted register)
- // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE;
- //
- // This also accounts for shift instructions (register) where, fortunately,
- // Inst{19-16} = 0b0000.
- // A8.6.89 LSL (register)
- // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE;
- if (decodeRd(insn) == 15 || decodeRn(insn) == 15 ||
- decodeRm(insn) == 15 || decodeRs(insn) == 15)
- return false;
-
- // Register-controlled shifts: [Rm, Rs, shift].
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRs(insn))));
- // Inst{6-5} encodes the shift opcode.
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5));
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, 0)));
- } else {
- // Constant shifts: [Rm, reg0, shift_imm].
- MI.addOperand(MCOperand::CreateReg(0)); // NoRegister
- // Inst{6-5} encodes the shift opcode.
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5));
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShImm = slice(insn, 11, 7);
-
- // A8.4.1. Possible rrx or shift amount of 32...
- getImmShiftSE(ShOp, ShImm);
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShImm)));
- }
- OpIdx += 3;
-
- return true;
-}
-
-static bool DisassembleDPSoRegImmFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- unsigned short NumDefs = MCID.getNumDefs();
- bool isUnary = isUnaryDP(MCID.TSFlags);
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // Disassemble register def if there is one.
- if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
- }
-
- // Disassemble the src operands.
- if (OpIdx >= NumOps)
- return false;
-
- // BinaryDP has an Rn operand.
- if (!isUnary) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // If this is a two-address operand, skip it, e.g., MOVCCs operand 1.
- if (isUnary && (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)) {
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Disassemble operand 2, which consists of two components.
- if (OpIdx + 1 >= NumOps)
- return false;
-
- assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) &&
- (OpInfo[OpIdx+1].RegClass < 0) &&
- "Expect 2 reg operands");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
-
- // Inst{6-5} encodes the shift opcode.
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5));
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShImm = slice(insn, 11, 7);
-
- // A8.4.1. Possible rrx or shift amount of 32...
- getImmShiftSE(ShOp, ShImm);
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShImm)));
-
- OpIdx += 2;
-
- return true;
-}
-
-
-static bool BadRegsLdStFrm(unsigned Opcode, uint32_t insn, bool Store, bool WBack,
- bool Imm) {
- const StringRef Name = ARMInsts[Opcode].Name;
- unsigned Rt = decodeRd(insn);
- unsigned Rn = decodeRn(insn);
- unsigned Rm = decodeRm(insn);
- unsigned P = getPBit(insn);
- unsigned W = getWBit(insn);
-
- if (Store) {
- // Only STR (immediate, register) allows PC as the source.
- if (Name.startswith("STRB") && Rt == 15) {
- DEBUG(errs() << "if t == 15 then UNPREDICTABLE\n");
- return true;
- }
- if (WBack && (Rn == 15 || Rn == Rt)) {
- DEBUG(errs() << "if wback && (n == 15 || n == t) then UNPREDICTABLE\n");
- return true;
- }
- if (!Imm && Rm == 15) {
- DEBUG(errs() << "if m == 15 then UNPREDICTABLE\n");
- return true;
- }
- } else {
- // Only LDR (immediate, register) allows PC as the destination.
- if (Name.startswith("LDRB") && Rt == 15) {
- DEBUG(errs() << "if t == 15 then UNPREDICTABLE\n");
- return true;
- }
- if (Imm) {
- // Immediate
- if (Rn == 15) {
- // The literal form must be in offset mode; it's an encoding error
- // otherwise.
- if (!(P == 1 && W == 0)) {
- DEBUG(errs() << "Ld literal form with !(P == 1 && W == 0)\n");
- return true;
- }
- // LDRB (literal) does not allow PC as the destination.
- if (Opcode != ARM::LDRi12 && Rt == 15) {
- DEBUG(errs() << "if t == 15 then UNPREDICTABLE\n");
- return true;
- }
- } else {
- // Write back while Rn == Rt does not make sense.
- if (WBack && (Rn == Rt)) {
- DEBUG(errs() << "if wback && n == t then UNPREDICTABLE\n");
- return true;
- }
- }
- } else {
- // Register
- if (Rm == 15) {
- DEBUG(errs() << "if m == 15 then UNPREDICTABLE\n");
- return true;
- }
- if (WBack && (Rn == 15 || Rn == Rt)) {
- DEBUG(errs() << "if wback && (n == 15 || n == t) then UNPREDICTABLE\n");
- return true;
- }
- }
- }
- return false;
-}
-
-static bool DisassembleLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, bool isStore, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- bool isPrePost = isPrePostLdSt(MCID.TSFlags);
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(((!isStore && MCID.getNumDefs() > 0) ||
- (isStore && (MCID.getNumDefs() == 0 || isPrePost)))
- && "Invalid arguments");
-
- // Operand 0 of a pre- and post-indexed store is the address base writeback.
- if (isPrePost && isStore) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // Disassemble the dst/src operand.
- if (OpIdx >= NumOps)
- return false;
-
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
-
- // After dst of a pre- and post-indexed load is the address base writeback.
- if (isPrePost && !isStore) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // Disassemble the base operand.
- if (OpIdx >= NumOps)
- return false;
-
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- assert((!isPrePost || (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1))
- && "Index mode or tied_to operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
-
- // For reg/reg form, base reg is followed by +/- reg shop imm.
- // For immediate form, it is followed by +/- imm12.
- // See also ARMAddressingModes.h (Addressing Mode #2).
- if (OpIdx + 1 >= NumOps)
- return false;
-
- if (BadRegsLdStFrm(Opcode, insn, isStore, isPrePost, getIBit(insn)==0))
- return false;
-
- ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
- unsigned IndexMode =
- (MCID.TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
- if (getIBit(insn) == 0) {
- // For pre- and post-indexed case, add a reg0 operand (Addressing Mode #2).
- // Otherwise, skip the reg operand since for addrmode_imm12, Rn has already
- // been populated.
- if (isPrePost) {
- MI.addOperand(MCOperand::CreateReg(0));
- OpIdx += 1;
- }
-
- unsigned Imm12 = slice(insn, 11, 0);
- if (Opcode == ARM::LDRBi12 || Opcode == ARM::LDRi12 ||
- Opcode == ARM::STRBi12 || Opcode == ARM::STRi12) {
- // Disassemble the 12-bit immediate offset, which is the second operand in
- // $addrmode_imm12 => (ops GPR:$base, i32imm:$offsimm).
- int Offset = AddrOpcode == ARM_AM::add ? 1 * Imm12 : -1 * Imm12;
- MI.addOperand(MCOperand::CreateImm(Offset));
- } else {
- // Disassemble the 12-bit immediate offset, which is the second operand in
- // $am2offset => (ops GPR, i32imm).
- unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, Imm12, ARM_AM::no_shift,
- IndexMode);
- MI.addOperand(MCOperand::CreateImm(Offset));
- }
- OpIdx += 1;
- } else {
- // If Inst{25} = 1 and Inst{4} != 0, we should reject this as invalid.
- if (slice(insn,4,4) == 1)
- return false;
-
- // Disassemble the offset reg (Rm), shift type, and immediate shift length.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- // Inst{6-5} encodes the shift opcode.
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5));
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShImm = slice(insn, 11, 7);
-
- // A8.4.1. Possible rrx or shift amount of 32...
- getImmShiftSE(ShOp, ShImm);
- MI.addOperand(MCOperand::CreateImm(
- ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp, IndexMode)));
- OpIdx += 2;
- }
-
- return true;
-}
-
-static bool DisassembleLdFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false, B);
-}
-
-static bool DisassembleStFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true, B);
-}
-
-static bool HasDualReg(unsigned Opcode) {
- switch (Opcode) {
- default:
- return false;
- case ARM::LDRD: case ARM::LDRD_PRE: case ARM::LDRD_POST:
- case ARM::STRD: case ARM::STRD_PRE: case ARM::STRD_POST:
- return true;
- }
-}
-
-static bool DisassembleLdStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, bool isStore, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- bool isPrePost = isPrePostLdSt(MCID.TSFlags);
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(((!isStore && MCID.getNumDefs() > 0) ||
- (isStore && (MCID.getNumDefs() == 0 || isPrePost)))
- && "Invalid arguments");
-
- // Operand 0 of a pre- and post-indexed store is the address base writeback.
- if (isPrePost && isStore) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // Disassemble the dst/src operand.
- if (OpIdx >= NumOps)
- return false;
-
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
-
- // Fill in LDRD and STRD's second operand Rt operand.
- if (HasDualReg(Opcode)) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn) + 1)));
- ++OpIdx;
- }
-
- // After dst of a pre- and post-indexed load is the address base writeback.
- if (isPrePost && !isStore) {
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- // Disassemble the base operand.
- if (OpIdx >= NumOps)
- return false;
-
- assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
- assert((!isPrePost || (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1))
- && "Offset mode or tied_to operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
-
- // For reg/reg form, base reg is followed by +/- reg.
- // For immediate form, it is followed by +/- imm8.
- if (OpIdx + 1 >= NumOps)
- return false;
-
- unsigned IndexMode =
- (MCID.TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
- ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
- if (getAM3IBit(insn) == 1) {
- // FIXME: Conditional while in the midst of refactoring addrmode3. Will
- // go away entirely when the rest are converted.
- if (Opcode != ARM::STRHTi && Opcode != ARM::LDRSBTi &&
- Opcode != ARM::LDRHTi && Opcode != ARM::LDRSHTi) {
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Disassemble the 8-bit immediate offset (postidx_imm8).
- unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF;
- unsigned Imm4L = insn & 0xF;
- unsigned Offset;
- // FIXME: Remove the 'else' once done w/ addrmode3 refactor.
- if (Opcode == ARM::STRHTi || Opcode == ARM::LDRSBTi ||
- Opcode == ARM::LDRHTi || Opcode == ARM::LDRSHTi)
- Offset = (Imm4H << 4) | Imm4L | (getUBit(insn) << 8);
- else
- Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L,
- IndexMode);
-
- MI.addOperand(MCOperand::CreateImm(Offset));
- ++OpIdx;
- } else {
- // Disassemble the offset reg (Rm).
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- // FIXME: Remove the 'else' once done w/ addrmode3 refactor.
- if (Opcode == ARM::STRHTr || Opcode == ARM::LDRSBTr ||
- Opcode == ARM::LDRHTr || Opcode == ARM::LDRSHTr)
- MI.addOperand(MCOperand::CreateImm(getUBit(insn)));
- else {
- unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0);
- MI.addOperand(MCOperand::CreateImm(Offset));
- }
- OpIdx += 2;
- }
-
- return true;
-}
-
-static bool DisassembleLdMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false,
- B);
-}
-
-static bool DisassembleStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true, B);
-}
-
-// The algorithm for disassembly of LdStMulFrm is different from others because
-// it explicitly populates the two predicate operands after the base register.
-// After that, we need to populate the reglist with each affected register
-// encoded as an MCOperand.
-static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 4 && "LdStMulFrm expects NumOps >= 4");
- NumOpsAdded = 0;
-
- unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn));
-
- // Writeback to base, if necessary.
- if (Opcode == ARM::LDMIA_UPD || Opcode == ARM::STMIA_UPD ||
- Opcode == ARM::LDMDA_UPD || Opcode == ARM::STMDA_UPD ||
- Opcode == ARM::LDMDB_UPD || Opcode == ARM::STMDB_UPD ||
- Opcode == ARM::LDMIB_UPD || Opcode == ARM::STMIB_UPD) {
- MI.addOperand(MCOperand::CreateReg(Base));
- ++NumOpsAdded;
- }
-
- // Add the base register operand.
- MI.addOperand(MCOperand::CreateReg(Base));
-
- // Handling the two predicate operands before the reglist.
- int64_t CondVal = getCondField(insn);
- if (CondVal == 0xF)
- return false;
- MI.addOperand(MCOperand::CreateImm(CondVal));
- MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
-
- NumOpsAdded += 3;
-
- // Fill the variadic part of reglist.
- unsigned RegListBits = insn & ((1 << 16) - 1);
- for (unsigned i = 0; i < 16; ++i) {
- if ((RegListBits >> i) & 1) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- i)));
- ++NumOpsAdded;
- }
- }
-
- return true;
-}
-
-// LDREX, LDREXB, LDREXH: Rd Rn
-// LDREXD: Rd Rd+1 Rn
-// STREX, STREXB, STREXH: Rd Rm Rn
-// STREXD: Rd Rm Rm+1 Rn
-//
-// SWP, SWPB: Rd Rm Rn
-static bool DisassembleLdStExFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2
- && OpInfo[0].RegClass == ARM::GPRRegClassID
- && OpInfo[1].RegClass == ARM::GPRRegClassID
- && "Expect 2 reg operands");
-
- bool isStore = slice(insn, 20, 20) == 0;
- bool isDW = (Opcode == ARM::LDREXD || Opcode == ARM::STREXD);
-
- // Add the destination operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
-
- // Store register Exclusive needs a source operand.
- if (isStore) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- ++OpIdx;
-
- if (isDW) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn)+1)));
- ++OpIdx;
- }
- } else if (isDW) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn)+1)));
- ++OpIdx;
- }
-
- // Finally add the pointer operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
-
- return true;
-}
-
-// Misc. Arithmetic Instructions.
-// CLZ: Rd Rm
-// PKHBT, PKHTB: Rd Rn Rm , LSL/ASR #imm5
-// RBIT, REV, REV16, REVSH: Rd Rm
-static bool DisassembleArithMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2
- && OpInfo[0].RegClass == ARM::GPRRegClassID
- && OpInfo[1].RegClass == ARM::GPRRegClassID
- && "Expect 2 reg operands");
-
- bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
-
- // Sanity check the registers, which should not be 15.
- if (decodeRd(insn) == 15 || decodeRm(insn) == 15)
- return false;
- if (ThreeReg && decodeRn(insn) == 15)
- return false;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
-
- if (ThreeReg) {
- assert(NumOps >= 4 && "Expect >= 4 operands");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- ++OpIdx;
-
- // If there is still an operand info left which is an immediate operand, add
- // an additional imm5 LSL/ASR operand.
- if (ThreeReg && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // Extract the 5-bit immediate field Inst{11-7}.
- unsigned ShiftAmt = (insn >> ARMII::ShiftShift) & 0x1F;
- if (Opcode == ARM::PKHBT || Opcode == ARM::PKHTB)
- MI.addOperand(MCOperand::CreateImm(ShiftAmt));
- else
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ARM_AM::no_shift,
- ShiftAmt)));
- ++OpIdx;
- }
-
- return true;
-}
-
-/// DisassembleSatFrm - Disassemble saturate instructions:
-/// SSAT, SSAT16, USAT, and USAT16.
-static bool DisassembleSatFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- // A8.6.183 SSAT
- // if d == 15 || n == 15 then UNPREDICTABLE;
- if (decodeRd(insn) == 15 || decodeRm(insn) == 15)
- return false;
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- NumOpsAdded = MCID.getNumOperands() - 2; // ignore predicate operands
-
- // Disassemble register def.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
-
- unsigned Pos = slice(insn, 20, 16);
- MI.addOperand(MCOperand::CreateImm(Pos));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
-
- if (NumOpsAdded == 4) {
- // Inst{6} encodes the shift type.
- bool isASR = slice(insn, 6, 6);
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShAmt = slice(insn, 11, 7);
- MI.addOperand(MCOperand::CreateImm(isASR << 5 | ShAmt));
- }
- return true;
-}
-
-// Extend instructions.
-// SXT* and UXT*: Rd [Rn] Rm [rot_imm].
-// The 2nd operand register is Rn and the 3rd operand regsiter is Rm for the
-// three register operand form. Otherwise, Rn=0b1111 and only Rm is used.
-static bool DisassembleExtFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- // A8.6.220 SXTAB
- // if d == 15 || m == 15 then UNPREDICTABLE;
- if (decodeRd(insn) == 15 || decodeRm(insn) == 15)
- return false;
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2
- && OpInfo[0].RegClass == ARM::GPRRegClassID
- && OpInfo[1].RegClass == ARM::GPRRegClassID
- && "Expect 2 reg operands");
-
- bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- ++OpIdx;
-
- if (ThreeReg) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- ++OpIdx;
-
- // If there is still an operand info left which is an immediate operand, add
- // an additional rotate immediate operand.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // Extract the 2-bit rotate field Inst{11-10}.
- unsigned rot = (insn >> ARMII::ExtRotImmShift) & 3;
- MI.addOperand(MCOperand::CreateImm(rot));
- ++OpIdx;
- }
-
- return true;
-}
-
-/////////////////////////////////////
-// //
-// Utility Functions For VFP //
-// //
-/////////////////////////////////////
-
-// Extract/Decode Dd/Sd:
-//
-// SP => d = UInt(Vd:D)
-// DP => d = UInt(D:Vd)
-static unsigned decodeVFPRd(uint32_t insn, bool isSPVFP) {
- return isSPVFP ? (decodeRd(insn) << 1 | getDBit(insn))
- : (decodeRd(insn) | getDBit(insn) << 4);
-}
-
-// Extract/Decode Dn/Sn:
-//
-// SP => n = UInt(Vn:N)
-// DP => n = UInt(N:Vn)
-static unsigned decodeVFPRn(uint32_t insn, bool isSPVFP) {
- return isSPVFP ? (decodeRn(insn) << 1 | getNBit(insn))
- : (decodeRn(insn) | getNBit(insn) << 4);
-}
-
-// Extract/Decode Dm/Sm:
-//
-// SP => m = UInt(Vm:M)
-// DP => m = UInt(M:Vm)
-static unsigned decodeVFPRm(uint32_t insn, bool isSPVFP) {
- return isSPVFP ? (decodeRm(insn) << 1 | getMBit(insn))
- : (decodeRm(insn) | getMBit(insn) << 4);
-}
-
-// A7.5.1
-static APInt VFPExpandImm(unsigned char byte, unsigned N) {
- assert(N == 32 || N == 64);
-
- uint64_t Result;
- unsigned bit6 = slice(byte, 6, 6);
- if (N == 32) {
- Result = slice(byte, 7, 7) << 31 | slice(byte, 5, 0) << 19;
- if (bit6)
- Result |= 0x1f << 25;
- else
- Result |= 0x1 << 30;
- } else {
- Result = (uint64_t)slice(byte, 7, 7) << 63 |
- (uint64_t)slice(byte, 5, 0) << 48;
- if (bit6)
- Result |= 0xffULL << 54;
- else
- Result |= 0x1ULL << 62;
- }
- return APInt(N, Result);
-}
-
-// VFP Unary Format Instructions:
-//
-// VCMP[E]ZD, VCMP[E]ZS: compares one floating-point register with zero
-// VCVTDS, VCVTSD: converts between double-precision and single-precision
-// The rest of the instructions have homogeneous [VFP]Rd and [VFP]Rm registers.
-static bool DisassembleVFPUnaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 1 && "VFPUnaryFrm expects NumOps >= 1");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned RegClass = OpInfo[OpIdx].RegClass;
- assert((RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID) &&
- "Reg operand expected");
- bool isSP = (RegClass == ARM::SPRRegClassID);
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, decodeVFPRd(insn, isSP))));
- ++OpIdx;
-
- // Early return for compare with zero instructions.
- if (Opcode == ARM::VCMPEZD || Opcode == ARM::VCMPEZS
- || Opcode == ARM::VCMPZD || Opcode == ARM::VCMPZS)
- return true;
-
- RegClass = OpInfo[OpIdx].RegClass;
- assert((RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID) &&
- "Reg operand expected");
- isSP = (RegClass == ARM::SPRRegClassID);
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, decodeVFPRm(insn, isSP))));
- ++OpIdx;
-
- return true;
-}
-
-// All the instructions have homogeneous [VFP]Rd, [VFP]Rn, and [VFP]Rm regs.
-// Some of them have operand constraints which tie the first operand in the
-// InOperandList to that of the dst. As far as asm printing is concerned, this
-// tied_to operand is simply skipped.
-static bool DisassembleVFPBinaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 3 && "VFPBinaryFrm expects NumOps >= 3");
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned RegClass = OpInfo[OpIdx].RegClass;
- assert((RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID) &&
- "Reg operand expected");
- bool isSP = (RegClass == ARM::SPRRegClassID);
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, decodeVFPRd(insn, isSP))));
- ++OpIdx;
-
- // Skip tied_to operand constraint.
- if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1) {
- assert(NumOps >= 4 && "Expect >=4 operands");
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, decodeVFPRn(insn, isSP))));
- ++OpIdx;
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, decodeVFPRm(insn, isSP))));
- ++OpIdx;
-
- return true;
-}
-
-// A8.6.295 vcvt (floating-point <-> integer)
-// Int to FP: VSITOD, VSITOS, VUITOD, VUITOS
-// FP to Int: VTOSI[Z|R]D, VTOSI[Z|R]S, VTOUI[Z|R]D, VTOUI[Z|R]S
-//
-// A8.6.297 vcvt (floating-point and fixed-point)
-// Dd|Sd Dd|Sd(TIED_TO) #fbits(= 16|32 - UInt(imm4:i))
-static bool DisassembleVFPConv1Frm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 2 && "VFPConv1Frm expects NumOps >= 2");
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- bool SP = slice(insn, 8, 8) == 0; // A8.6.295 & A8.6.297
- bool fixed_point = slice(insn, 17, 17) == 1; // A8.6.297
- unsigned RegClassID = SP ? ARM::SPRRegClassID : ARM::DPRRegClassID;
-
- if (fixed_point) {
- // A8.6.297
- assert(NumOps >= 3 && "Expect >= 3 operands");
- int size = slice(insn, 7, 7) == 0 ? 16 : 32;
- int fbits = size - (slice(insn,3,0) << 1 | slice(insn,5,5));
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClassID,
- decodeVFPRd(insn, SP))));
-
- assert(MCID.getOperandConstraint(1, MCOI::TIED_TO) != -1 &&
- "Tied to operand expected");
- MI.addOperand(MI.getOperand(0));
-
- assert(OpInfo[2].RegClass < 0 && !OpInfo[2].isPredicate() &&
- !OpInfo[2].isOptionalDef() && "Imm operand expected");
- MI.addOperand(MCOperand::CreateImm(fbits));
-
- NumOpsAdded = 3;
- } else {
- // A8.6.295
- // The Rd (destination) and Rm (source) bits have different interpretations
- // depending on their single-precisonness.
- unsigned d, m;
- if (slice(insn, 18, 18) == 1) { // to_integer operation
- d = decodeVFPRd(insn, true /* Is Single Precision */);
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::SPRRegClassID, d)));
- m = decodeVFPRm(insn, SP);
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassID, m)));
- } else {
- d = decodeVFPRd(insn, SP);
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassID, d)));
- m = decodeVFPRm(insn, true /* Is Single Precision */);
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::SPRRegClassID, m)));
- }
- NumOpsAdded = 2;
- }
-
- return true;
-}
-
-// VMOVRS - A8.6.330
-// Rt => Rd; Sn => UInt(Vn:N)
-static bool DisassembleVFPConv2Frm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 2 && "VFPConv2Frm expects NumOps >= 2");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- decodeVFPRn(insn, true))));
- NumOpsAdded = 2;
- return true;
-}
-
-// VMOVRRD - A8.6.332
-// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm)
-//
-// VMOVRRS - A8.6.331
-// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1
-static bool DisassembleVFPConv3Frm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 3 && "VFPConv3Frm expects NumOps >= 3");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- OpIdx = 2;
-
- if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) {
- unsigned Sm = decodeVFPRm(insn, true);
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- Sm)));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- Sm+1)));
- OpIdx += 2;
- } else {
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::DPRRegClassID,
- decodeVFPRm(insn, false))));
- ++OpIdx;
- }
- return true;
-}
-
-// VMOVSR - A8.6.330
-// Rt => Rd; Sn => UInt(Vn:N)
-static bool DisassembleVFPConv4Frm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 2 && "VFPConv4Frm expects NumOps >= 2");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- decodeVFPRn(insn, true))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- NumOpsAdded = 2;
- return true;
-}
-
-// VMOVDRR - A8.6.332
-// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm)
-//
-// VMOVRRS - A8.6.331
-// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1
-static bool DisassembleVFPConv5Frm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 3 && "VFPConv5Frm expects NumOps >= 3");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) {
- unsigned Sm = decodeVFPRm(insn, true);
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- Sm)));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::SPRRegClassID,
- Sm+1)));
- OpIdx += 2;
- } else {
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::DPRRegClassID,
- decodeVFPRm(insn, false))));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- OpIdx += 2;
- return true;
-}
-
-// VFP Load/Store Instructions.
-// VLDRD, VLDRS, VSTRD, VSTRS
-static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3");
-
- bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS);
- unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID;
-
- // Extract Dd/Sd for operand 0.
- unsigned RegD = decodeVFPRd(insn, isSPVFP);
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassID, RegD)));
-
- unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn));
- MI.addOperand(MCOperand::CreateReg(Base));
-
- // Next comes the AM5 Opcode.
- ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
- unsigned char Imm8 = insn & 0xFF;
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(AddrOpcode, Imm8)));
-
- NumOpsAdded = 3;
-
- return true;
-}
-
-// VFP Load/Store Multiple Instructions.
-// We have an optional write back reg, the base, and two predicate operands.
-// It is then followed by a reglist of either DPR(s) or SPR(s).
-//
-// VLDMD[_UPD], VLDMS[_UPD], VSTMD[_UPD], VSTMS[_UPD]
-static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 4 && "VFPLdStMulFrm expects NumOps >= 4");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn));
-
- // Writeback to base, if necessary.
- if (Opcode == ARM::VLDMDIA_UPD || Opcode == ARM::VLDMSIA_UPD ||
- Opcode == ARM::VLDMDDB_UPD || Opcode == ARM::VLDMSDB_UPD ||
- Opcode == ARM::VSTMDIA_UPD || Opcode == ARM::VSTMSIA_UPD ||
- Opcode == ARM::VSTMDDB_UPD || Opcode == ARM::VSTMSDB_UPD) {
- MI.addOperand(MCOperand::CreateReg(Base));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(Base));
-
- // Handling the two predicate operands before the reglist.
- int64_t CondVal = getCondField(insn);
- if (CondVal == 0xF)
- return false;
- MI.addOperand(MCOperand::CreateImm(CondVal));
- MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
-
- OpIdx += 3;
-
- bool isSPVFP = (Opcode == ARM::VLDMSIA ||
- Opcode == ARM::VLDMSIA_UPD || Opcode == ARM::VLDMSDB_UPD ||
- Opcode == ARM::VSTMSIA ||
- Opcode == ARM::VSTMSIA_UPD || Opcode == ARM::VSTMSDB_UPD);
- unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID;
-
- // Extract Dd/Sd.
- unsigned RegD = decodeVFPRd(insn, isSPVFP);
-
- // Fill the variadic part of reglist.
- unsigned char Imm8 = insn & 0xFF;
- unsigned Regs = isSPVFP ? Imm8 : Imm8/2;
-
- // Apply some sanity checks before proceeding.
- if (Regs == 0 || (RegD + Regs) > 32 || (!isSPVFP && Regs > 16))
- return false;
-
- for (unsigned i = 0; i < Regs; ++i) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassID,
- RegD + i)));
- ++OpIdx;
- }
-
- return true;
-}
-
-// Misc. VFP Instructions.
-// FMSTAT (vmrs with Rt=0b1111, i.e., to apsr_nzcv and no register operand)
-// FCONSTD (DPR and a VFPf64Imm operand)
-// FCONSTS (SPR and a VFPf32Imm operand)
-// VMRS/VMSR (GPR operand)
-static bool DisassembleVFPMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- if (Opcode == ARM::FMSTAT)
- return true;
-
- assert(NumOps >= 2 && "VFPMiscFrm expects >=2 operands");
-
- unsigned RegEnum = 0;
- switch (OpInfo[0].RegClass) {
- case ARM::DPRRegClassID:
- RegEnum = getRegisterEnum(B, ARM::DPRRegClassID, decodeVFPRd(insn, false));
- break;
- case ARM::SPRRegClassID:
- RegEnum = getRegisterEnum(B, ARM::SPRRegClassID, decodeVFPRd(insn, true));
- break;
- case ARM::GPRRegClassID:
- RegEnum = getRegisterEnum(B, ARM::GPRRegClassID, decodeRd(insn));
- break;
- default:
- assert(0 && "Invalid reg class id");
- return false;
- }
-
- MI.addOperand(MCOperand::CreateReg(RegEnum));
- ++OpIdx;
-
- // Extract/decode the f64/f32 immediate.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // The asm syntax specifies the floating point value, not the 8-bit literal.
- APInt immRaw = VFPExpandImm(slice(insn,19,16) << 4 | slice(insn, 3, 0),
- Opcode == ARM::FCONSTD ? 64 : 32);
- APFloat immFP = APFloat(immRaw, true);
- double imm = Opcode == ARM::FCONSTD ? immFP.convertToDouble() :
- immFP.convertToFloat();
- MI.addOperand(MCOperand::CreateFPImm(imm));
-
- ++OpIdx;
- }
-
- return true;
-}
-
-// DisassembleThumbFrm() is defined in ThumbDisassemblerCore.h file.
-#include "ThumbDisassemblerCore.h"
-
-/////////////////////////////////////////////////////
-// //
-// Utility Functions For ARM Advanced SIMD //
-// //
-/////////////////////////////////////////////////////
-
-// The following NEON namings are based on A8.6.266 VABA, VABAL. Notice that
-// A8.6.303 VDUP (ARM core register)'s D/Vd pair is the N/Vn pair of VABA/VABAL.
-
-// A7.3 Register encoding
-
-// Extract/Decode NEON D/Vd:
-//
-// Note that for quadword, Qd = UInt(D:Vd<3:1>) = Inst{22:15-13}, whereas for
-// doubleword, Dd = UInt(D:Vd). We compensate for this difference by
-// handling it in the getRegisterEnum() utility function.
-// D = Inst{22}, Vd = Inst{15-12}
-static unsigned decodeNEONRd(uint32_t insn) {
- return ((insn >> ARMII::NEON_D_BitShift) & 1) << 4
- | ((insn >> ARMII::NEON_RegRdShift) & ARMII::NEONRegMask);
-}
-
-// Extract/Decode NEON N/Vn:
-//
-// Note that for quadword, Qn = UInt(N:Vn<3:1>) = Inst{7:19-17}, whereas for
-// doubleword, Dn = UInt(N:Vn). We compensate for this difference by
-// handling it in the getRegisterEnum() utility function.
-// N = Inst{7}, Vn = Inst{19-16}
-static unsigned decodeNEONRn(uint32_t insn) {
- return ((insn >> ARMII::NEON_N_BitShift) & 1) << 4
- | ((insn >> ARMII::NEON_RegRnShift) & ARMII::NEONRegMask);
-}
-
-// Extract/Decode NEON M/Vm:
-//
-// Note that for quadword, Qm = UInt(M:Vm<3:1>) = Inst{5:3-1}, whereas for
-// doubleword, Dm = UInt(M:Vm). We compensate for this difference by
-// handling it in the getRegisterEnum() utility function.
-// M = Inst{5}, Vm = Inst{3-0}
-static unsigned decodeNEONRm(uint32_t insn) {
- return ((insn >> ARMII::NEON_M_BitShift) & 1) << 4
- | ((insn >> ARMII::NEON_RegRmShift) & ARMII::NEONRegMask);
-}
-
-namespace {
-enum ElemSize {
- ESizeNA = 0,
- ESize8 = 8,
- ESize16 = 16,
- ESize32 = 32,
- ESize64 = 64
-};
-} // End of unnamed namespace
-
-// size field -> Inst{11-10}
-// index_align field -> Inst{7-4}
-//
-// The Lane Index interpretation depends on the Data Size:
-// 8 (encoded as size = 0b00) -> Index = index_align[3:1]
-// 16 (encoded as size = 0b01) -> Index = index_align[3:2]
-// 32 (encoded as size = 0b10) -> Index = index_align[3]
-//
-// Ref: A8.6.317 VLD4 (single 4-element structure to one lane).
-static unsigned decodeLaneIndex(uint32_t insn) {
- unsigned size = insn >> 10 & 3;
- assert((size == 0 || size == 1 || size == 2) &&
- "Encoding error: size should be either 0, 1, or 2");
-
- unsigned index_align = insn >> 4 & 0xF;
- return (index_align >> 1) >> size;
-}
-
-// imm64 = AdvSIMDExpandImm(op, cmode, i:imm3:imm4)
-// op = Inst{5}, cmode = Inst{11-8}
-// i = Inst{24} (ARM architecture)
-// imm3 = Inst{18-16}, imm4 = Inst{3-0}
-// Ref: Table A7-15 Modified immediate values for Advanced SIMD instructions.
-static uint64_t decodeN1VImm(uint32_t insn, ElemSize esize) {
- unsigned char op = (insn >> 5) & 1;
- unsigned char cmode = (insn >> 8) & 0xF;
- unsigned char Imm8 = ((insn >> 24) & 1) << 7 |
- ((insn >> 16) & 7) << 4 |
- (insn & 0xF);
- return (op << 12) | (cmode << 8) | Imm8;
-}
-
-// A8.6.339 VMUL, VMULL (by scalar)
-// ESize16 => m = Inst{2-0} (Vm<2:0>) D0-D7
-// ESize32 => m = Inst{3-0} (Vm<3:0>) D0-D15
-static unsigned decodeRestrictedDm(uint32_t insn, ElemSize esize) {
- switch (esize) {
- case ESize16:
- return insn & 7;
- case ESize32:
- return insn & 0xF;
- default:
- assert(0 && "Unreachable code!");
- return 0;
- }
-}
-
-// A8.6.339 VMUL, VMULL (by scalar)
-// ESize16 => index = Inst{5:3} (M:Vm<3>) D0-D7
-// ESize32 => index = Inst{5} (M) D0-D15
-static unsigned decodeRestrictedDmIndex(uint32_t insn, ElemSize esize) {
- switch (esize) {
- case ESize16:
- return (((insn >> 5) & 1) << 1) | ((insn >> 3) & 1);
- case ESize32:
- return (insn >> 5) & 1;
- default:
- assert(0 && "Unreachable code!");
- return 0;
- }
-}
-
-// A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD)
-// (64 - <fbits>) is encoded as imm6, i.e., Inst{21-16}.
-static unsigned decodeVCVTFractionBits(uint32_t insn) {
- return 64 - ((insn >> 16) & 0x3F);
-}
-
-// A8.6.302 VDUP (scalar)
-// ESize8 => index = Inst{19-17}
-// ESize16 => index = Inst{19-18}
-// ESize32 => index = Inst{19}
-static unsigned decodeNVLaneDupIndex(uint32_t insn, ElemSize esize) {
- switch (esize) {
- case ESize8:
- return (insn >> 17) & 7;
- case ESize16:
- return (insn >> 18) & 3;
- case ESize32:
- return (insn >> 19) & 1;
- default:
- assert(0 && "Unspecified element size!");
- return 0;
- }
-}
-
-// A8.6.328 VMOV (ARM core register to scalar)
-// A8.6.329 VMOV (scalar to ARM core register)
-// ESize8 => index = Inst{21:6-5}
-// ESize16 => index = Inst{21:6}
-// ESize32 => index = Inst{21}
-static unsigned decodeNVLaneOpIndex(uint32_t insn, ElemSize esize) {
- switch (esize) {
- case ESize8:
- return ((insn >> 21) & 1) << 2 | ((insn >> 5) & 3);
- case ESize16:
- return ((insn >> 21) & 1) << 1 | ((insn >> 6) & 1);
- case ESize32:
- return ((insn >> 21) & 1);
- default:
- assert(0 && "Unspecified element size!");
- return 0;
- }
-}
-
-// Imm6 = Inst{21-16}, L = Inst{7}
-//
-// LeftShift == true (A8.6.367 VQSHL, A8.6.387 VSLI):
-// case L:imm6 of
-// '0001xxx' => esize = 8; shift_amount = imm6 - 8
-// '001xxxx' => esize = 16; shift_amount = imm6 - 16
-// '01xxxxx' => esize = 32; shift_amount = imm6 - 32
-// '1xxxxxx' => esize = 64; shift_amount = imm6
-//
-// LeftShift == false (A8.6.376 VRSHR, A8.6.368 VQSHRN):
-// case L:imm6 of
-// '0001xxx' => esize = 8; shift_amount = 16 - imm6
-// '001xxxx' => esize = 16; shift_amount = 32 - imm6
-// '01xxxxx' => esize = 32; shift_amount = 64 - imm6
-// '1xxxxxx' => esize = 64; shift_amount = 64 - imm6
-//
-static unsigned decodeNVSAmt(uint32_t insn, bool LeftShift) {
- ElemSize esize = ESizeNA;
- unsigned L = (insn >> 7) & 1;
- unsigned imm6 = (insn >> 16) & 0x3F;
- if (L == 0) {
- if (imm6 >> 3 == 1)
- esize = ESize8;
- else if (imm6 >> 4 == 1)
- esize = ESize16;
- else if (imm6 >> 5 == 1)
- esize = ESize32;
- else
- assert(0 && "Wrong encoding of Inst{7:21-16}!");
- } else
- esize = ESize64;
-
- if (LeftShift)
- return esize == ESize64 ? imm6 : (imm6 - esize);
- else
- return esize == ESize64 ? (esize - imm6) : (2*esize - imm6);
-}
-
-// A8.6.305 VEXT
-// Imm4 = Inst{11-8}
-static unsigned decodeN3VImm(uint32_t insn) {
- return (insn >> 8) & 0xF;
-}
-
-// VLD*
-// D[d] D[d2] ... Rn [TIED_TO Rn] align [Rm]
-// VLD*LN*
-// D[d] D[d2] ... Rn [TIED_TO Rn] align [Rm] TIED_TO ... imm(idx)
-// VST*
-// Rn [TIED_TO Rn] align [Rm] D[d] D[d2] ...
-// VST*LN*
-// Rn [TIED_TO Rn] align [Rm] D[d] D[d2] ... [imm(idx)]
-//
-// Correctly set VLD*/VST*'s TIED_TO GPR, as the asm printer needs it.
-static bool DisassembleNLdSt0(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, bool Store, bool DblSpaced,
- unsigned alignment, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
-
- // At least one DPR register plus addressing mode #6.
- assert(NumOps >= 3 && "Expect >= 3 operands");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // We have homogeneous NEON registers for Load/Store.
- unsigned RegClass = 0;
-
- // Double-spaced registers have increments of 2.
- unsigned Inc = DblSpaced ? 2 : 1;
-
- unsigned Rn = decodeRn(insn);
- unsigned Rm = decodeRm(insn);
- unsigned Rd = decodeNEONRd(insn);
-
- // A7.7.1 Advanced SIMD addressing mode.
- bool WB = Rm != 15;
-
- // LLVM Addressing Mode #6.
- unsigned RmEnum = 0;
- if (WB && Rm != 13)
- RmEnum = getRegisterEnum(B, ARM::GPRRegClassID, Rm);
-
- if (Store) {
- // Consume possible WB, AddrMode6, possible increment reg, the DPR/QPR's,
- // then possible lane index.
- assert(OpIdx < NumOps && OpInfo[0].RegClass == ARM::GPRRegClassID &&
- "Reg operand expected");
-
- if (WB) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- Rn)));
- ++OpIdx;
- }
-
- assert((OpIdx+1) < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- OpInfo[OpIdx + 1].RegClass < 0 && "Addrmode #6 Operands expected");
- // addrmode6 := (ops GPR:$addr, i32imm)
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- Rn)));
- MI.addOperand(MCOperand::CreateImm(alignment)); // Alignment
- OpIdx += 2;
-
- if (WB) {
- MI.addOperand(MCOperand::CreateReg(RmEnum));
- ++OpIdx;
- }
-
- assert(OpIdx < NumOps &&
- (OpInfo[OpIdx].RegClass == ARM::DPRRegClassID ||
- OpInfo[OpIdx].RegClass == ARM::QPRRegClassID) &&
- "Reg operand expected");
-
- RegClass = OpInfo[OpIdx].RegClass;
- while (OpIdx < NumOps && (unsigned)OpInfo[OpIdx].RegClass == RegClass) {
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, Rd)));
- Rd += Inc;
- ++OpIdx;
- }
-
- // Handle possible lane index.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn)));
- ++OpIdx;
- }
-
- } else {
- // Consume the DPR/QPR's, possible WB, AddrMode6, possible incrment reg,
- // possible TIED_TO DPR/QPR's (ignored), then possible lane index.
- RegClass = OpInfo[0].RegClass;
-
- while (OpIdx < NumOps && (unsigned)OpInfo[OpIdx].RegClass == RegClass) {
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass, Rd)));
- Rd += Inc;
- ++OpIdx;
- }
-
- if (WB) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- Rn)));
- ++OpIdx;
- }
-
- assert((OpIdx+1) < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID &&
- OpInfo[OpIdx + 1].RegClass < 0 && "Addrmode #6 Operands expected");
- // addrmode6 := (ops GPR:$addr, i32imm)
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- Rn)));
- MI.addOperand(MCOperand::CreateImm(alignment)); // Alignment
- OpIdx += 2;
-
- if (WB) {
- MI.addOperand(MCOperand::CreateReg(RmEnum));
- ++OpIdx;
- }
-
- while (OpIdx < NumOps && (unsigned)OpInfo[OpIdx].RegClass == RegClass) {
- assert(MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1 &&
- "Tied to operand expected");
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Handle possible lane index.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn)));
- ++OpIdx;
- }
- }
-
- // Accessing registers past the end of the NEON register file is not
- // defined.
- if (Rd > 32)
- return false;
-
- return true;
-}
-
-// A8.6.308, A8.6.311, A8.6.314, A8.6.317.
-static bool Align4OneLaneInst(unsigned elem, unsigned size,
- unsigned index_align, unsigned & alignment) {
- unsigned bits = 0;
- switch (elem) {
- default:
- return false;
- case 1:
- // A8.6.308
- if (size == 0)
- return slice(index_align, 0, 0) == 0;
- else if (size == 1) {
- bits = slice(index_align, 1, 0);
- if (bits != 0 && bits != 1)
- return false;
- if (bits == 1)
- alignment = 16;
- return true;
- } else if (size == 2) {
- bits = slice(index_align, 2, 0);
- if (bits != 0 && bits != 3)
- return false;
- if (bits == 3)
- alignment = 32;
- return true;;
- }
- return true;
- case 2:
- // A8.6.311
- if (size == 0) {
- if (slice(index_align, 0, 0) == 1)
- alignment = 16;
- return true;
- } if (size == 1) {
- if (slice(index_align, 0, 0) == 1)
- alignment = 32;
- return true;
- } else if (size == 2) {
- if (slice(index_align, 1, 1) != 0)
- return false;
- if (slice(index_align, 0, 0) == 1)
- alignment = 64;
- return true;;
- }
- return true;
- case 3:
- // A8.6.314
- if (size == 0) {
- if (slice(index_align, 0, 0) != 0)
- return false;
- return true;
- } if (size == 1) {
- if (slice(index_align, 0, 0) != 0)
- return false;
- return true;
- return true;
- } else if (size == 2) {
- if (slice(index_align, 1, 0) != 0)
- return false;
- return true;;
- }
- return true;
- case 4:
- // A8.6.317
- if (size == 0) {
- if (slice(index_align, 0, 0) == 1)
- alignment = 32;
- return true;
- } if (size == 1) {
- if (slice(index_align, 0, 0) == 1)
- alignment = 64;
- return true;
- } else if (size == 2) {
- bits = slice(index_align, 1, 0);
- if (bits == 3)
- return false;
- if (bits == 1)
- alignment = 64;
- else if (bits == 2)
- alignment = 128;
- return true;;
- }
- return true;
- }
-}
-
-// A7.7
-// If L (Inst{21}) == 0, store instructions.
-// Find out about double-spaced-ness of the Opcode and pass it on to
-// DisassembleNLdSt0().
-static bool DisassembleNLdSt(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const StringRef Name = ARMInsts[Opcode].Name;
- bool DblSpaced = false;
- // 0 represents standard alignment, i.e., unaligned data access.
- unsigned alignment = 0;
-
- unsigned elem = 0; // legal values: {1, 2, 3, 4}
- if (Name.startswith("VST1") || Name.startswith("VLD1"))
- elem = 1;
-
- if (Name.startswith("VST2") || Name.startswith("VLD2"))
- elem = 2;
-
- if (Name.startswith("VST3") || Name.startswith("VLD3"))
- elem = 3;
-
- if (Name.startswith("VST4") || Name.startswith("VLD4"))
- elem = 4;
-
- if (Name.find("LN") != std::string::npos) {
- // To one lane instructions.
- // See, for example, 8.6.317 VLD4 (single 4-element structure to one lane).
-
- // Utility function takes number of elements, size, and index_align.
- if (!Align4OneLaneInst(elem,
- slice(insn, 11, 10),
- slice(insn, 7, 4),
- alignment))
- return false;
-
- // <size> == 16 && Inst{5} == 1 --> DblSpaced = true
- if (Name.endswith("16") || Name.endswith("16_UPD"))
- DblSpaced = slice(insn, 5, 5) == 1;
-
- // <size> == 32 && Inst{6} == 1 --> DblSpaced = true
- if (Name.endswith("32") || Name.endswith("32_UPD"))
- DblSpaced = slice(insn, 6, 6) == 1;
- } else if (Name.find("DUP") != std::string::npos) {
- // Single element (or structure) to all lanes.
- // Inst{9-8} encodes the number of element(s) in the structure, with:
- // 0b00 (VLD1DUP) (for this, a bit makes sense only for data size 16 and 32.
- // 0b01 (VLD2DUP)
- // 0b10 (VLD3DUP) (for this, a bit must be encoded as 0)
- // 0b11 (VLD4DUP)
- //
- // Inst{7-6} encodes the data size, with:
- // 0b00 => 8, 0b01 => 16, 0b10 => 32
- //
- // Inst{4} (the a bit) encodes the align action (0: standard alignment)
- unsigned elem = slice(insn, 9, 8) + 1;
- unsigned a = slice(insn, 4, 4);
- if (elem != 3) {
- // 0b11 is not a valid encoding for Inst{7-6}.
- if (slice(insn, 7, 6) == 3)
- return false;
- unsigned data_size = 8 << slice(insn, 7, 6);
- // For VLD1DUP, a bit makes sense only for data size of 16 and 32.
- if (a && data_size == 8)
- return false;
-
- // Now we can calculate the alignment!
- if (a)
- alignment = elem * data_size;
- } else {
- if (a) {
- // A8.6.315 VLD3 (single 3-element structure to all lanes)
- // The a bit must be encoded as 0.
- return false;
- }
- }
- } else {
- // Multiple n-element structures with type encoded as Inst{11-8}.
- // See, for example, A8.6.316 VLD4 (multiple 4-element structures).
-
- // Inst{5-4} encodes alignment.
- unsigned align = slice(insn, 5, 4);
- switch (align) {
- default:
- break;
- case 1:
- alignment = 64; break;
- case 2:
- alignment = 128; break;
- case 3:
- alignment = 256; break;
- }
-
- unsigned type = slice(insn, 11, 8);
- // Reject UNDEFINED instructions based on type and align.
- // Plus set DblSpaced flag where appropriate.
- switch (elem) {
- default:
- break;
- case 1:
- // n == 1
- // A8.6.307 & A8.6.391
- if ((type == 7 && slice(align, 1, 1) == 1) ||
- (type == 10 && align == 3) ||
- (type == 6 && slice(align, 1, 1) == 1))
- return false;
- break;
- case 2:
- // n == 2 && type == 0b1001 -> DblSpaced = true
- // A8.6.310 & A8.6.393
- if ((type == 8 || type == 9) && align == 3)
- return false;
- DblSpaced = (type == 9);
- break;
- case 3:
- // n == 3 && type == 0b0101 -> DblSpaced = true
- // A8.6.313 & A8.6.395
- if (slice(insn, 7, 6) == 3 || slice(align, 1, 1) == 1)
- return false;
- DblSpaced = (type == 5);
- break;
- case 4:
- // n == 4 && type == 0b0001 -> DblSpaced = true
- // A8.6.316 & A8.6.397
- if (slice(insn, 7, 6) == 3)
- return false;
- DblSpaced = (type == 1);
- break;
- }
- }
- return DisassembleNLdSt0(MI, Opcode, insn, NumOps, NumOpsAdded,
- slice(insn, 21, 21) == 0, DblSpaced, alignment/8, B);
-}
-
-// VMOV (immediate)
-// Qd/Dd imm
-// VBIC (immediate)
-// VORR (immediate)
-// Qd/Dd imm src(=Qd/Dd)
-static bool DisassembleN1RegModImmFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
-
- assert(NumOps >= 2 &&
- (OpInfo[0].RegClass == ARM::DPRRegClassID ||
- OpInfo[0].RegClass == ARM::QPRRegClassID) &&
- (OpInfo[1].RegClass < 0) &&
- "Expect 1 reg operand followed by 1 imm operand");
-
- // Qd/Dd = Inst{22:15-12} => NEON Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[0].RegClass,
- decodeNEONRd(insn))));
-
- ElemSize esize = ESizeNA;
- switch (Opcode) {
- case ARM::VMOVv8i8:
- case ARM::VMOVv16i8:
- esize = ESize8;
- break;
- case ARM::VMOVv4i16:
- case ARM::VMOVv8i16:
- case ARM::VMVNv4i16:
- case ARM::VMVNv8i16:
- case ARM::VBICiv4i16:
- case ARM::VBICiv8i16:
- case ARM::VORRiv4i16:
- case ARM::VORRiv8i16:
- esize = ESize16;
- break;
- case ARM::VMOVv2i32:
- case ARM::VMOVv4i32:
- case ARM::VMVNv2i32:
- case ARM::VMVNv4i32:
- case ARM::VBICiv2i32:
- case ARM::VBICiv4i32:
- case ARM::VORRiv2i32:
- case ARM::VORRiv4i32:
- esize = ESize32;
- break;
- case ARM::VMOVv1i64:
- case ARM::VMOVv2i64:
- esize = ESize64;
- break;
- default:
- assert(0 && "Unexpected opcode!");
- return false;
- }
-
- // One register and a modified immediate value.
- // Add the imm operand.
- MI.addOperand(MCOperand::CreateImm(decodeN1VImm(insn, esize)));
-
- NumOpsAdded = 2;
-
- // VBIC/VORRiv*i* variants have an extra $src = $Vd to be filled in.
- if (NumOps >= 3 &&
- (OpInfo[2].RegClass == ARM::DPRRegClassID ||
- OpInfo[2].RegClass == ARM::QPRRegClassID)) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[0].RegClass,
- decodeNEONRd(insn))));
- NumOpsAdded += 1;
- }
-
- return true;
-}
-
-namespace {
-enum N2VFlag {
- N2V_None,
- N2V_VectorDupLane,
- N2V_VectorConvert_Between_Float_Fixed
-};
-} // End of unnamed namespace
-
-// Vector Convert [between floating-point and fixed-point]
-// Qd/Dd Qm/Dm [fbits]
-//
-// Vector Duplicate Lane (from scalar to all elements) Instructions.
-// VDUPLN16d, VDUPLN16q, VDUPLN32d, VDUPLN32q, VDUPLN8d, VDUPLN8q:
-// Qd/Dd Dm index
-//
-// Vector Move Long:
-// Qd Dm
-//
-// Vector Move Narrow:
-// Dd Qm
-//
-// Others
-static bool DisassembleNVdVmOptImm(MCInst &MI, unsigned Opc, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, N2VFlag Flag, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opc];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
-
- assert(NumOps >= 2 &&
- (OpInfo[0].RegClass == ARM::DPRRegClassID ||
- OpInfo[0].RegClass == ARM::QPRRegClassID) &&
- (OpInfo[1].RegClass == ARM::DPRRegClassID ||
- OpInfo[1].RegClass == ARM::QPRRegClassID) &&
- "Expect >= 2 operands and first 2 as reg operands");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- ElemSize esize = ESizeNA;
- if (Flag == N2V_VectorDupLane) {
- // VDUPLN has its index embedded. Its size can be inferred from the Opcode.
- assert(Opc >= ARM::VDUPLN16d && Opc <= ARM::VDUPLN8q &&
- "Unexpected Opcode");
- esize = (Opc == ARM::VDUPLN8d || Opc == ARM::VDUPLN8q) ? ESize8
- : ((Opc == ARM::VDUPLN16d || Opc == ARM::VDUPLN16q) ? ESize16
- : ESize32);
- }
-
- // Qd/Dd = Inst{22:15-12} => NEON Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeNEONRd(insn))));
- ++OpIdx;
-
- // VPADAL...
- if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1) {
- // TIED_TO operand.
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Dm = Inst{5:3-0} => NEON Rm
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeNEONRm(insn))));
- ++OpIdx;
-
- // VZIP and others have two TIED_TO reg operands.
- int Idx;
- while (OpIdx < NumOps &&
- (Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // Add TIED_TO operand.
- MI.addOperand(MI.getOperand(Idx));
- ++OpIdx;
- }
-
- // Add the imm operand, if required.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
-
- unsigned imm = 0xFFFFFFFF;
-
- if (Flag == N2V_VectorDupLane)
- imm = decodeNVLaneDupIndex(insn, esize);
- if (Flag == N2V_VectorConvert_Between_Float_Fixed)
- imm = decodeVCVTFractionBits(insn);
-
- assert(imm != 0xFFFFFFFF && "Internal error");
- MI.addOperand(MCOperand::CreateImm(imm));
- ++OpIdx;
- }
-
- return true;
-}
-
-static bool DisassembleN2RegFrm(MCInst &MI, unsigned Opc, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVmOptImm(MI, Opc, insn, NumOps, NumOpsAdded,
- N2V_None, B);
-}
-static bool DisassembleNVCVTFrm(MCInst &MI, unsigned Opc, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVmOptImm(MI, Opc, insn, NumOps, NumOpsAdded,
- N2V_VectorConvert_Between_Float_Fixed, B);
-}
-static bool DisassembleNVecDupLnFrm(MCInst &MI, unsigned Opc, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVmOptImm(MI, Opc, insn, NumOps, NumOpsAdded,
- N2V_VectorDupLane, B);
-}
-
-// Vector Shift [Accumulate] Instructions.
-// Qd/Dd [Qd/Dd (TIED_TO)] Qm/Dm ShiftAmt
-//
-// Vector Shift Left Long (with maximum shift count) Instructions.
-// VSHLLi16, VSHLLi32, VSHLLi8: Qd Dm imm (== size)
-//
-static bool DisassembleNVectorShift(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, bool LeftShift, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
-
- assert(NumOps >= 3 &&
- (OpInfo[0].RegClass == ARM::DPRRegClassID ||
- OpInfo[0].RegClass == ARM::QPRRegClassID) &&
- (OpInfo[1].RegClass == ARM::DPRRegClassID ||
- OpInfo[1].RegClass == ARM::QPRRegClassID) &&
- "Expect >= 3 operands and first 2 as reg operands");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // Qd/Dd = Inst{22:15-12} => NEON Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeNEONRd(insn))));
- ++OpIdx;
-
- if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1) {
- // TIED_TO operand.
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- assert((OpInfo[OpIdx].RegClass == ARM::DPRRegClassID ||
- OpInfo[OpIdx].RegClass == ARM::QPRRegClassID) &&
- "Reg operand expected");
-
- // Qm/Dm = Inst{5:3-0} => NEON Rm
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeNEONRm(insn))));
- ++OpIdx;
-
- assert(OpInfo[OpIdx].RegClass < 0 && "Imm operand expected");
-
- // Add the imm operand.
-
- // VSHLL has maximum shift count as the imm, inferred from its size.
- unsigned Imm;
- switch (Opcode) {
- default:
- Imm = decodeNVSAmt(insn, LeftShift);
- break;
- case ARM::VSHLLi8:
- Imm = 8;
- break;
- case ARM::VSHLLi16:
- Imm = 16;
- break;
- case ARM::VSHLLi32:
- Imm = 32;
- break;
- }
- MI.addOperand(MCOperand::CreateImm(Imm));
- ++OpIdx;
-
- return true;
-}
-
-// Left shift instructions.
-static bool DisassembleN2RegVecShLFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVectorShift(MI, Opcode, insn, NumOps, NumOpsAdded, true,
- B);
-}
-// Right shift instructions have different shift amount interpretation.
-static bool DisassembleN2RegVecShRFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVectorShift(MI, Opcode, insn, NumOps, NumOpsAdded, false,
- B);
-}
-
-namespace {
-enum N3VFlag {
- N3V_None,
- N3V_VectorExtract,
- N3V_VectorShift,
- N3V_Multiply_By_Scalar
-};
-} // End of unnamed namespace
-
-// NEON Three Register Instructions with Optional Immediate Operand
-//
-// Vector Extract Instructions.
-// Qd/Dd Qn/Dn Qm/Dm imm4
-//
-// Vector Shift (Register) Instructions.
-// Qd/Dd Qm/Dm Qn/Dn (notice the order of m, n)
-//
-// Vector Multiply [Accumulate/Subtract] [Long] By Scalar Instructions.
-// Qd/Dd Qn/Dn RestrictedDm index
-//
-// Others
-static bool DisassembleNVdVnVmOptImm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, N3VFlag Flag, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
-
- // No checking for OpInfo[2] because of MOVDneon/MOVQ with only two regs.
- assert(NumOps >= 3 &&
- (OpInfo[0].RegClass == ARM::DPRRegClassID ||
- OpInfo[0].RegClass == ARM::QPRRegClassID) &&
- (OpInfo[1].RegClass == ARM::DPRRegClassID ||
- OpInfo[1].RegClass == ARM::QPRRegClassID) &&
- "Expect >= 3 operands and first 2 as reg operands");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- bool VdVnVm = Flag == N3V_VectorShift ? false : true;
- bool IsImm4 = Flag == N3V_VectorExtract ? true : false;
- bool IsDmRestricted = Flag == N3V_Multiply_By_Scalar ? true : false;
- ElemSize esize = ESizeNA;
- if (Flag == N3V_Multiply_By_Scalar) {
- unsigned size = (insn >> 20) & 3;
- if (size == 1) esize = ESize16;
- if (size == 2) esize = ESize32;
- assert (esize == ESize16 || esize == ESize32);
- }
-
- // Qd/Dd = Inst{22:15-12} => NEON Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeNEONRd(insn))));
- ++OpIdx;
-
- // VABA, VABAL, VBSLd, VBSLq, ...
- if (MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1) {
- // TIED_TO operand.
- MI.addOperand(MCOperand::CreateReg(0));
- ++OpIdx;
- }
-
- // Dn = Inst{7:19-16} => NEON Rn
- // or
- // Dm = Inst{5:3-0} => NEON Rm
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- VdVnVm ? decodeNEONRn(insn)
- : decodeNEONRm(insn))));
- ++OpIdx;
-
- // Dm = Inst{5:3-0} => NEON Rm
- // or
- // Dm is restricted to D0-D7 if size is 16, D0-D15 otherwise
- // or
- // Dn = Inst{7:19-16} => NEON Rn
- unsigned m = VdVnVm ? (IsDmRestricted ? decodeRestrictedDm(insn, esize)
- : decodeNEONRm(insn))
- : decodeNEONRn(insn);
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, OpInfo[OpIdx].RegClass, m)));
- ++OpIdx;
-
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // Add the imm operand.
- unsigned Imm = 0;
- if (IsImm4)
- Imm = decodeN3VImm(insn);
- else if (IsDmRestricted)
- Imm = decodeRestrictedDmIndex(insn, esize);
- else {
- assert(0 && "Internal error: unreachable code!");
- return false;
- }
-
- MI.addOperand(MCOperand::CreateImm(Imm));
- ++OpIdx;
- }
-
- return true;
-}
-
-static bool DisassembleN3RegFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVnVmOptImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- N3V_None, B);
-}
-static bool DisassembleN3RegVecShFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVnVmOptImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- N3V_VectorShift, B);
-}
-static bool DisassembleNVecExtractFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVnVmOptImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- N3V_VectorExtract, B);
-}
-static bool DisassembleNVecMulScalarFrm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- return DisassembleNVdVnVmOptImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- N3V_Multiply_By_Scalar, B);
-}
-
-// Vector Table Lookup
-//
-// VTBL1, VTBX1: Dd [Dd(TIED_TO)] Dn Dm
-// VTBL2, VTBX2: Dd [Dd(TIED_TO)] Dn Dn+1 Dm
-// VTBL3, VTBX3: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dm
-// VTBL4, VTBX4: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dn+3 Dm
-static bool DisassembleNVTBLFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::DPRRegClassID &&
- OpInfo[1].RegClass == ARM::DPRRegClassID &&
- OpInfo[2].RegClass == ARM::DPRRegClassID &&
- "Expect >= 3 operands and first 3 as reg operands");
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned Rn = decodeNEONRn(insn);
-
- // {Dn} encoded as len = 0b00
- // {Dn Dn+1} encoded as len = 0b01
- // {Dn Dn+1 Dn+2 } encoded as len = 0b10
- // {Dn Dn+1 Dn+2 Dn+3} encoded as len = 0b11
- unsigned Len = slice(insn, 9, 8) + 1;
-
- // Dd (the destination vector)
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::DPRRegClassID,
- decodeNEONRd(insn))));
- ++OpIdx;
-
- // Process tied_to operand constraint.
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- MI.addOperand(MI.getOperand(Idx));
- ++OpIdx;
- }
-
- // Do the <list> now.
- for (unsigned i = 0; i < Len; ++i) {
- assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID &&
- "Reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::DPRRegClassID,
- Rn + i)));
- ++OpIdx;
- }
-
- // Dm (the index vector)
- assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID &&
- "Reg operand (index vector) expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::DPRRegClassID,
- decodeNEONRm(insn))));
- ++OpIdx;
-
- return true;
-}
-
-// Vector Get Lane (move scalar to ARM core register) Instructions.
-// VGETLNi32, VGETLNs16, VGETLNs8, VGETLNu16, VGETLNu8: Rt Dn index
-static bool DisassembleNGetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- assert(MCID.getNumDefs() == 1 && NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::GPRRegClassID &&
- OpInfo[1].RegClass == ARM::DPRRegClassID &&
- OpInfo[2].RegClass < 0 &&
- "Expect >= 3 operands with one dst operand");
-
- ElemSize esize =
- Opcode == ARM::VGETLNi32 ? ESize32
- : ((Opcode == ARM::VGETLNs16 || Opcode == ARM::VGETLNu16) ? ESize16
- : ESize8);
-
- // Rt = Inst{15-12} => ARM Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
-
- // Dn = Inst{7:19-16} => NEON Rn
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::DPRRegClassID,
- decodeNEONRn(insn))));
-
- MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize)));
-
- NumOpsAdded = 3;
- return true;
-}
-
-// Vector Set Lane (move ARM core register to scalar) Instructions.
-// VSETLNi16, VSETLNi32, VSETLNi8: Dd Dd (TIED_TO) Rt index
-static bool DisassembleNSetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- if (!OpInfo) return false;
-
- assert(MCID.getNumDefs() == 1 && NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::DPRRegClassID &&
- OpInfo[1].RegClass == ARM::DPRRegClassID &&
- MCID.getOperandConstraint(1, MCOI::TIED_TO) != -1 &&
- OpInfo[2].RegClass == ARM::GPRRegClassID &&
- OpInfo[3].RegClass < 0 &&
- "Expect >= 3 operands with one dst operand");
-
- ElemSize esize =
- Opcode == ARM::VSETLNi8 ? ESize8
- : (Opcode == ARM::VSETLNi16 ? ESize16
- : ESize32);
-
- // Dd = Inst{7:19-16} => NEON Rn
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::DPRRegClassID,
- decodeNEONRn(insn))));
-
- // TIED_TO operand.
- MI.addOperand(MCOperand::CreateReg(0));
-
- // Rt = Inst{15-12} => ARM Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
-
- MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize)));
-
- NumOpsAdded = 4;
- return true;
-}
-
-// Vector Duplicate Instructions (from ARM core register to all elements).
-// VDUP8d, VDUP16d, VDUP32d, VDUP8q, VDUP16q, VDUP32q: Qd/Dd Rt
-static bool DisassembleNDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
-
- assert(NumOps >= 2 &&
- (OpInfo[0].RegClass == ARM::DPRRegClassID ||
- OpInfo[0].RegClass == ARM::QPRRegClassID) &&
- OpInfo[1].RegClass == ARM::GPRRegClassID &&
- "Expect >= 2 operands and first 2 as reg operand");
-
- unsigned RegClass = OpInfo[0].RegClass;
-
- // Qd/Dd = Inst{7:19-16} => NEON Rn
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClass,
- decodeNEONRn(insn))));
-
- // Rt = Inst{15-12} => ARM Rd
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
-
- NumOpsAdded = 2;
- return true;
-}
-
-static inline bool PreLoadOpcode(unsigned Opcode) {
- switch(Opcode) {
- case ARM::PLDi12: case ARM::PLDrs:
- case ARM::PLDWi12: case ARM::PLDWrs:
- case ARM::PLIi12: case ARM::PLIrs:
- return true;
- default:
- return false;
- }
-}
-
-static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- // Preload Data/Instruction requires either 2 or 3 operands.
- // PLDi12, PLDWi12, PLIi12: addrmode_imm12
- // PLDrs, PLDWrs, PLIrs: ldst_so_reg
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
-
- if (Opcode == ARM::PLDi12 || Opcode == ARM::PLDWi12
- || Opcode == ARM::PLIi12) {
- unsigned Imm12 = slice(insn, 11, 0);
- bool Negative = getUBit(insn) == 0;
-
- // A8.6.118 PLD (literal) PLDWi12 with Rn=PC is transformed to PLDi12.
- if (Opcode == ARM::PLDWi12 && slice(insn, 19, 16) == 0xF) {
- DEBUG(errs() << "Rn == '1111': PLDWi12 morphed to PLDi12\n");
- MI.setOpcode(ARM::PLDi12);
- }
-
- // -0 is represented specially. All other values are as normal.
- int Offset = Negative ? -1 * Imm12 : Imm12;
- if (Imm12 == 0 && Negative)
- Offset = INT32_MIN;
-
- MI.addOperand(MCOperand::CreateImm(Offset));
- NumOpsAdded = 2;
- } else {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
-
- ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
-
- // Inst{6-5} encodes the shift opcode.
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5));
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShImm = slice(insn, 11, 7);
-
- // A8.4.1. Possible rrx or shift amount of 32...
- getImmShiftSE(ShOp, ShImm);
- MI.addOperand(MCOperand::CreateImm(
- ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp)));
- NumOpsAdded = 3;
- }
-
- return true;
-}
-
-static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- if (Opcode == ARM::DMB || Opcode == ARM::DSB || Opcode == ARM::ISB) {
- // Inst{3-0} encodes the memory barrier option for the variants.
- unsigned opt = slice(insn, 3, 0);
- switch (opt) {
- case ARM_MB::SY: case ARM_MB::ST:
- case ARM_MB::ISH: case ARM_MB::ISHST:
- case ARM_MB::NSH: case ARM_MB::NSHST:
- case ARM_MB::OSH: case ARM_MB::OSHST:
- MI.addOperand(MCOperand::CreateImm(opt));
- NumOpsAdded = 1;
- return true;
- default:
- return false;
- }
- }
-
- switch (Opcode) {
- case ARM::CLREX:
- case ARM::NOP:
- case ARM::TRAP:
- case ARM::YIELD:
- case ARM::WFE:
- case ARM::WFI:
- case ARM::SEV:
- return true;
- case ARM::SWP:
- case ARM::SWPB:
- // SWP, SWPB: Rd Rm Rn
- // Delegate to DisassembleLdStExFrm()....
- return DisassembleLdStExFrm(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- default:
- break;
- }
-
- if (Opcode == ARM::SETEND) {
- NumOpsAdded = 1;
- MI.addOperand(MCOperand::CreateImm(slice(insn, 9, 9)));
- return true;
- }
-
- // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
- // opcodes which match the same real instruction. This is needed since there's
- // no current handling of optional arguments. Fix here when a better handling
- // of optional arguments is implemented.
- if (Opcode == ARM::CPS3p) { // M = 1
- // Let's reject these impossible imod values by returning false:
- // 1. (imod=0b01)
- //
- // AsmPrinter cannot handle imod=0b00, plus (imod=0b00,M=1,iflags!=0) is an
- // invalid combination, so we just check for imod=0b00 here.
- if (slice(insn, 19, 18) == 0 || slice(insn, 19, 18) == 1)
- return false;
- MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
- MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
- NumOpsAdded = 3;
- return true;
- }
- if (Opcode == ARM::CPS2p) { // mode = 0, M = 0
- // Let's reject these impossible imod values by returning false:
- // 1. (imod=0b00,M=0)
- // 2. (imod=0b01)
- if (slice(insn, 19, 18) == 0 || slice(insn, 19, 18) == 1)
- return false;
- MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
- MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags
- NumOpsAdded = 2;
- return true;
- }
- if (Opcode == ARM::CPS1p) { // imod = 0, iflags = 0, M = 1
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
- NumOpsAdded = 1;
- return true;
- }
-
- // DBG has its option specified in Inst{3-0}.
- if (Opcode == ARM::DBG) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0)));
- NumOpsAdded = 1;
- return true;
- }
-
- // BKPT takes an imm32 val equal to ZeroExtend(Inst{19-8:3-0}).
- if (Opcode == ARM::BKPT) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 8) << 4 |
- slice(insn, 3, 0)));
- NumOpsAdded = 1;
- return true;
- }
-
- if (PreLoadOpcode(Opcode))
- return DisassemblePreLoadFrm(MI, Opcode, insn, NumOps, NumOpsAdded, B);
-
- assert(0 && "Unexpected misc instruction!");
- return false;
-}
-
-/// FuncPtrs - FuncPtrs maps ARMFormat to its corresponding DisassembleFP.
-/// We divide the disassembly task into different categories, with each one
-/// corresponding to a specific instruction encoding format. There could be
-/// exceptions when handling a specific format, and that is why the Opcode is
-/// also present in the function prototype.
-static const DisassembleFP FuncPtrs[] = {
- &DisassemblePseudo,
- &DisassembleMulFrm,
- &DisassembleBrFrm,
- &DisassembleBrMiscFrm,
- &DisassembleDPFrm,
- &DisassembleDPSoRegRegFrm,
- &DisassembleLdFrm,
- &DisassembleStFrm,
- &DisassembleLdMiscFrm,
- &DisassembleStMiscFrm,
- &DisassembleLdStMulFrm,
- &DisassembleLdStExFrm,
- &DisassembleArithMiscFrm,
- &DisassembleSatFrm,
- &DisassembleExtFrm,
- &DisassembleVFPUnaryFrm,
- &DisassembleVFPBinaryFrm,
- &DisassembleVFPConv1Frm,
- &DisassembleVFPConv2Frm,
- &DisassembleVFPConv3Frm,
- &DisassembleVFPConv4Frm,
- &DisassembleVFPConv5Frm,
- &DisassembleVFPLdStFrm,
- &DisassembleVFPLdStMulFrm,
- &DisassembleVFPMiscFrm,
- &DisassembleThumbFrm,
- &DisassembleMiscFrm,
- &DisassembleNGetLnFrm,
- &DisassembleNSetLnFrm,
- &DisassembleNDupFrm,
-
- // VLD and VST (including one lane) Instructions.
- &DisassembleNLdSt,
-
- // A7.4.6 One register and a modified immediate value
- // 1-Register Instructions with imm.
- // LLVM only defines VMOVv instructions.
- &DisassembleN1RegModImmFrm,
-
- // 2-Register Instructions with no imm.
- &DisassembleN2RegFrm,
-
- // 2-Register Instructions with imm (vector convert float/fixed point).
- &DisassembleNVCVTFrm,
-
- // 2-Register Instructions with imm (vector dup lane).
- &DisassembleNVecDupLnFrm,
-
- // Vector Shift Left Instructions.
- &DisassembleN2RegVecShLFrm,
-
- // Vector Shift Righ Instructions, which has different interpretation of the
- // shift amount from the imm6 field.
- &DisassembleN2RegVecShRFrm,
-
- // 3-Register Data-Processing Instructions.
- &DisassembleN3RegFrm,
-
- // Vector Shift (Register) Instructions.
- // D:Vd M:Vm N:Vn (notice that M:Vm is the first operand)
- &DisassembleN3RegVecShFrm,
-
- // Vector Extract Instructions.
- &DisassembleNVecExtractFrm,
-
- // Vector [Saturating Rounding Doubling] Multiply [Accumulate/Subtract] [Long]
- // By Scalar Instructions.
- &DisassembleNVecMulScalarFrm,
-
- // Vector Table Lookup uses byte indexes in a control vector to look up byte
- // values in a table and generate a new vector.
- &DisassembleNVTBLFrm,
-
- &DisassembleDPSoRegImmFrm,
-
-
- NULL
-};
-
-/// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder.
-/// The general idea is to set the Opcode for the MCInst, followed by adding
-/// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates
-/// to the Format-specific disassemble function for disassembly, followed by
-/// TryPredicateAndSBitModifier() to do PredicateOperand and OptionalDefOperand
-/// which follow the Dst/Src Operands.
-bool ARMBasicMCBuilder::BuildIt(MCInst &MI, uint32_t insn) {
- // Stage 1 sets the Opcode.
- MI.setOpcode(Opcode);
- // If the number of operands is zero, we're done!
- if (NumOps == 0)
- return true;
-
- // Stage 2 calls the format-specific disassemble function to build the operand
- // list.
- if (Disasm == NULL)
- return false;
- unsigned NumOpsAdded = 0;
- bool OK = (*Disasm)(MI, Opcode, insn, NumOps, NumOpsAdded, this);
-
- if (!OK || this->Err != 0) return false;
- if (NumOpsAdded >= NumOps)
- return true;
-
- // Stage 3 deals with operands unaccounted for after stage 2 is finished.
- // FIXME: Should this be done selectively?
- return TryPredicateAndSBitModifier(MI, Opcode, insn, NumOps - NumOpsAdded);
-}
-
-// A8.3 Conditional execution
-// A8.3.1 Pseudocode details of conditional execution
-// Condition bits '111x' indicate the instruction is always executed.
-static uint32_t CondCode(uint32_t CondField) {
- if (CondField == 0xF)
- return ARMCC::AL;
- return CondField;
-}
-
-/// DoPredicateOperands - DoPredicateOperands process the predicate operands
-/// of some Thumb instructions which come before the reglist operands. It
-/// returns true if the two predicate operands have been processed.
-bool ARMBasicMCBuilder::DoPredicateOperands(MCInst& MI, unsigned Opcode,
- uint32_t /* insn */, unsigned short NumOpsRemaining) {
-
- assert(NumOpsRemaining > 0 && "Invalid argument");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned Idx = MI.getNumOperands();
-
- // First, we check whether this instr specifies the PredicateOperand through
- // a pair of MCOperandInfos with isPredicate() property.
- if (NumOpsRemaining >= 2 &&
- OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() &&
- OpInfo[Idx].RegClass < 0 &&
- OpInfo[Idx+1].RegClass == ARM::CCRRegClassID)
- {
- // If we are inside an IT block, get the IT condition bits maintained via
- // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond().
- // See also A2.5.2.
- if (InITBlock())
- MI.addOperand(MCOperand::CreateImm(GetITCond()));
- else
- MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
- MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
- return true;
- }
-
- return false;
-}
-
-/// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process
-/// the possible Predicate and SBitModifier, to build the remaining MCOperand
-/// constituents.
-bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOpsRemaining) {
-
- assert(NumOpsRemaining > 0 && "Invalid argument");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- const std::string &Name = ARMInsts[Opcode].Name;
- unsigned Idx = MI.getNumOperands();
- uint64_t TSFlags = ARMInsts[Opcode].TSFlags;
-
- // First, we check whether this instr specifies the PredicateOperand through
- // a pair of MCOperandInfos with isPredicate() property.
- if (NumOpsRemaining >= 2 &&
- OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() &&
- OpInfo[Idx].RegClass < 0 &&
- OpInfo[Idx+1].RegClass == ARM::CCRRegClassID)
- {
- // If we are inside an IT block, get the IT condition bits maintained via
- // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond().
- // See also A2.5.2.
- if (InITBlock())
- MI.addOperand(MCOperand::CreateImm(GetITCond()));
- else {
- if (Name.length() > 1 && Name[0] == 't') {
- // Thumb conditional branch instructions have their cond field embedded,
- // like ARM.
- //
- // A8.6.16 B
- // Check for undefined encodings.
- unsigned cond;
- if (Name == "t2Bcc") {
- if ((cond = slice(insn, 25, 22)) >= 14)
- return false;
- MI.addOperand(MCOperand::CreateImm(CondCode(cond)));
- } else if (Name == "tBcc") {
- if ((cond = slice(insn, 11, 8)) == 14)
- return false;
- MI.addOperand(MCOperand::CreateImm(CondCode(cond)));
- } else
- MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
- } else {
- // ARM instructions get their condition field from Inst{31-28}.
- // We should reject Inst{31-28} = 0b1111 as invalid encoding.
- if (!isNEONDomain(TSFlags) && getCondField(insn) == 0xF)
- return false;
- MI.addOperand(MCOperand::CreateImm(CondCode(getCondField(insn))));
- }
- }
- MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
- Idx += 2;
- NumOpsRemaining -= 2;
- }
-
- if (NumOpsRemaining == 0)
- return true;
-
- // Next, if OptionalDefOperand exists, we check whether the 'S' bit is set.
- if (OpInfo[Idx].isOptionalDef() && OpInfo[Idx].RegClass==ARM::CCRRegClassID) {
- MI.addOperand(MCOperand::CreateReg(getSBit(insn) == 1 ? ARM::CPSR : 0));
- --NumOpsRemaining;
- }
-
- if (NumOpsRemaining == 0)
- return true;
- else
- return false;
-}
-
-/// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary
-/// after BuildIt is finished.
-bool ARMBasicMCBuilder::RunBuildAfterHook(bool Status, MCInst &MI,
- uint32_t insn) {
-
- if (!SP) return Status;
-
- if (Opcode == ARM::t2IT)
- Status = SP->InitIT(slice(insn, 7, 0)) ? Status : false;
- else if (InITBlock())
- SP->UpdateIT();
-
- return Status;
-}
-
-/// Opcode, Format, and NumOperands make up an ARM Basic MCBuilder.
-ARMBasicMCBuilder::ARMBasicMCBuilder(unsigned opc, ARMFormat format,
- unsigned short num)
- : Opcode(opc), Format(format), NumOps(num), SP(0), Err(0) {
- unsigned Idx = (unsigned)format;
- assert(Idx < (array_lengthof(FuncPtrs) - 1) && "Unknown format");
- Disasm = FuncPtrs[Idx];
-}
-
-/// CreateMCBuilder - Return an ARMBasicMCBuilder that can build up the MC
-/// infrastructure of an MCInst given the Opcode and Format of the instr.
-/// Return NULL if it fails to create/return a proper builder. API clients
-/// are responsible for freeing up of the allocated memory. Cacheing can be
-/// performed by the API clients to improve performance.
-ARMBasicMCBuilder *llvm::CreateMCBuilder(unsigned Opcode, ARMFormat Format) {
- // For "Unknown format", fail by returning a NULL pointer.
- if ((unsigned)Format >= (array_lengthof(FuncPtrs) - 1)) {
- DEBUG(errs() << "Unknown format\n");
- return 0;
- }
-
- return new ARMBasicMCBuilder(Opcode, Format,
- ARMInsts[Opcode].getNumOperands());
-}
-
-/// tryAddingSymbolicOperand - tryAddingSymbolicOperand trys to add a symbolic
-/// operand in place of the immediate Value in the MCInst. The immediate
-/// Value has had any PC adjustment made by the caller. If the getOpInfo()
-/// function was set as part of the setupBuilderForSymbolicDisassembly() call
-/// then that function is called to get any symbolic information at the
-/// builder's Address for this instrution. If that returns non-zero then the
-/// symbolic information it returns is used to create an MCExpr and that is
-/// added as an operand to the MCInst. This function returns true if it adds
-/// an operand to the MCInst and false otherwise.
-bool ARMBasicMCBuilder::tryAddingSymbolicOperand(uint64_t Value,
- uint64_t InstSize,
- MCInst &MI) {
- if (!GetOpInfo)
- return false;
-
- struct LLVMOpInfo1 SymbolicOp;
- SymbolicOp.Value = Value;
- if (!GetOpInfo(DisInfo, Address, 0 /* Offset */, InstSize, 1, &SymbolicOp))
- return false;
-
- const MCExpr *Add = NULL;
- if (SymbolicOp.AddSymbol.Present) {
- if (SymbolicOp.AddSymbol.Name) {
- StringRef Name(SymbolicOp.AddSymbol.Name);
- MCSymbol *Sym = Ctx->GetOrCreateSymbol(Name);
- Add = MCSymbolRefExpr::Create(Sym, *Ctx);
- } else {
- Add = MCConstantExpr::Create(SymbolicOp.AddSymbol.Value, *Ctx);
- }
- }
-
- const MCExpr *Sub = NULL;
- if (SymbolicOp.SubtractSymbol.Present) {
- if (SymbolicOp.SubtractSymbol.Name) {
- StringRef Name(SymbolicOp.SubtractSymbol.Name);
- MCSymbol *Sym = Ctx->GetOrCreateSymbol(Name);
- Sub = MCSymbolRefExpr::Create(Sym, *Ctx);
- } else {
- Sub = MCConstantExpr::Create(SymbolicOp.SubtractSymbol.Value, *Ctx);
- }
- }
-
- const MCExpr *Off = NULL;
- if (SymbolicOp.Value != 0)
- Off = MCConstantExpr::Create(SymbolicOp.Value, *Ctx);
-
- const MCExpr *Expr;
- if (Sub) {
- const MCExpr *LHS;
- if (Add)
- LHS = MCBinaryExpr::CreateSub(Add, Sub, *Ctx);
- else
- LHS = MCUnaryExpr::CreateMinus(Sub, *Ctx);
- if (Off != 0)
- Expr = MCBinaryExpr::CreateAdd(LHS, Off, *Ctx);
- else
- Expr = LHS;
- } else if (Add) {
- if (Off != 0)
- Expr = MCBinaryExpr::CreateAdd(Add, Off, *Ctx);
- else
- Expr = Add;
- } else {
- if (Off != 0)
- Expr = Off;
- else
- Expr = MCConstantExpr::Create(0, *Ctx);
- }
-
- if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_ARM_HI16)
- MI.addOperand(MCOperand::CreateExpr(ARMMCExpr::CreateUpper16(Expr, *Ctx)));
- else if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_ARM_LO16)
- MI.addOperand(MCOperand::CreateExpr(ARMMCExpr::CreateLower16(Expr, *Ctx)));
- else if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_None)
- MI.addOperand(MCOperand::CreateExpr(Expr));
- else
- assert("bad SymbolicOp.VariantKind");
-
- return true;
-}
diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
deleted file mode 100644
index c1ebd3edf8..0000000000
--- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
+++ /dev/null
@@ -1,337 +0,0 @@
-//===- ARMDisassemblerCore.h - ARM disassembler helpers ---------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is part of the ARM Disassembler.
-//
-// The first part defines the enumeration type of ARM instruction format, which
-// specifies the encoding used by the instruction, as well as a helper function
-// to convert the enums to printable char strings.
-//
-// It also contains code to represent the concepts of Builder and DisassembleFP
-// to solve the problem of disassembling an ARM instr.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ARMDISASSEMBLERCORE_H
-#define ARMDISASSEMBLERCORE_H
-
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm-c/Disassembler.h"
-#include "ARMBaseInstrInfo.h"
-#include "ARMRegisterInfo.h"
-#include "ARMDisassembler.h"
-
-namespace llvm {
-class MCContext;
-
-class ARMUtils {
-public:
- static const char *OpcodeName(unsigned Opcode);
-};
-
-/////////////////////////////////////////////////////
-// //
-// Enums and Utilities for ARM Instruction Format //
-// //
-/////////////////////////////////////////////////////
-
-#define ARM_FORMATS \
- ENTRY(ARM_FORMAT_PSEUDO, 0) \
- ENTRY(ARM_FORMAT_MULFRM, 1) \
- ENTRY(ARM_FORMAT_BRFRM, 2) \
- ENTRY(ARM_FORMAT_BRMISCFRM, 3) \
- ENTRY(ARM_FORMAT_DPFRM, 4) \
- ENTRY(ARM_FORMAT_DPSOREGREGFRM, 5) \
- ENTRY(ARM_FORMAT_LDFRM, 6) \
- ENTRY(ARM_FORMAT_STFRM, 7) \
- ENTRY(ARM_FORMAT_LDMISCFRM, 8) \
- ENTRY(ARM_FORMAT_STMISCFRM, 9) \
- ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \
- ENTRY(ARM_FORMAT_LDSTEXFRM, 11) \
- ENTRY(ARM_FORMAT_ARITHMISCFRM, 12) \
- ENTRY(ARM_FORMAT_SATFRM, 13) \
- ENTRY(ARM_FORMAT_EXTFRM, 14) \
- ENTRY(ARM_FORMAT_VFPUNARYFRM, 15) \
- ENTRY(ARM_FORMAT_VFPBINARYFRM, 16) \
- ENTRY(ARM_FORMAT_VFPCONV1FRM, 17) \
- ENTRY(ARM_FORMAT_VFPCONV2FRM, 18) \
- ENTRY(ARM_FORMAT_VFPCONV3FRM, 19) \
- ENTRY(ARM_FORMAT_VFPCONV4FRM, 20) \
- ENTRY(ARM_FORMAT_VFPCONV5FRM, 21) \
- ENTRY(ARM_FORMAT_VFPLDSTFRM, 22) \
- ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 23) \
- ENTRY(ARM_FORMAT_VFPMISCFRM, 24) \
- ENTRY(ARM_FORMAT_THUMBFRM, 25) \
- ENTRY(ARM_FORMAT_MISCFRM, 26) \
- ENTRY(ARM_FORMAT_NEONGETLNFRM, 27) \
- ENTRY(ARM_FORMAT_NEONSETLNFRM, 28) \
- ENTRY(ARM_FORMAT_NEONDUPFRM, 29) \
- ENTRY(ARM_FORMAT_NLdSt, 30) \
- ENTRY(ARM_FORMAT_N1RegModImm, 31) \
- ENTRY(ARM_FORMAT_N2Reg, 32) \
- ENTRY(ARM_FORMAT_NVCVT, 33) \
- ENTRY(ARM_FORMAT_NVecDupLn, 34) \
- ENTRY(ARM_FORMAT_N2RegVecShL, 35) \
- ENTRY(ARM_FORMAT_N2RegVecShR, 36) \
- ENTRY(ARM_FORMAT_N3Reg, 37) \
- ENTRY(ARM_FORMAT_N3RegVecSh, 38) \
- ENTRY(ARM_FORMAT_NVecExtract, 39) \
- ENTRY(ARM_FORMAT_NVecMulScalar, 40) \
- ENTRY(ARM_FORMAT_NVTBL, 41) \
- ENTRY(ARM_FORMAT_DPSOREGIMMFRM, 42)
-
-// ARM instruction format specifies the encoding used by the instruction.
-#define ENTRY(n, v) n = v,
-typedef enum {
- ARM_FORMATS
- ARM_FORMAT_NA
-} ARMFormat;
-#undef ENTRY
-
-// Converts enum to const char*.
-static const inline char *stringForARMFormat(ARMFormat form) {
-#define ENTRY(n, v) case n: return #n;
- switch(form) {
- ARM_FORMATS
- case ARM_FORMAT_NA:
- default:
- return "";
- }
-#undef ENTRY
-}
-
-/// Expands on the enum definitions from ARMBaseInstrInfo.h.
-/// They are being used by the disassembler implementation.
-namespace ARMII {
- enum {
- NEONRegMask = 15,
- GPRRegMask = 15,
- NEON_RegRdShift = 12,
- NEON_D_BitShift = 22,
- NEON_RegRnShift = 16,
- NEON_N_BitShift = 7,
- NEON_RegRmShift = 0,
- NEON_M_BitShift = 5
- };
-}
-
-/// Utility function for extracting [From, To] bits from a uint32_t.
-static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) {
- assert(From < 32 && To < 32 && From >= To);
- return (Bits >> To) & ((1 << (From - To + 1)) - 1);
-}
-
-/// Utility function for setting [From, To] bits to Val for a uint32_t.
-static inline void setSlice(unsigned &Bits, unsigned From, unsigned To,
- unsigned Val) {
- assert(From < 32 && To < 32 && From >= To);
- uint32_t Mask = ((1 << (From - To + 1)) - 1);
- Bits &= ~(Mask << To);
- Bits |= (Val & Mask) << To;
-}
-
-// Return an integer result equal to the number of bits of x that are ones.
-static inline uint32_t
-BitCount (uint64_t x)
-{
- // c accumulates the total bits set in x
- uint32_t c;
- for (c = 0; x; ++c)
- {
- x &= x - 1; // clear the least significant bit set
- }
- return c;
-}
-
-static inline bool
-BitIsSet (const uint64_t value, const uint64_t bit)
-{
- return (value & (1ull << bit)) != 0;
-}
-
-static inline bool
-BitIsClear (const uint64_t value, const uint64_t bit)
-{
- return (value & (1ull << bit)) == 0;
-}
-
-/// Various utilities for checking the target specific flags.
-
-/// A unary data processing instruction doesn't have an Rn operand.
-static inline bool isUnaryDP(uint64_t TSFlags) {
- return (TSFlags & ARMII::UnaryDP);
-}
-
-/// A NEON Domain instruction has cond field (Inst{31-28}) as 0b1111.
-static inline bool isNEONDomain(uint64_t TSFlags) {
- return (TSFlags & ARMII::DomainNEON) ||
- (TSFlags & ARMII::DomainNEONA8);
-}
-
-/// This four-bit field describes the addressing mode used.
-/// See also ARMBaseInstrInfo.h.
-static inline unsigned getAddrMode(uint64_t TSFlags) {
- return (TSFlags & ARMII::AddrModeMask);
-}
-
-/// {IndexModePre, IndexModePost}
-/// Only valid for load and store ops.
-/// See also ARMBaseInstrInfo.h.
-static inline unsigned getIndexMode(uint64_t TSFlags) {
- return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
-}
-
-/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList.
-static inline bool isPrePostLdSt(uint64_t TSFlags) {
- return (TSFlags & ARMII::IndexModeMask) != 0;
-}
-
-// Forward declaration.
-class ARMBasicMCBuilder;
-
-// Builder Object is mostly ignored except in some Thumb disassemble functions.
-typedef ARMBasicMCBuilder *BO;
-
-/// DisassembleFP - DisassembleFP points to a function that disassembles an insn
-/// and builds the MCOperand list upon disassembly. It returns false on failure
-/// or true on success. The number of operands added is updated upon success.
-typedef bool (*DisassembleFP)(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO Builder);
-
-/// CreateMCBuilder - Return an ARMBasicMCBuilder that can build up the MC
-/// infrastructure of an MCInst given the Opcode and Format of the instr.
-/// Return NULL if it fails to create/return a proper builder. API clients
-/// are responsible for freeing up of the allocated memory. Cacheing can be
-/// performed by the API clients to improve performance.
-extern ARMBasicMCBuilder *CreateMCBuilder(unsigned Opcode, ARMFormat Format);
-
-/// ARMBasicMCBuilder - ARMBasicMCBuilder represents an ARM MCInst builder that
-/// knows how to build up the MCOperand list.
-class ARMBasicMCBuilder {
- friend ARMBasicMCBuilder *CreateMCBuilder(unsigned Opcode, ARMFormat Format);
- unsigned Opcode;
- ARMFormat Format;
- unsigned short NumOps;
- DisassembleFP Disasm;
- Session *SP;
- int Err; // !=0 if the builder encounters some error condition during build.
-
-private:
- /// Opcode, Format, and NumOperands make up an ARM Basic MCBuilder.
- ARMBasicMCBuilder(unsigned opc, ARMFormat format, unsigned short num);
-
-public:
- ARMBasicMCBuilder(ARMBasicMCBuilder &B)
- : Opcode(B.Opcode), Format(B.Format), NumOps(B.NumOps), Disasm(B.Disasm),
- SP(B.SP), GetOpInfo(0), DisInfo(0), Ctx(0) {
- Err = 0;
- }
-
- virtual ~ARMBasicMCBuilder() {}
-
- void SetSession(Session *sp) {
- SP = sp;
- }
-
- void SetErr(int ErrCode) {
- Err = ErrCode;
- }
-
- /// DoPredicateOperands - DoPredicateOperands process the predicate operands
- /// of some Thumb instructions which come before the reglist operands. It
- /// returns true if the two predicate operands have been processed.
- bool DoPredicateOperands(MCInst& MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOpsRemaning);
-
- /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process
- /// the possible Predicate and SBitModifier, to build the remaining MCOperand
- /// constituents.
- bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOpsRemaning);
-
- /// InITBlock - InITBlock returns true if we are inside an IT block.
- bool InITBlock() {
- if (SP)
- return SP->ITCounter > 0;
-
- return false;
- }
-
- /// Build - Build delegates to BuildIt to perform the heavy liftling. After
- /// that, it invokes RunBuildAfterHook where some housekeepings can be done.
- virtual bool Build(MCInst &MI, uint32_t insn) {
- bool Status = BuildIt(MI, insn);
- return RunBuildAfterHook(Status, MI, insn);
- }
-
- /// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder.
- /// The general idea is to set the Opcode for the MCInst, followed by adding
- /// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates
- /// to the Format-specific disassemble function for disassembly, followed by
- /// TryPredicateAndSBitModifier() for PredicateOperand and OptionalDefOperand
- /// which follow the Dst/Src Operands.
- virtual bool BuildIt(MCInst &MI, uint32_t insn);
-
- /// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary
- /// after BuildIt is finished.
- virtual bool RunBuildAfterHook(bool Status, MCInst &MI, uint32_t insn);
-
-private:
- /// Get condition of the current IT instruction.
- unsigned GetITCond() {
- assert(SP);
- return slice(SP->ITState, 7, 4);
- }
-
-private:
- //
- // Hooks for symbolic disassembly via the public 'C' interface.
- //
- // The function to get the symbolic information for operands.
- LLVMOpInfoCallback GetOpInfo;
- // The pointer to the block of symbolic information for above call back.
- void *DisInfo;
- // The assembly context for creating symbols and MCExprs in place of
- // immediate operands when there is symbolic information.
- MCContext *Ctx;
- // The address of the instruction being disassembled.
- uint64_t Address;
-
-public:
- void setupBuilderForSymbolicDisassembly(LLVMOpInfoCallback getOpInfo,
- void *disInfo, MCContext *ctx,
- uint64_t address) {
- GetOpInfo = getOpInfo;
- DisInfo = disInfo;
- Ctx = ctx;
- Address = address;
- }
-
- uint64_t getBuilderAddress() const { return Address; }
-
- /// tryAddingSymbolicOperand - tryAddingSymbolicOperand trys to add a symbolic
- /// operand in place of the immediate Value in the MCInst. The immediate
- /// Value has had any PC adjustment made by the caller. If the getOpInfo()
- /// function was set as part of the setupBuilderForSymbolicDisassembly() call
- /// then that function is called to get any symbolic information at the
- /// builder's Address for this instrution. If that returns non-zero then the
- /// symbolic information it returns is used to create an MCExpr and that is
- /// added as an operand to the MCInst. This function returns true if it adds
- /// an operand to the MCInst and false otherwise.
- bool tryAddingSymbolicOperand(uint64_t Value, uint64_t InstSize, MCInst &MI);
-
-};
-
-} // namespace llvm
-
-#endif
diff --git a/lib/Target/ARM/Disassembler/CMakeLists.txt b/lib/Target/ARM/Disassembler/CMakeLists.txt
index 952dab53ec..da87751150 100644
--- a/lib/Target/ARM/Disassembler/CMakeLists.txt
+++ b/lib/Target/ARM/Disassembler/CMakeLists.txt
@@ -2,7 +2,6 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/
add_llvm_library(LLVMARMDisassembler
ARMDisassembler.cpp
- ARMDisassemblerCore.cpp
)
# workaround for hanging compilation on MSVC8, 9 and 10
if( MSVC_VERSION EQUAL 1400 OR MSVC_VERSION EQUAL 1500 OR MSVC_VERSION EQUAL 1600 )
diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
deleted file mode 100644
index a1b38f377a..0000000000
--- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
+++ /dev/null
@@ -1,2461 +0,0 @@
-//===- ThumbDisassemblerCore.h - Thumb disassembler helpers -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is part of the ARM Disassembler.
-// It contains code for disassembling a Thumb instr. It is to be included by
-// ARMDisassemblerCore.cpp because it contains the static DisassembleThumbFrm()
-// function which acts as the dispatcher to disassemble a Thumb instruction.
-//
-//===----------------------------------------------------------------------===//
-
-///////////////////////////////
-// //
-// Utility Functions //
-// //
-///////////////////////////////
-
-// Utilities for 16-bit Thumb instructions.
-/*
-15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- [ tRt ]
- [ tRm ] [ tRn ] [ tRd ]
- D [ Rm ] [ Rd ]
-
- [ imm3]
- [ imm5 ]
- i [ imm5 ]
- [ imm7 ]
- [ imm8 ]
- [ imm11 ]
-
- [ cond ]
-*/
-
-// Extract tRt: Inst{10-8}.
-static inline unsigned getT1tRt(uint32_t insn) {
- return slice(insn, 10, 8);
-}
-
-// Extract tRm: Inst{8-6}.
-static inline unsigned getT1tRm(uint32_t insn) {
- return slice(insn, 8, 6);
-}
-
-// Extract tRn: Inst{5-3}.
-static inline unsigned getT1tRn(uint32_t insn) {
- return slice(insn, 5, 3);
-}
-
-// Extract tRd: Inst{2-0}.
-static inline unsigned getT1tRd(uint32_t insn) {
- return slice(insn, 2, 0);
-}
-
-// Extract [D:Rd]: Inst{7:2-0}.
-static inline unsigned getT1Rd(uint32_t insn) {
- return slice(insn, 7, 7) << 3 | slice(insn, 2, 0);
-}
-
-// Extract Rm: Inst{6-3}.
-static inline unsigned getT1Rm(uint32_t insn) {
- return slice(insn, 6, 3);
-}
-
-// Extract imm3: Inst{8-6}.
-static inline unsigned getT1Imm3(uint32_t insn) {
- return slice(insn, 8, 6);
-}
-
-// Extract imm5: Inst{10-6}.
-static inline unsigned getT1Imm5(uint32_t insn) {
- return slice(insn, 10, 6);
-}
-
-// Extract i:imm5: Inst{9:7-3}.
-static inline unsigned getT1Imm6(uint32_t insn) {
- return slice(insn, 9, 9) << 5 | slice(insn, 7, 3);
-}
-
-// Extract imm7: Inst{6-0}.
-static inline unsigned getT1Imm7(uint32_t insn) {
- return slice(insn, 6, 0);
-}
-
-// Extract imm8: Inst{7-0}.
-static inline unsigned getT1Imm8(uint32_t insn) {
- return slice(insn, 7, 0);
-}
-
-// Extract imm11: Inst{10-0}.
-static inline unsigned getT1Imm11(uint32_t insn) {
- return slice(insn, 10, 0);
-}
-
-// Extract cond: Inst{11-8}.
-static inline unsigned getT1Cond(uint32_t insn) {
- return slice(insn, 11, 8);
-}
-
-static inline bool IsGPR(unsigned RegClass) {
- return RegClass == ARM::GPRRegClassID || RegClass == ARM::rGPRRegClassID;
-}
-
-// Utilities for 32-bit Thumb instructions.
-
-static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
-
-// Extract imm4: Inst{19-16}.
-static inline unsigned getImm4(uint32_t insn) {
- return slice(insn, 19, 16);
-}
-
-// Extract imm3: Inst{14-12}.
-static inline unsigned getImm3(uint32_t insn) {
- return slice(insn, 14, 12);
-}
-
-// Extract imm8: Inst{7-0}.
-static inline unsigned getImm8(uint32_t insn) {
- return slice(insn, 7, 0);
-}
-
-// A8.6.61 LDRB (immediate, Thumb) and friends
-// +/-: Inst{9}
-// imm8: Inst{7-0}
-static inline int decodeImm8(uint32_t insn) {
- int Offset = getImm8(insn);
- return slice(insn, 9, 9) ? Offset : -Offset;
-}
-
-// Extract imm12: Inst{11-0}.
-static inline unsigned getImm12(uint32_t insn) {
- return slice(insn, 11, 0);
-}
-
-// A8.6.63 LDRB (literal) and friends
-// +/-: Inst{23}
-// imm12: Inst{11-0}
-static inline int decodeImm12(uint32_t insn) {
- int Offset = getImm12(insn);
- return slice(insn, 23, 23) ? Offset : -Offset;
-}
-
-// Extract imm2: Inst{7-6}.
-static inline unsigned getImm2(uint32_t insn) {
- return slice(insn, 7, 6);
-}
-
-// For BFI, BFC, t2SBFX, and t2UBFX.
-// Extract lsb: Inst{14-12:7-6}.
-static inline unsigned getLsb(uint32_t insn) {
- return getImm3(insn) << 2 | getImm2(insn);
-}
-
-// For BFI and BFC.
-// Extract msb: Inst{4-0}.
-static inline unsigned getMsb(uint32_t insn) {
- return slice(insn, 4, 0);
-}
-
-// For t2SBFX and t2UBFX.
-// Extract widthminus1: Inst{4-0}.
-static inline unsigned getWidthMinus1(uint32_t insn) {
- return slice(insn, 4, 0);
-}
-
-// For t2ADDri12 and t2SUBri12.
-// imm12 = i:imm3:imm8;
-static inline unsigned getIImm3Imm8(uint32_t insn) {
- return slice(insn, 26, 26) << 11 | getImm3(insn) << 8 | getImm8(insn);
-}
-
-// For t2MOVi16 and t2MOVTi16.
-// imm16 = imm4:i:imm3:imm8;
-static inline unsigned getImm16(uint32_t insn) {
- return getImm4(insn) << 12 | slice(insn, 26, 26) << 11 |
- getImm3(insn) << 8 | getImm8(insn);
-}
-
-// Inst{5-4} encodes the shift type.
-static inline unsigned getShiftTypeBits(uint32_t insn) {
- return slice(insn, 5, 4);
-}
-
-// Inst{14-12}:Inst{7-6} encodes the imm5 shift amount.
-static inline unsigned getShiftAmtBits(uint32_t insn) {
- return getImm3(insn) << 2 | getImm2(insn);
-}
-
-// A8.6.17 BFC
-// Encoding T1 ARMv6T2, ARMv7
-// LLVM-specific encoding for #<lsb> and #<width>
-static inline bool getBitfieldInvMask(uint32_t insn, uint32_t &mask) {
- uint32_t lsb = getImm3(insn) << 2 | getImm2(insn);
- uint32_t msb = getMsb(insn);
- uint32_t Val = 0;
- if (msb < lsb) {
- DEBUG(errs() << "Encoding error: msb < lsb\n");
- return false;
- }
- for (uint32_t i = lsb; i <= msb; ++i)
- Val |= (1 << i);
- mask = ~Val;
- return true;
-}
-
-// A8.4 Shifts applied to a register
-// A8.4.1 Constant shifts
-// A8.4.3 Pseudocode details of instruction-specified shifts and rotates
-//
-// decodeImmShift() returns the shift amount and the the shift opcode.
-// Note that, as of Jan-06-2010, LLVM does not support rrx shifted operands yet.
-static inline unsigned decodeImmShift(unsigned bits2, unsigned imm5,
- ARM_AM::ShiftOpc &ShOp) {
-
- assert(imm5 < 32 && "Invalid imm5 argument");
- switch (bits2) {
- default: assert(0 && "No such value");
- case 0:
- ShOp = (imm5 == 0 ? ARM_AM::no_shift : ARM_AM::lsl);
- return imm5;
- case 1:
- ShOp = ARM_AM::lsr;
- return (imm5 == 0 ? 32 : imm5);
- case 2:
- ShOp = ARM_AM::asr;
- return (imm5 == 0 ? 32 : imm5);
- case 3:
- ShOp = (imm5 == 0 ? ARM_AM::rrx : ARM_AM::ror);
- return (imm5 == 0 ? 1 : imm5);
- }
-}
-
-// A6.3.2 Modified immediate constants in Thumb instructions
-//
-// ThumbExpandImm() returns the modified immediate constant given an imm12 for
-// Thumb data-processing instructions with modified immediate.
-// See also A6.3.1 Data-processing (modified immediate).
-static inline unsigned ThumbExpandImm(unsigned imm12) {
- assert(imm12 <= 0xFFF && "Invalid imm12 argument");
-
- // If the leading two bits is 0b00, the modified immediate constant is
- // obtained by splatting the low 8 bits into the first byte, every other byte,
- // or every byte of a 32-bit value.
- //
- // Otherwise, a rotate right of '1':imm12<6:0> by the amount imm12<11:7> is
- // performed.
-
- if (slice(imm12, 11, 10) == 0) {
- unsigned short control = slice(imm12, 9, 8);
- unsigned imm8 = slice(imm12, 7, 0);
- switch (control) {
- default:
- assert(0 && "No such value");
- return 0;
- case 0:
- return imm8;
- case 1:
- return imm8 << 16 | imm8;
- case 2:
- return imm8 << 24 | imm8 << 8;
- case 3:
- return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8;
- }
- } else {
- // A rotate is required.
- unsigned Val = 1 << 7 | slice(imm12, 6, 0);
- unsigned Amt = slice(imm12, 11, 7);
- return ARM_AM::rotr32(Val, Amt);
- }
-}
-
-static inline int decodeImm32_B_EncodingT3(uint32_t insn) {
- bool S = slice(insn, 26, 26);
- bool J1 = slice(insn, 13, 13);
- bool J2 = slice(insn, 11, 11);
- unsigned Imm21 = slice(insn, 21, 16) << 12 | slice(insn, 10, 0) << 1;
- if (S) Imm21 |= 1 << 20;
- if (J2) Imm21 |= 1 << 19;
- if (J1) Imm21 |= 1 << 18;
-
- return SignExtend32<21>(Imm21);
-}
-
-static inline int decodeImm32_B_EncodingT4(uint32_t insn) {
- unsigned S = slice(insn, 26, 26);
- bool I1 = slice(insn, 13, 13) == S;
- bool I2 = slice(insn, 11, 11) == S;
- unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1;
- if (S) Imm25 |= 1 << 24;
- if (I1) Imm25 |= 1 << 23;
- if (I2) Imm25 |= 1 << 22;
-
- return SignExtend32<25>(Imm25);
-}
-
-static inline int decodeImm32_BL(uint32_t insn) {
- unsigned S = slice(insn, 26, 26);
- bool I1 = slice(insn, 13, 13) == S;
- bool I2 = slice(insn, 11, 11) == S;
- unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1;
- if (S) Imm25 |= 1 << 24;
- if (I1) Imm25 |= 1 << 23;
- if (I2) Imm25 |= 1 << 22;
-
- return SignExtend32<25>(Imm25);
-}
-
-static inline int decodeImm32_BLX(uint32_t insn) {
- unsigned S = slice(insn, 26, 26);
- bool I1 = slice(insn, 13, 13) == S;
- bool I2 = slice(insn, 11, 11) == S;
- unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 1) << 2;
- if (S) Imm25 |= 1 << 24;
- if (I1) Imm25 |= 1 << 23;
- if (I2) Imm25 |= 1 << 22;
-
- return SignExtend32<25>(Imm25);
-}
-
-///////////////////////////////////////////////
-// //
-// Thumb1 instruction disassembly functions. //
-// //
-///////////////////////////////////////////////
-
-// See "Utilities for 16-bit Thumb instructions" for register naming convention.
-
-// A6.2.1 Shift (immediate), add, subtract, move, and compare
-//
-// shift immediate: tRd CPSR tRn imm5
-// add/sub register: tRd CPSR tRn tRm
-// add/sub 3-bit immediate: tRd CPSR tRn imm3
-// add/sub 8-bit immediate: tRt CPSR tRt(TIED_TO) imm8
-// mov/cmp immediate: tRt [CPSR] imm8 (CPSR present for mov)
-//
-// Special case:
-// tMOVSr: tRd tRn
-static bool DisassembleThumb1General(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID
- && "Invalid arguments");
-
- bool Imm3 = (Opcode == ARM::tADDi3 || Opcode == ARM::tSUBi3);
-
- // Use Rt implies use imm8.
- bool UseRt = (Opcode == ARM::tADDi8 || Opcode == ARM::tSUBi8 ||
- Opcode == ARM::tMOVi8 || Opcode == ARM::tCMPi8);
-
- // Add the destination operand.
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::tGPRRegClassID,
- UseRt ? getT1tRt(insn) : getT1tRd(insn))));
- ++OpIdx;
-
- // Check whether the next operand to be added is a CCR Register.
- if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) {
- assert(OpInfo[OpIdx].isOptionalDef() && "Optional def operand expected");
- MI.addOperand(MCOperand::CreateReg(B->InITBlock() ? 0 : ARM::CPSR));
- ++OpIdx;
- }
-
- // Check whether the next operand to be added is a Thumb1 Register.
- assert(OpIdx < NumOps && "More operands expected");
- if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) {
- // For UseRt, the reg operand is tied to the first reg operand.
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, ARM::tGPRRegClassID,
- UseRt ? getT1tRt(insn) : getT1tRn(insn))));
- ++OpIdx;
- }
-
- // Special case for tMOVSr.
- if (OpIdx == NumOps)
- return true;
-
- // The next available operand is either a reg operand or an imm operand.
- if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) {
- // Three register operand instructions.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRm(insn))));
- } else {
- assert(OpInfo[OpIdx].RegClass < 0 &&
- !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()
- && "Pure imm operand expected");
- unsigned Imm = 0;
- if (UseRt)
- Imm = getT1Imm8(insn);
- else if (Imm3)
- Imm = getT1Imm3(insn);
- else {
- Imm = getT1Imm5(insn);
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 12, 11));
- getImmShiftSE(ShOp, Imm);
- }
- MI.addOperand(MCOperand::CreateImm(Imm));
- }
- ++OpIdx;
-
- return true;
-}
-
-// A6.2.2 Data-processing
-//
-// tCMPr, tTST, tCMN: tRd tRn
-// tMVN, tRSB: tRd CPSR tRn
-// Others: tRd CPSR tRd(TIED_TO) tRn
-static bool DisassembleThumb1DP(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- (OpInfo[1].RegClass == ARM::CCRRegClassID
- || OpInfo[1].RegClass == ARM::tGPRRegClassID)
- && "Invalid arguments");
-
- // Add the destination operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRd(insn))));
- ++OpIdx;
-
- // Check whether the next operand to be added is a CCR Register.
- if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) {
- assert(OpInfo[OpIdx].isOptionalDef() && "Optional def operand expected");
- MI.addOperand(MCOperand::CreateReg(B->InITBlock() ? 0 : ARM::CPSR));
- ++OpIdx;
- }
-
- // We have either { tRd(TIED_TO), tRn } or { tRn } remaining.
- // Process the TIED_TO operand first.
-
- assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID
- && "Thumb reg operand expected");
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // The reg operand is tied to the first reg operand.
- MI.addOperand(MI.getOperand(Idx));
- ++OpIdx;
- }
-
- // Process possible next reg operand.
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) {
- // Add tRn operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRn(insn))));
- ++OpIdx;
- }
-
- return true;
-}
-
-// A6.2.3 Special data instructions and branch and exchange
-//
-// tADDhirr: Rd Rd(TIED_TO) Rm
-// tCMPhir: Rd Rm
-// tMOVr, tMOVgpr2gpr, tMOVgpr2tgpr, tMOVtgpr2gpr: Rd|tRd Rm|tRn
-// tBX: Rm
-// tBX_RET: 0 operand
-// tBX_RET_vararg: Rm
-// tBLXr: Rm
-// tBRIND: Rm
-static bool DisassembleThumb1Special(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- // tBX_RET has 0 operand.
- if (NumOps == 0)
- return true;
-
- // BX/BLX/tBRIND (indirect branch, i.e, mov pc, Rm) has 1 reg operand: Rm.
- if (Opcode==ARM::tBLXr || Opcode==ARM::tBX || Opcode==ARM::tBRIND) {
- if (Opcode == ARM::tBLXr) {
- // Handling the two predicate operands before the reg operand.
- if (!B->DoPredicateOperands(MI, Opcode, insn, NumOps))
- return false;
- NumOpsAdded += 2;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- getT1Rm(insn))));
- NumOpsAdded += 1;
-
- if (Opcode == ARM::tBX) {
- // Handling the two predicate operands after the reg operand.
- if (!B->DoPredicateOperands(MI, Opcode, insn, NumOps))
- return false;
- NumOpsAdded += 2;
- }
-
- return true;
- }
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- // Add the destination operand.
- unsigned RegClass = OpInfo[OpIdx].RegClass;
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass,
- IsGPR(RegClass) ? getT1Rd(insn)
- : getT1tRd(insn))));
- ++OpIdx;
-
- // We have either { Rd(TIED_TO), Rm } or { Rm|tRn } remaining.
- // Process the TIED_TO operand first.
-
- assert(OpIdx < NumOps && "More operands expected");
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // The reg operand is tied to the first reg operand.
- MI.addOperand(MI.getOperand(Idx));
- ++OpIdx;
- }
-
- // The next reg operand is either Rm or tRn.
- assert(OpIdx < NumOps && "More operands expected");
- RegClass = OpInfo[OpIdx].RegClass;
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RegClass,
- IsGPR(RegClass) ? getT1Rm(insn)
- : getT1tRn(insn))));
- ++OpIdx;
-
- return true;
-}
-
-// A8.6.59 LDR (literal)
-//
-// tLDRpci: tRt imm8*4
-static bool DisassembleThumb1LdPC(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- (OpInfo[1].RegClass < 0 &&
- !OpInfo[1].isPredicate() &&
- !OpInfo[1].isOptionalDef())
- && "Invalid arguments");
-
- // Add the destination operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRt(insn))));
-
- // And the (imm8 << 2) operand.
- MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn) << 2));
-
- NumOpsAdded = 2;
-
- return true;
-}
-
-// Thumb specific addressing modes (see ARMInstrThumb.td):
-//
-// t_addrmode_rr := reg + reg
-//
-// t_addrmode_s4 := reg + reg
-// reg + imm5 * 4
-//
-// t_addrmode_s2 := reg + reg
-// reg + imm5 * 2
-//
-// t_addrmode_s1 := reg + reg
-// reg + imm5
-//
-// t_addrmode_sp := sp + imm8 * 4
-//
-
-// A8.6.63 LDRB (literal)
-// A8.6.79 LDRSB (literal)
-// A8.6.75 LDRH (literal)
-// A8.6.83 LDRSH (literal)
-// A8.6.59 LDR (literal)
-//
-// These instrs calculate an address from the PC value and an immediate offset.
-// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1)
-static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 2 &&
- OpInfo[0].RegClass == ARM::GPRRegClassID &&
- OpInfo[1].RegClass < 0 &&
- "Expect >= 2 operands, first as reg, and second as imm operand");
-
- // Build the register operand, followed by the (+/-)imm12 immediate.
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRd(insn))));
-
- MI.addOperand(MCOperand::CreateImm(decodeImm12(insn)));
-
- NumOpsAdded = 2;
-
- return true;
-}
-
-
-// A6.2.4 Load/store single data item
-//
-// Load/Store Register (reg|imm): tRd tRn imm5|tRm
-// Load Register Signed Byte|Halfword: tRd tRn tRm
-static bool DisassembleThumb1LdSt(unsigned opA, MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- assert(NumOps >= 2
- && OpInfo[0].RegClass == ARM::tGPRRegClassID
- && OpInfo[1].RegClass == ARM::tGPRRegClassID
- && "Expect >= 2 operands and first two as thumb reg operands");
-
- // Add the destination reg and the base reg.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRd(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRn(insn))));
- OpIdx = 2;
-
- // We have either { imm5 } or { tRm } remaining.
- // Note that STR/LDR (register) should skip the imm5 offset operand for
- // t_addrmode_s[1|2|4].
-
- assert(OpIdx < NumOps && "More operands expected");
-
- if (OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate() &&
- !OpInfo[OpIdx].isOptionalDef()) {
- // Table A6-5 16-bit Thumb Load/store instructions
- // opA = 0b0101 for STR/LDR (register) and friends.
- // Otherwise, we have STR/LDR (immediate) and friends.
- assert(opA != 5 && "Immediate operand expected for this opcode");
- MI.addOperand(MCOperand::CreateImm(getT1Imm5(insn)));
- ++OpIdx;
- } else {
- // The next reg operand is tRm, the offset.
- assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID
- && "Thumb reg operand expected");
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRm(insn))));
- ++OpIdx;
- }
- return true;
-}
-
-// A6.2.4 Load/store single data item
-//
-// Load/Store Register SP relative: tRt ARM::SP imm8
-static bool DisassembleThumb1LdStSP(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert((Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi)
- && "Unexpected opcode");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- OpInfo[1].RegClass == ARM::GPRRegClassID &&
- (OpInfo[2].RegClass < 0 &&
- !OpInfo[2].isPredicate() &&
- !OpInfo[2].isOptionalDef())
- && "Invalid arguments");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRt(insn))));
- MI.addOperand(MCOperand::CreateReg(ARM::SP));
- MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn)));
- NumOpsAdded = 3;
- return true;
-}
-
-// Table A6-1 16-bit Thumb instruction encoding
-// A8.6.10 ADR
-//
-// tADDrPCi: tRt imm8
-static bool DisassembleThumb1AddPCi(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(Opcode == ARM::tADDrPCi && "Unexpected opcode");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- (OpInfo[1].RegClass < 0 &&
- !OpInfo[1].isPredicate() &&
- !OpInfo[1].isOptionalDef())
- && "Invalid arguments");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRt(insn))));
- MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn)));
- NumOpsAdded = 2;
- return true;
-}
-
-// Table A6-1 16-bit Thumb instruction encoding
-// A8.6.8 ADD (SP plus immediate)
-//
-// tADDrSPi: tRt ARM::SP imm8
-static bool DisassembleThumb1AddSPi(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(Opcode == ARM::tADDrSPi && "Unexpected opcode");
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- OpInfo[1].RegClass == ARM::GPRRegClassID &&
- (OpInfo[2].RegClass < 0 &&
- !OpInfo[2].isPredicate() &&
- !OpInfo[2].isOptionalDef())
- && "Invalid arguments");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRt(insn))));
- MI.addOperand(MCOperand::CreateReg(ARM::SP));
- MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn)));
- NumOpsAdded = 3;
- return true;
-}
-
-// tPUSH, tPOP: Pred-Imm Pred-CCR register_list
-//
-// where register_list = low registers + [lr] for PUSH or
-// low registers + [pc] for POP
-//
-// "low registers" is specified by Inst{7-0}
-// lr|pc is specified by Inst{8}
-static bool DisassembleThumb1PushPop(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert((Opcode == ARM::tPUSH || Opcode == ARM::tPOP) && "Unexpected opcode");
-
- unsigned &OpIdx = NumOpsAdded;
-
- // Handling the two predicate operands before the reglist.
- if (B->DoPredicateOperands(MI, Opcode, insn, NumOps))
- OpIdx += 2;
- else {
- DEBUG(errs() << "Expected predicate operands not found.\n");
- return false;
- }
-
- unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15)
- | slice(insn, 7, 0);
-
- // Fill the variadic part of reglist.
- for (unsigned i = 0; i < 16; ++i) {
- if ((RegListBits >> i) & 1) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- i)));
- ++OpIdx;
- }
- }
-
- return true;
-}
-
-// A6.2.5 Miscellaneous 16-bit instructions
-// Delegate to DisassembleThumb1PushPop() for tPUSH & tPOP.
-//
-// tADDspi, tSUBspi: ARM::SP ARM::SP(TIED_TO) imm7
-// t2IT: firstcond=Inst{7-4} mask=Inst{3-0}
-// tCBNZ, tCBZ: tRd imm6*2
-// tBKPT: imm8
-// tNOP, tSEV, tYIELD, tWFE, tWFI:
-// no operand (except predicate pair)
-// tSETEND: i1
-// Others: tRd tRn
-static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- if (NumOps == 0)
- return true;
-
- if (Opcode == ARM::tPUSH || Opcode == ARM::tPOP)
- return DisassembleThumb1PushPop(MI, Opcode, insn, NumOps, NumOpsAdded, B);
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
-
- // Predicate operands are handled elsewhere.
- if (NumOps == 2 &&
- OpInfo[0].isPredicate() && OpInfo[1].isPredicate() &&
- OpInfo[0].RegClass < 0 && OpInfo[1].RegClass == ARM::CCRRegClassID) {
- return true;
- }
-
- if (Opcode == ARM::tADDspi || Opcode == ARM::tSUBspi) {
- // Special case handling for tADDspi and tSUBspi.
- // A8.6.8 ADD (SP plus immediate) & A8.6.215 SUB (SP minus immediate)
- MI.addOperand(MCOperand::CreateReg(ARM::SP));
- MI.addOperand(MCOperand::CreateReg(ARM::SP));
- MI.addOperand(MCOperand::CreateImm(getT1Imm7(insn)));
- NumOpsAdded = 3;
- return true;
- }
-
- if (Opcode == ARM::t2IT) {
- // Special case handling for If-Then.
- // A8.6.50 IT
- // Tag the (firstcond[0] bit << 4) along with mask.
-
- // firstcond
- MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 4)));
-
- // firstcond[0] and mask
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));
- NumOpsAdded = 2;
- return true;
- }
-
- if (Opcode == ARM::tBKPT) {
- MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); // breakpoint value
- NumOpsAdded = 1;
- return true;
- }
-
- // CPS has a singleton $opt operand that contains the following information:
- // The first op would be 0b10 as enable and 0b11 as disable in regular ARM,
- // but in Thumb it's is 0 as enable and 1 as disable. So map it to ARM's
- // default one. The second get the AIF flags from Inst{2-0}.
- if (Opcode == ARM::tCPS) {
- MI.addOperand(MCOperand::CreateImm(2 + slice(insn, 4, 4)));
- MI.addOperand(MCOperand::CreateImm(slice(insn, 2, 0)));
- NumOpsAdded = 2;
- return true;
- }
-
- if (Opcode == ARM::tSETEND) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 1)));
- NumOpsAdded = 1;
- return true;
- }
-
- assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
- (OpInfo[1].RegClass < 0 || OpInfo[1].RegClass==ARM::tGPRRegClassID)
- && "Expect >=2 operands");
-
- // Add the destination operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRd(insn))));
-
- if (OpInfo[1].RegClass == ARM::tGPRRegClassID) {
- // Two register instructions.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- getT1tRn(insn))));
- } else {
- // CBNZ, CBZ
- assert((Opcode == ARM::tCBNZ || Opcode == ARM::tCBZ) &&"Unexpected opcode");
- MI.addOperand(MCOperand::CreateImm(getT1Imm6(insn) * 2));
- }
-
- NumOpsAdded = 2;
-
- return true;
-}
-
-// A8.6.53 LDM / LDMIA
-// A8.6.189 STM / STMIA
-//
-// tLDMIA_UPD/tSTMIA_UPD: tRt tRt AM4ModeImm Pred-Imm Pred-CCR register_list
-// tLDMIA: tRt AM4ModeImm Pred-Imm Pred-CCR register_list
-static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps,
- unsigned &NumOpsAdded, BO B) {
- assert((Opcode == ARM::tLDMIA || Opcode == ARM::tSTMIA) &&
- "Unexpected opcode");
-
- unsigned tRt = getT1tRt(insn);
- NumOpsAdded = 0;
-
- // WB register, if necessary.
- if (Opcode == ARM::tLDMIA_UPD || Opcode == ARM::tSTMIA_UPD) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- tRt)));
- ++NumOpsAdded;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- tRt)));
- ++NumOpsAdded;
-
- // Handling the two predicate operands before the reglist.
- if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) {
- NumOpsAdded += 2;
- } else {
- DEBUG(errs() << "Expected predicate operands not found.\n");
- return false;
- }
-
- unsigned RegListBits = slice(insn, 7, 0);
- if (BitCount(RegListBits) < 1) {
- DEBUG(errs() << "if BitCount(registers) < 1 then UNPREDICTABLE\n");
- return false;
- }
-
- // Fill the variadic part of reglist.
- for (unsigned i = 0; i < 8; ++i)
- if ((RegListBits >> i) & 1) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID,
- i)));
- ++NumOpsAdded;
- }
-
- return true;
-}
-
-static bool DisassembleThumb1LdMul(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleThumb1LdStMul(true, MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
-}
-
-static bool DisassembleThumb1StMul(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- return DisassembleThumb1LdStMul(false, MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
-}
-
-// A8.6.16 B Encoding T1
-// cond = Inst{11-8} & imm8 = Inst{7-0}
-// imm32 = SignExtend(imm8:'0', 32)
-//
-// tBcc: offset Pred-Imm Pred-CCR
-// tSVC: imm8 Pred-Imm Pred-CCR
-// tTRAP: 0 operand (early return)
-static bool DisassembleThumb1CondBr(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO) {
-
- if (Opcode == ARM::tTRAP)
- return true;
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps == 3 && OpInfo[0].RegClass < 0 &&
- OpInfo[1].isPredicate() && OpInfo[2].RegClass == ARM::CCRRegClassID
- && "Exactly 3 operands expected");
-
- unsigned Imm8 = getT1Imm8(insn);
- MI.addOperand(MCOperand::CreateImm(
- Opcode == ARM::tBcc ? SignExtend32<9>(Imm8 << 1)
- : (int)Imm8));
-
- // Predicate operands by ARMBasicMCBuilder::TryPredicateAndSBitModifier().
- // But note that for tBcc, if cond = '1110' then UNDEFINED.
- if (Opcode == ARM::tBcc && slice(insn, 11, 8) == 14) {
- DEBUG(errs() << "if cond = '1110' then UNDEFINED\n");
- return false;
- }
- NumOpsAdded = 1;
-
- return true;
-}
-
-// A8.6.16 B Encoding T2
-// imm11 = Inst{10-0}
-// imm32 = SignExtend(imm11:'0', 32)
-//
-// tB: offset
-static bool DisassembleThumb1Br(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- assert(NumOps == 1 && OpInfo[0].RegClass < 0 && "1 imm operand expected");
-
- unsigned Imm11 = getT1Imm11(insn);
-
- MI.addOperand(MCOperand::CreateImm(SignExtend32<12>(Imm11 << 1)));
-
- NumOpsAdded = 1;
-
- return true;
-
-}
-
-// See A6.2 16-bit Thumb instruction encoding for instruction classes
-// corresponding to op.
-//
-// Table A6-1 16-bit Thumb instruction encoding (abridged)
-// op Instruction or instruction class
-// ------ --------------------------------------------------------------------
-// 00xxxx Shift (immediate), add, subtract, move, and compare on page A6-7
-// 010000 Data-processing on page A6-8
-// 010001 Special data instructions and branch and exchange on page A6-9
-// 01001x Load from Literal Pool, see LDR (literal) on page A8-122
-// 0101xx Load/store single data item on page A6-10
-// 011xxx
-// 100xxx
-// 10100x Generate PC-relative address, see ADR on page A8-32
-// 10101x Generate SP-relative address, see ADD (SP plus immediate) on
-// page A8-28
-// 1011xx Miscellaneous 16-bit instructions on page A6-11
-// 11000x Store multiple registers, see STM / STMIA / STMEA on page A8-374
-// 11001x Load multiple registers, see LDM / LDMIA / LDMFD on page A8-110 a
-// 1101xx Conditional branch, and Supervisor Call on page A6-13
-// 11100x Unconditional Branch, see B on page A8-44
-//
-static bool DisassembleThumb1(uint16_t op, MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- unsigned op1 = slice(op, 5, 4);
- unsigned op2 = slice(op, 3, 2);
- unsigned op3 = slice(op, 1, 0);
- unsigned opA = slice(op, 5, 2);
- switch (op1) {
- case 0:
- // A6.2.1 Shift (immediate), add, subtract, move, and compare
- return DisassembleThumb1General(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- case 1:
- switch (op2) {
- case 0:
- switch (op3) {
- case 0:
- // A6.2.2 Data-processing
- return DisassembleThumb1DP(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- case 1:
- // A6.2.3 Special data instructions and branch and exchange
- return DisassembleThumb1Special(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- default:
- // A8.6.59 LDR (literal)
- return DisassembleThumb1LdPC(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- }
- break;
- default:
- // A6.2.4 Load/store single data item
- return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- break;
- }
- break;
- case 2:
- switch (op2) {
- case 0:
- // A6.2.4 Load/store single data item
- return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- case 1:
- // A6.2.4 Load/store single data item
- return DisassembleThumb1LdStSP(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- case 2:
- if (op3 <= 1) {
- // A8.6.10 ADR
- return DisassembleThumb1AddPCi(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- } else {
- // A8.6.8 ADD (SP plus immediate)
- return DisassembleThumb1AddSPi(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
- default:
- // A6.2.5 Miscellaneous 16-bit instructions
- return DisassembleThumb1Misc(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- }
- break;
- case 3:
- switch (op2) {
- case 0:
- if (op3 <= 1) {
- // A8.6.189 STM / STMIA / STMEA
- return DisassembleThumb1StMul(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- } else {
- // A8.6.53 LDM / LDMIA / LDMFD
- return DisassembleThumb1LdMul(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- }
- case 1:
- // A6.2.6 Conditional branch, and Supervisor Call
- return DisassembleThumb1CondBr(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- case 2:
- // Unconditional Branch, see B on page A8-44
- return DisassembleThumb1Br(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- default:
- assert(0 && "Unreachable code");
- break;
- }
- break;
- default:
- assert(0 && "Unreachable code");
- break;
- }
-
- return false;
-}
-
-///////////////////////////////////////////////
-// //
-// Thumb2 instruction disassembly functions. //
-// //
-///////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////
-// //
-// Note: the register naming follows the ARM convention! //
-// //
-///////////////////////////////////////////////////////////
-
-static inline bool Thumb2SRSOpcode(unsigned Opcode) {
- switch (Opcode) {
- default:
- return false;
- case ARM::t2SRSDBW: case ARM::t2SRSDB:
- case ARM::t2SRSIAW: case ARM::t2SRSIA:
- return true;
- }
-}
-
-static inline bool Thumb2RFEOpcode(unsigned Opcode) {
- switch (Opcode) {
- default:
- return false;
- case ARM::t2RFEDBW: case ARM::t2RFEDB:
- case ARM::t2RFEIAW: case ARM::t2RFEIA:
- return true;
- }
-}
-
-// t2SRS[IA|DB]W/t2SRS[IA|DB]: mode_imm = Inst{4-0}
-static bool DisassembleThumb2SRS(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));
- NumOpsAdded = 1;
- return true;
-}
-
-// t2RFE[IA|DB]W/t2RFE[IA|DB]: Rn
-static bool DisassembleThumb2RFE(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
- unsigned Rn = decodeRn(insn);
- if (Rn == 15) {
- DEBUG(errs() << "if n == 15 then UNPREDICTABLE\n");
- return false;
- }
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B,ARM::GPRRegClassID,Rn)));
- NumOpsAdded = 1;
- return true;
-}
-
-static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- if (Thumb2SRSOpcode(Opcode))
- return DisassembleThumb2SRS(MI, Opcode, insn, NumOps, NumOpsAdded);
-
- if (Thumb2RFEOpcode(Opcode))
- return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded, B);
-
- assert((Opcode == ARM::t2LDMIA || Opcode == ARM::t2LDMIA_UPD ||
- Opcode == ARM::t2LDMDB || Opcode == ARM::t2LDMDB_UPD ||
- Opcode == ARM::t2STMIA || Opcode == ARM::t2STMIA_UPD ||
- Opcode == ARM::t2STMDB || Opcode == ARM::t2STMDB_UPD)
- && "Unexpected opcode");
- assert(NumOps >= 4 && "Thumb2 LdStMul expects NumOps >= 4");
-
- NumOpsAdded = 0;
-
- unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn));
-
- // Writeback to base.
- if (Opcode == ARM::t2LDMIA_UPD || Opcode == ARM::t2LDMDB_UPD ||
- Opcode == ARM::t2STMIA_UPD || Opcode == ARM::t2STMDB_UPD) {
- MI.addOperand(MCOperand::CreateReg(Base));
- ++NumOpsAdded;
- }
-
- MI.addOperand(MCOperand::CreateReg(Base));
- ++NumOpsAdded;
-
- // Handling the two predicate operands before the reglist.
- if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) {
- NumOpsAdded += 2;
- } else {
- DEBUG(errs() << "Expected predicate operands not found.\n");
- return false;
- }
-
- unsigned RegListBits = insn & ((1 << 16) - 1);
-
- // Fill the variadic part of reglist.
- for (unsigned i = 0; i < 16; ++i)
- if ((RegListBits >> i) & 1) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- i)));
- ++NumOpsAdded;
- }
-
- return true;
-}
-
-// t2LDREX: Rd Rn
-// t2LDREXD: Rd Rs Rn
-// t2LDREXB, t2LDREXH: Rd Rn
-// t2STREX: Rs Rd Rn
-// t2STREXD: Rm Rd Rs Rn
-// t2STREXB, t2STREXH: Rm Rd Rn
-static bool DisassembleThumb2LdStEx(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2
- && OpInfo[0].RegClass > 0
- && OpInfo[1].RegClass > 0
- && "Expect >=2 operands and first two as reg operands");
-
- bool isStore = (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH);
- bool isSW = (Opcode == ARM::t2LDREX || Opcode == ARM::t2STREX);
- bool isDW = (Opcode == ARM::t2LDREXD || Opcode == ARM::t2STREXD);
-
- unsigned Rt = decodeRd(insn);
- unsigned Rt2 = decodeRs(insn); // But note that this is Rd for t2STREX.
- unsigned Rd = decodeRm(insn);
- unsigned Rn = decodeRn(insn);
-
- // Some sanity checking first.
- if (isStore) {
- // if d == n || d == t then UNPREDICTABLE
- // if d == n || d == t || d == t2 then UNPREDICTABLE
- if (isDW) {
- if (Rd == Rn || Rd == Rt || Rd == Rt2) {
- DEBUG(errs() << "if d == n || d == t || d == t2 then UNPREDICTABLE\n");
- return false;
- }
- } else {
- if (isSW) {
- if (Rt2 == Rn || Rt2 == Rt) {
- DEBUG(errs() << "if d == n || d == t then UNPREDICTABLE\n");
- return false;
- }
- } else {
- if (Rd == Rn || Rd == Rt) {
- DEBUG(errs() << "if d == n || d == t then UNPREDICTABLE\n");
- return false;
- }
- }
- }
- } else {
- // Load
- // A8.6.71 LDREXD
- // if t == t2 then UNPREDICTABLE
- if (isDW && Rt == Rt2) {
- DEBUG(errs() << "if t == t2 then UNPREDICTABLE\n");
- return false;
- }
- }
-
- // Add the destination operand for store.
- if (isStore) {
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- isSW ? Rt2 : Rd)));
- ++OpIdx;
- }
-
- // Source operand for store and destination operand for load.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- Rt)));
- ++OpIdx;
-
- // Thumb2 doubleword complication: with an extra source/destination operand.
- if (isDW) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B,OpInfo[OpIdx].RegClass,
- Rt2)));
- ++OpIdx;
- }
-
- // Finally add the pointer operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- Rn)));
- ++OpIdx;
-
- return true;
-}
-
-// t2LDRDi8: Rd Rs Rn imm8s4 (offset mode)
-// t2LDRDpci: Rd Rs imm8s4 (Not decoded, prefer the generic t2LDRDi8 version)
-// t2STRDi8: Rd Rs Rn imm8s4 (offset mode)
-//
-// Ditto for t2LDRD_PRE, t2LDRD_POST, t2STRD_PRE, t2STRD_POST, which are for
-// disassembly only and do not have a tied_to writeback base register operand.
-static bool DisassembleThumb2LdStDual(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
- if (!OpInfo) return false;
-
- // Thumnb allows for specifying Rt and Rt2, unlike ARM (which has Rt2==Rt+1).
- unsigned Rt = decodeRd(insn);
- unsigned Rt2 = decodeRs(insn);
- unsigned Rn = decodeRn(insn);
-
- // Some sanity checking first.
-
- // A8.6.67 LDRD (literal) has its W bit as (0).
- if (Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2LDRD_PRE || Opcode == ARM::t2LDRD_POST) {
- if (Rn == 15 && slice(insn, 21, 21) != 0)
- return false;
- } else {
- // For Dual Store, PC cannot be used as the base register.
- if (Rn == 15) {
- DEBUG(errs() << "if n == 15 then UNPREDICTABLE\n");
- return false;
- }
- }
- if (Rt == Rt2) {
- DEBUG(errs() << "if t == t2 then UNPREDICTABLE\n");
- return false;
- }
- if (Opcode != ARM::t2LDRDi8 && Opcode != ARM::t2STRDi8) {
- if (Rn == Rt || Rn == Rt2) {
- DEBUG(errs() << "if wback && (n == t || n == t2) then UNPREDICTABLE\n");
- return false;
- }
- }
-
- // Add the <Rt> <Rt2> operands.
- unsigned RegClassPair = OpInfo[0].RegClass;
- unsigned RegClassBase = OpInfo[2].RegClass;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassPair,
- decodeRd(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassPair,
- decodeRs(insn))));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassBase,
- decodeRn(insn))));
- unsigned Added = 4;
- switch (MI.getOpcode()) {
- case ARM::t2LDRD_PRE:
- case ARM::t2LDRD_POST:
- case ARM::t2STRD_PRE:
- case ARM::t2STRD_POST:
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassBase,
- decodeRn(insn))));
- Added = 5;
- default:
- break;
- }
-
- // Finally add (+/-)imm8*4, depending on the U bit.
- int Offset = getImm8(insn) * 4;
- if (getUBit(insn) == 0)
- Offset = -Offset;
- MI.addOperand(MCOperand::CreateImm(Offset));
- NumOpsAdded = Added;
-
- return true;
-}
-
-// t2TBB, t2TBH: Rn Rm Pred-Imm Pred-CCR
-static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- assert(NumOps >= 2 && "Expect >= 2 operands");
-
- // The generic version of TBB/TBH needs a base register.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- // Add the index register.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- NumOpsAdded = 2;
-
- return true;
-}
-
-static inline bool Thumb2ShiftOpcode(unsigned Opcode) {
- switch (Opcode) {
- default:
- return false;
- case ARM::t2MOVCClsl: case ARM::t2MOVCClsr:
- case ARM::t2MOVCCasr: case ARM::t2MOVCCror:
- case ARM::t2LSLri: case ARM::t2LSRri:
- case ARM::t2ASRri: case ARM::t2RORri:
- return true;
- }
-}
-
-// A6.3.11 Data-processing (shifted register)
-//
-// Two register operands (Rn=0b1111 no 1st operand reg): Rs Rm
-// Two register operands (Rs=0b1111 no dst operand reg): Rn Rm
-// Three register operands: Rs Rn Rm
-// Three register operands: (Rn=0b1111 Conditional Move) Rs Ro(TIED_TO) Rm
-//
-// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2
-// register with shift forms: (Rm, ConstantShiftSpecifier).
-// Constant shift specifier: Imm = (ShOp | ShAmt<<3).
-//
-// There are special instructions, like t2MOVsra_flag and t2MOVsrl_flag, which
-// only require two register operands: Rd, Rm in ARM Reference Manual terms, and
-// nothing else, because the shift amount is already specified.
-// Similar case holds for t2MOVrx, t2ADDrr, ..., etc.
-static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- // Special case handling.
- if (Opcode == ARM::t2BR_JT) {
- assert(NumOps == 4
- && OpInfo[0].RegClass == ARM::GPRRegClassID
- && OpInfo[1].RegClass == ARM::GPRRegClassID
- && OpInfo[2].RegClass < 0
- && OpInfo[3].RegClass < 0
- && "Exactly 4 operands expect and first two as reg operands");
- // Only need to populate the src reg operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- MI.addOperand(MCOperand::CreateReg(0));
- MI.addOperand(MCOperand::CreateImm(0));
- MI.addOperand(MCOperand::CreateImm(0));
- NumOpsAdded = 4;
- return true;
- }
-
- OpIdx = 0;
-
- assert(NumOps >= 2
- && (OpInfo[0].RegClass == ARM::GPRRegClassID ||
- OpInfo[0].RegClass == ARM::rGPRRegClassID)
- && (OpInfo[1].RegClass == ARM::GPRRegClassID ||
- OpInfo[1].RegClass == ARM::rGPRRegClassID)
- && "Expect >= 2 operands and first two as reg operands");
-
- bool ThreeReg = (NumOps > 2 && (OpInfo[2].RegClass == ARM::GPRRegClassID ||
- OpInfo[2].RegClass == ARM::rGPRRegClassID));
- bool NoDstReg = (decodeRs(insn) == 0xF);
-
- // Build the register operands, followed by the constant shift specifier.
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, OpInfo[0].RegClass,
- NoDstReg ? decodeRn(insn) : decodeRs(insn))));
- ++OpIdx;
-
- if (ThreeReg) {
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // Process tied_to operand constraint.
- MI.addOperand(MI.getOperand(Idx));
- ++OpIdx;
- } else if (!NoDstReg) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[1].RegClass,
- decodeRn(insn))));
- ++OpIdx;
- } else {
- DEBUG(errs() << "Thumb2 encoding error: d==15 for three-reg operands.\n");
- return false;
- }
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeRm(insn))));
- ++OpIdx;
-
- if (NumOps == OpIdx)
- return true;
-
- if (OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate()
- && !OpInfo[OpIdx].isOptionalDef()) {
-
- if (Thumb2ShiftOpcode(Opcode)) {
- unsigned Imm = getShiftAmtBits(insn);
- ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 5, 4));
- getImmShiftSE(ShOp, Imm);
- MI.addOperand(MCOperand::CreateImm(Imm));
- } else {
- // Build the constant shift specifier operand.
- unsigned imm5 = getShiftAmtBits(insn);
- // The PKHBT/PKHTB instructions have an implied shift type and so just
- // use a plain immediate for the amount.
- if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB)
- MI.addOperand(MCOperand::CreateImm(imm5));
- else {
- ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift;
- unsigned bits2 = getShiftTypeBits(insn);
- unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp);
- MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt)));
- }
- }
- ++OpIdx;
- }
-
- return true;
-}
-
-// A6.3.1 Data-processing (modified immediate)
-//
-// Two register operands: Rs Rn ModImm
-// One register operands (Rs=0b1111 no explicit dest reg): Rn ModImm
-// One register operands (Rn=0b1111 no explicit src reg): Rs ModImm -
-// {t2MOVi, t2MVNi}
-//
-// ModImm = ThumbExpandImm(i:imm3:imm8)
-static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned RdRegClassID = OpInfo[0].RegClass;
- assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID ||
- RdRegClassID == ARM::rGPRRegClassID)
- && "Expect >= 2 operands and first one as reg operand");
-
- unsigned RnRegClassID = OpInfo[1].RegClass;
- bool TwoReg = (RnRegClassID == ARM::GPRRegClassID
- || RnRegClassID == ARM::rGPRRegClassID);
- bool NoDstReg = (decodeRs(insn) == 0xF);
-
- // Build the register operands, followed by the modified immediate.
-
- MI.addOperand(MCOperand::CreateReg(
- getRegisterEnum(B, RdRegClassID,
- NoDstReg ? decodeRn(insn) : decodeRs(insn))));
- ++OpIdx;
-
- if (TwoReg) {
- if (NoDstReg) {
- DEBUG(errs()<<"Thumb2 encoding error: d==15 for DPModImm 2-reg instr.\n");
- return false;
- }
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // The reg operand is tied to the first reg operand.
- MI.addOperand(MI.getOperand(Idx));
- } else {
- // Add second reg operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
- decodeRn(insn))));
- }
- ++OpIdx;
- }
-
- // The modified immediate operand should come next.
- assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0 &&
- !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()
- && "Pure imm operand expected");
-
- // i:imm3:imm8
- // A6.3.2 Modified immediate constants in Thumb instructions
- unsigned imm12 = getIImm3Imm8(insn);
- MI.addOperand(MCOperand::CreateImm(ThumbExpandImm(imm12)));
- ++OpIdx;
-
- return true;
-}
-
-static inline bool Thumb2SaturateOpcode(unsigned Opcode) {
- switch (Opcode) {
- case ARM::t2SSAT: case ARM::t2SSAT16:
- case ARM::t2USAT: case ARM::t2USAT16:
- return true;
- default:
- return false;
- }
-}
-
-/// DisassembleThumb2Sat - Disassemble Thumb2 saturate instructions:
-/// o t2SSAT, t2USAT: Rs sat_pos Rn shamt
-/// o t2SSAT16, t2USAT16: Rs sat_pos Rn
-static bool DisassembleThumb2Sat(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned &NumOpsAdded, BO B) {
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- NumOpsAdded = MCID.getNumOperands() - 2; // ignore predicate operands
-
- // Disassemble the register def.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRs(insn))));
-
- unsigned Pos = slice(insn, 4, 0);
- MI.addOperand(MCOperand::CreateImm(Pos));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRn(insn))));
-
- if (NumOpsAdded == 4) {
- // Inst{6} encodes the shift type.
- bool isASR = slice(insn, 6, 6);
- // Inst{11-7} encodes the imm5 shift amount.
- unsigned ShAmt = slice(insn, 11, 7);
- MI.addOperand(MCOperand::CreateImm(isASR << 5 | ShAmt));
- }
- return true;
-}
-
-// A6.3.3 Data-processing (plain binary immediate)
-//
-// o t2ADDri12, t2SUBri12: Rs Rn imm12
-// o t2LEApcrel (ADR): Rs imm12
-// o t2BFC (BFC): Rs Ro(TIED_TO) bf_inv_mask_imm
-// o t2BFI (BFI): Rs Ro(TIED_TO) Rn bf_inv_mask_imm
-// o t2MOVi16: Rs imm16
-// o t2MOVTi16: Rs imm16
-// o t2SBFX (SBFX): Rs Rn lsb width
-// o t2UBFX (UBFX): Rs Rn lsb width
-// o t2BFI (BFI): Rs Rn lsb width
-static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- unsigned RdRegClassID = OpInfo[0].RegClass;
- assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID ||
- RdRegClassID == ARM::rGPRRegClassID)
- && "Expect >= 2 operands and first one as reg operand");
-
- unsigned RnRegClassID = OpInfo[1].RegClass;
- bool TwoReg = (RnRegClassID == ARM::GPRRegClassID
- || RnRegClassID == ARM::rGPRRegClassID);
-
- // Build the register operand(s), followed by the immediate(s).
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RdRegClassID,
- decodeRs(insn))));
- ++OpIdx;
-
- if (TwoReg) {
- assert(NumOps >= 3 && "Expect >= 3 operands");
- int Idx;
- if ((Idx = MCID.getOperandConstraint(OpIdx, MCOI::TIED_TO)) != -1) {
- // Process tied_to operand constraint.
- MI.addOperand(MI.getOperand(Idx));
- } else {
- // Add src reg operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
- decodeRn(insn))));
- }
- ++OpIdx;
- }
-
- if (Opcode == ARM::t2BFI) {
- // Add val reg operand.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- assert(OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate()
- && !OpInfo[OpIdx].isOptionalDef()
- && "Pure imm operand expected");
-
- // Pre-increment OpIdx.
- ++OpIdx;
-
- if (Opcode == ARM::t2ADDri12 || Opcode == ARM::t2SUBri12
- || Opcode == ARM::t2LEApcrel)
- MI.addOperand(MCOperand::CreateImm(getIImm3Imm8(insn)));
- else if (Opcode == ARM::t2MOVi16 || Opcode == ARM::t2MOVTi16) {
- if (!B->tryAddingSymbolicOperand(getImm16(insn), 4, MI))
- MI.addOperand(MCOperand::CreateImm(getImm16(insn)));
- } else if (Opcode == ARM::t2BFC || Opcode == ARM::t2BFI) {
- uint32_t mask = 0;
- if (getBitfieldInvMask(insn, mask))
- MI.addOperand(MCOperand::CreateImm(mask));
- else
- return false;
- } else {
- // Handle the case of: lsb width
- assert((Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX)
- && "Unexpected opcode");
- MI.addOperand(MCOperand::CreateImm(getLsb(insn)));
- MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn)));
-
- ++OpIdx;
- }
-
- return true;
-}
-
-// A6.3.4 Table A6-15 Miscellaneous control instructions
-// A8.6.41 DMB
-// A8.6.42 DSB
-// A8.6.49 ISB
-static inline bool t2MiscCtrlInstr(uint32_t insn) {
- if (slice(insn, 31, 20) == 0xf3b && slice(insn, 15, 14) == 2 &&
- slice(insn, 12, 12) == 0)
- return true;
-
- return false;
-}
-
-// A6.3.4 Branches and miscellaneous control
-//
-// A8.6.16 B
-// Branches: t2B, t2Bcc -> imm operand
-//
-// Branches: t2TPsoft -> no operand
-//
-// A8.6.23 BL, BLX (immediate)
-// Branches (defined in ARMInstrThumb.td): tBL, tBLXi -> imm operand
-//
-// A8.6.26
-// t2BXJ -> Rn
-//
-// Miscellaneous control:
-// -> no operand (except pred-imm pred-ccr for CLREX, memory barrier variants)
-//
-// Hint: t2NOP, t2YIELD, t2WFE, t2WFI, t2SEV
-// -> no operand (except pred-imm pred-ccr)
-//
-// t2DBG -> imm4 = Inst{3-0}
-//
-// t2MRS/t2MRSsys -> Rs
-// t2MSR/t2MSRsys -> Rn mask=Inst{11-8}
-// t2SMC -> imm4 = Inst{19-16}
-static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- if (NumOps == 0)
- return true;
-
- if (Opcode == ARM::t2DMB || Opcode == ARM::t2DSB) {
- // Inst{3-0} encodes the memory barrier option for the variants.
- unsigned opt = slice(insn, 3, 0);
- switch (opt) {
- case ARM_MB::SY: case ARM_MB::ST:
- case ARM_MB::ISH: case ARM_MB::ISHST:
- case ARM_MB::NSH: case ARM_MB::NSHST:
- case ARM_MB::OSH: case ARM_MB::OSHST:
- MI.addOperand(MCOperand::CreateImm(opt));
- NumOpsAdded = 1;
- return true;
- default:
- return false;
- }
- }
-
- if (t2MiscCtrlInstr(insn))
- return true;
-
- switch (Opcode) {
- case ARM::t2CLREX:
- case ARM::t2NOP:
- case ARM::t2YIELD:
- case ARM::t2WFE:
- case ARM::t2WFI:
- case ARM::t2SEV:
- return true;
- default:
- break;
- }
-
- // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
- // opcodes which match the same real instruction. This is needed since there's
- // no current handling of optional arguments. Fix here when a better handling
- // of optional arguments is implemented.
- if (Opcode == ARM::t2CPS3p) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
- MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
- NumOpsAdded = 3;
- return true;
- }
- if (Opcode == ARM::t2CPS2p) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
- MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags
- NumOpsAdded = 2;
- return true;
- }
- if (Opcode == ARM::t2CPS1p) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
- NumOpsAdded = 1;
- return true;
- }
-
- // DBG has its option specified in Inst{3-0}.
- if (Opcode == ARM::t2DBG) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0)));
- NumOpsAdded = 1;
- return true;
- }
-
- // MRS and MRSsys take one GPR reg Rs.
- if (Opcode == ARM::t2MRS || Opcode == ARM::t2MRSsys) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRs(insn))));
- NumOpsAdded = 1;
- return true;
- }
- // BXJ takes one GPR reg Rn.
- if (Opcode == ARM::t2BXJ) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- NumOpsAdded = 1;
- return true;
- }
- // MSR take a mask, followed by one GPR reg Rn. The mask contains the R Bit in
- // bit 4, and the special register fields in bits 3-0.
- if (Opcode == ARM::t2MSR) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 20) << 4 /* R Bit */ |
- slice(insn, 11, 8) /* Special Reg */));
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- NumOpsAdded = 2;
- return true;
- }
- // SMC take imm4.
- if (Opcode == ARM::t2SMC) {
- MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16)));
- NumOpsAdded = 1;
- return true;
- }
-
- // Some instructions have predicate operands first before the immediate.
- if (Opcode == ARM::tBLXi || Opcode == ARM::tBL) {
- // Handling the two predicate operands before the imm operand.
- if (B->DoPredicateOperands(MI, Opcode, insn, NumOps))
- NumOpsAdded += 2;
- else {
- DEBUG(errs() << "Expected predicate operands not found.\n");
- return false;
- }
- }
-
- // Add the imm operand.
- int Offset = 0;
-
- switch (Opcode) {
- default:
- assert(0 && "Unexpected opcode");
- return false;
- case ARM::t2B:
- Offset = decodeImm32_B_EncodingT4(insn);
- break;
- case ARM::t2Bcc:
- Offset = decodeImm32_B_EncodingT3(insn);
- break;
- case ARM::tBL:
- Offset = decodeImm32_BL(insn);
- break;
- case ARM::tBLXi:
- Offset = decodeImm32_BLX(insn);
- break;
- }
-
- if (!B->tryAddingSymbolicOperand(Offset + B->getBuilderAddress() + 4, 4, MI))
- MI.addOperand(MCOperand::CreateImm(Offset));
-
- // This is an increment as some predicate operands may have been added first.
- NumOpsAdded += 1;
-
- return true;
-}
-
-static inline bool Thumb2PreloadOpcode(unsigned Opcode) {
- switch (Opcode) {
- default:
- return false;
- case ARM::t2PLDi12: case ARM::t2PLDi8:
- case ARM::t2PLDs:
- case ARM::t2PLDWi12: case ARM::t2PLDWi8:
- case ARM::t2PLDWs:
- case ARM::t2PLIi12: case ARM::t2PLIi8:
- case ARM::t2PLIs:
- return true;
- }
-}
-
-static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- // Preload Data/Instruction requires either 2 or 3 operands.
- // t2PLDi12, t2PLDi8, t2PLDpci: Rn [+/-]imm12/imm8
- // t2PLDr: Rn Rm
- // t2PLDs: Rn Rm imm2=Inst{5-4}
- // Same pattern applies for t2PLDW* and t2PLI*.
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2 &&
- OpInfo[0].RegClass == ARM::GPRRegClassID &&
- "Expect >= 2 operands and first one as reg operand");
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRn(insn))));
- ++OpIdx;
-
- if (OpInfo[OpIdx].RegClass == ARM::rGPRRegClassID) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
- decodeRm(insn))));
- } else {
- assert(OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate()
- && !OpInfo[OpIdx].isOptionalDef()
- && "Pure imm operand expected");
- int Offset = 0;
- if (Opcode == ARM::t2PLDi8 || Opcode == ARM::t2PLDWi8 ||
- Opcode == ARM::t2PLIi8) {
- // A8.6.117 Encoding T2: add = FALSE
- unsigned Imm8 = getImm8(insn);
- Offset = -1 * Imm8;
- } else {
- // The i12 forms. See, for example, A8.6.117 Encoding T1.
- // Note that currently t2PLDi12 also handles the previously named t2PLDpci
- // opcode, that's why we use decodeImm12(insn) which returns +/- imm12.
- Offset = decodeImm12(insn);
- }
- MI.addOperand(MCOperand::CreateImm(Offset));
- }
- ++OpIdx;
-
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0 &&
- !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // Fills in the shift amount for t2PLDs, t2PLDWs, t2PLIs.
- MI.addOperand(MCOperand::CreateImm(slice(insn, 5, 4)));
- ++OpIdx;
- }
-
- return true;
-}
-
-static bool BadRegsThumb2LdSt(unsigned Opcode, uint32_t insn, bool Load,
- unsigned R0, unsigned R1, unsigned R2, bool UseRm, bool WB) {
-
- // Inst{22-21} encodes the data item transferred for load/store.
- // For single word, it is encoded as ob10.
- bool Word = (slice(insn, 22, 21) == 2);
- bool Half = (slice(insn, 22, 21) == 1);
- bool Byte = (slice(insn, 22, 21) == 0);
-
- if (UseRm && BadReg(R2)) {
- DEBUG(errs() << "if BadReg(m) then UNPREDICTABLE\n");
- return true;
- }
-
- if (Load) {
- if (!Word && R0 == 13) {
- DEBUG(errs() << "if t == 13 then UNPREDICTABLE\n");
- return true;
- }
- if (Byte) {
- if (WB && R0 == 15 && slice(insn, 10, 8) == 3) {
- // A8.6.78 LDRSB (immediate) Encoding T2 (errata markup 8.0)
- DEBUG(errs() << "if t == 15 && PUW == '011' then UNPREDICTABLE\n");
- return true;
- }
- }
- // A6.3.8 Load halfword, memory hints
- if (Half) {
- if (WB) {
- if (R0 == R1) {
- // A8.6.82 LDRSH (immediate) Encoding T2
- DEBUG(errs() << "if WB && n == t then UNPREDICTABLE\n");
- return true;
- }
- if (R0 == 15 && slice(insn, 10, 8) == 3) {
- // A8.6.82 LDRSH (immediate) Encoding T2 (errata markup 8.0)
- DEBUG(errs() << "if t == 15 && PUW == '011' then UNPREDICTABLE\n");
- return true;
- }
- } else {
- if (Opcode == ARM::t2LDRHi8 || Opcode == ARM::t2LDRSHi8) {
- if (R0 == 15 && slice(insn, 10, 8) == 4) {
- // A8.6.82 LDRSH (immediate) Encoding T2
- DEBUG(errs() << "if Rt == '1111' and PUW == '100' then SEE"
- << " \"Unallocated memory hints\"\n");
- return true;
- }
- } else {
- if (R0 == 15) {
- // A8.6.82 LDRSH (immediate) Encoding T1
- DEBUG(errs() << "if Rt == '1111' then SEE"
- << " \"Unallocated memory hints\"\n");
- return true;
- }
- }
- }
- }
- } else {
- if (WB && R0 == R1) {
- DEBUG(errs() << "if wback && n == t then UNPREDICTABLE\n");
- return true;
- }
- if ((WB && R0 == 15) || (!WB && R1 == 15)) {
- DEBUG(errs() << "if Rn == '1111' then UNDEFINED\n");
- return true;
- }
- if (Word) {
- if ((WB && R1 == 15) || (!WB && R0 == 15)) {
- DEBUG(errs() << "if t == 15 then UNPREDICTABLE\n");
- return true;
- }
- } else {
- if ((WB && BadReg(R1)) || (!WB && BadReg(R0))) {
- DEBUG(errs() << "if BadReg(t) then UNPREDICTABLE\n");
- return true;
- }
- }
- }
- return false;
-}
-
-// A6.3.10 Store single data item
-// A6.3.9 Load byte, memory hints
-// A6.3.8 Load halfword, memory hints
-// A6.3.7 Load word
-//
-// For example,
-//
-// t2LDRi12: Rd Rn (+)imm12
-// t2LDRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1)
-// t2LDRs: Rd Rn Rm ConstantShiftSpecifier (see also
-// DisassembleThumb2DPSoReg)
-// t2LDR_POST: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1)
-// t2LDR_PRE: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1)
-//
-// t2STRi12: Rd Rn (+)imm12
-// t2STRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1)
-// t2STRs: Rd Rn Rm ConstantShiftSpecifier (see also
-// DisassembleThumb2DPSoReg)
-// t2STR_POST: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1)
-// t2STR_PRE: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1)
-//
-// Note that for indexed modes, the Rn(TIED_TO) operand needs to be populated
-// correctly, as LLVM AsmPrinter depends on it. For indexed stores, the first
-// operand is Rn; for all the other instructions, Rd is the first operand.
-//
-// Delegates to DisassembleThumb2PreLoad() for preload data/instruction.
-// Delegates to DisassembleThumb2Ldpci() for load * literal operations.
-static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode,
- uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- unsigned Rn = decodeRn(insn);
-
- if (Thumb2PreloadOpcode(Opcode))
- return DisassembleThumb2PreLoad(MI, Opcode, insn, NumOps, NumOpsAdded, B);
-
- // See, for example, A6.3.7 Load word: Table A6-18 Load word.
- if (Load && Rn == 15)
- return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass > 0 &&
- OpInfo[1].RegClass > 0 &&
- "Expect >= 3 operands and first two as reg operands");
-
- bool ThreeReg = (OpInfo[2].RegClass > 0);
- bool TIED_TO = ThreeReg && MCID.getOperandConstraint(2, MCOI::TIED_TO) != -1;
- bool Imm12 = !ThreeReg && slice(insn, 23, 23) == 1; // ARMInstrThumb2.td
-
- // Build the register operands, followed by the immediate.
- unsigned R0 = 0, R1 = 0, R2 = 0;
- unsigned Rd = decodeRd(insn);
- int Imm = 0;
-
- if (!Load && TIED_TO) {
- R0 = Rn;
- R1 = Rd;
- } else {
- R0 = Rd;
- R1 = Rn;
- }
- if (ThreeReg) {
- if (TIED_TO) {
- R2 = Rn;
- Imm = decodeImm8(insn);
- } else {
- R2 = decodeRm(insn);
- // See, for example, A8.6.64 LDRB (register).
- // And ARMAsmPrinter::printT2AddrModeSoRegOperand().
- // LSL is the default shift opc, and LLVM does not expect it to be encoded
- // as part of the immediate operand.
- // Imm = ARM_AM::getSORegOpc(ARM_AM::lsl, slice(insn, 5, 4));
- Imm = slice(insn, 5, 4);
- }
- } else {
- if (Imm12)
- Imm = getImm12(insn);
- else
- Imm = decodeImm8(insn);
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- R0)));
- ++OpIdx;
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- R1)));
- ++OpIdx;
-
- if (ThreeReg) {
- // This could be an offset register or a TIED_TO register.
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B,OpInfo[OpIdx].RegClass,
- R2)));
- ++OpIdx;
- }
-
- if (BadRegsThumb2LdSt(Opcode, insn, Load, R0, R1, R2, ThreeReg & !TIED_TO,
- TIED_TO))
- return false;
-
- assert(OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate()
- && !OpInfo[OpIdx].isOptionalDef()
- && "Pure imm operand expected");
-
- MI.addOperand(MCOperand::CreateImm(Imm));
- ++OpIdx;
-
- return true;
-}
-
-// A6.3.12 Data-processing (register)
-//
-// Two register operands [rotate]: Rs Rm [rotation(= (rotate:'000'))]
-// Three register operands only: Rs Rn Rm
-// Three register operands [rotate]: Rs Rn Rm [rotation(= (rotate:'000'))]
-//
-// Parallel addition and subtraction 32-bit Thumb instructions: Rs Rn Rm
-//
-// Miscellaneous operations: Rs [Rn] Rm
-static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCInstrDesc &MCID = ARMInsts[Opcode];
- const MCOperandInfo *OpInfo = MCID.OpInfo;
- unsigned &OpIdx = NumOpsAdded;
-
- OpIdx = 0;
-
- assert(NumOps >= 2 &&
- OpInfo[0].RegClass > 0 &&
- OpInfo[1].RegClass > 0 &&
- "Expect >= 2 operands and first two as reg operands");
-
- // Build the register operands, followed by the optional rotation amount.
-
- bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass > 0;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeRs(insn))));
- ++OpIdx;
-
- if (ThreeReg) {
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B,OpInfo[OpIdx].RegClass,
- decodeRn(insn))));
- ++OpIdx;
- }
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
- decodeRm(insn))));
- ++OpIdx;
-
- if (OpIdx < NumOps && OpInfo[OpIdx].RegClass < 0
- && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) {
- // Add the rotation amount immediate.
- MI.addOperand(MCOperand::CreateImm(slice(insn, 5, 4)));
- ++OpIdx;
- }
-
- return true;
-}
-
-// A6.3.16 Multiply, multiply accumulate, and absolute difference
-//
-// t2MLA, t2MLS, t2SMMLA, t2SMMLS: Rs Rn Rm Ra=Inst{15-12}
-// t2MUL, t2SMMUL: Rs Rn Rm
-// t2SMLA[BB|BT|TB|TT|WB|WT]: Rs Rn Rm Ra=Inst{15-12}
-// t2SMUL[BB|BT|TB|TT|WB|WT]: Rs Rn Rm
-//
-// Dual halfword multiply: t2SMUAD[X], t2SMUSD[X], t2SMLAD[X], t2SMLSD[X]:
-// Rs Rn Rm Ra=Inst{15-12}
-//
-// Unsigned Sum of Absolute Differences [and Accumulate]
-// Rs Rn Rm [Ra=Inst{15-12}]
-static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::rGPRRegClassID &&
- OpInfo[1].RegClass == ARM::rGPRRegClassID &&
- OpInfo[2].RegClass == ARM::rGPRRegClassID &&
- "Expect >= 3 operands and first three as reg operands");
-
- // Build the register operands.
-
- bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID;
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRs(insn))));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRn(insn))));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRm(insn))));
-
- if (FourReg)
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRd(insn))));
-
- NumOpsAdded = FourReg ? 4 : 3;
-
- return true;
-}
-
-// A6.3.17 Long multiply, long multiply accumulate, and divide
-//
-// t2SMULL, t2UMULL, t2SMLAL, t2UMLAL, t2UMAAL: RdLo RdHi Rn Rm
-// where RdLo = Inst{15-12} and RdHi = Inst{11-8}
-//
-// Halfword multiple accumulate long: t2SMLAL<x><y>: RdLo RdHi Rn Rm
-// where RdLo = Inst{15-12} and RdHi = Inst{11-8}
-//
-// Dual halfword multiple: t2SMLALD[X], t2SMLSLD[X]: RdLo RdHi Rn Rm
-// where RdLo = Inst{15-12} and RdHi = Inst{11-8}
-//
-// Signed/Unsigned divide: t2SDIV, t2UDIV: Rs Rn Rm
-static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO B) {
-
- const MCOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
-
- assert(NumOps >= 3 &&
- OpInfo[0].RegClass == ARM::rGPRRegClassID &&
- OpInfo[1].RegClass == ARM::rGPRRegClassID &&
- OpInfo[2].RegClass == ARM::rGPRRegClassID &&
- "Expect >= 3 operands and first three as reg operands");
-
- bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID;
-
- // Build the register operands.
-
- if (FourReg)
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRd(insn))));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRs(insn))));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRn(insn))));
-
- MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
- decodeRm(insn))));
-
- if (FourReg)
- NumOpsAdded = 4;
- else
- NumOpsAdded = 3;
-
- return true;
-}
-
-// See A6.3 32-bit Thumb instruction encoding for instruction classes
-// corresponding to (op1, op2, op).
-//
-// Table A6-9 32-bit Thumb instruction encoding
-// op1 op2 op Instruction class, see
-// --- ------- -- -----------------------------------------------------------
-// 01 00xx0xx - Load/store multiple on page A6-23
-// 00xx1xx - Load/store dual, load/store exclusive, table branch on
-// page A6-24
-// 01xxxxx - Data-processing (shifted register) on page A6-31
-// 1xxxxxx - Coprocessor instructions on page A6-40
-// 10 x0xxxxx 0 Data-processing (modified immediate) on page A6-15
-// x1xxxxx 0 Data-processing (plain binary immediate) on page A6-19
-// - 1 Branches and miscellaneous control on page A6-20
-// 11 000xxx0 - Store single data item on page A6-30
-// 001xxx0 - Advanced SIMD element or structure load/store instructions
-// on page A7-27
-// 00xx001 - Load byte, memory hints on page A6-28
-// 00xx011 - Load halfword, memory hints on page A6-26
-// 00xx101 - Load word on page A6-25
-// 00xx111 - UNDEFINED
-// 010xxxx - Data-processing (register) on page A6-33
-// 0110xxx - Multiply, multiply accumulate, and absolute difference on
-// page A6-38
-// 0111xxx - Long multiply, long multiply accumulate, and divide on
-// page A6-39
-// 1xxxxxx - Coprocessor instructions on page A6-40
-//
-static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op,
- MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps,
- unsigned &NumOpsAdded, BO B) {
-
- switch (op1) {
- case 1:
- if (slice(op2, 6, 5) == 0) {
- if (slice(op2, 2, 2) == 0) {
- // Load/store multiple.
- return DisassembleThumb2LdStMul(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
-
- // Load/store dual, load/store exclusive, table branch, otherwise.
- assert(slice(op2, 2, 2) == 1 && "Thumb2 encoding error!");
- if ((ARM::t2LDREX <= Opcode && Opcode <= ARM::t2LDREXH) ||
- (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH)) {
- // Load/store exclusive.
- return DisassembleThumb2LdStEx(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
- if (Opcode == ARM::t2LDRDi8 ||
- Opcode == ARM::t2LDRD_PRE || Opcode == ARM::t2LDRD_POST ||
- Opcode == ARM::t2STRDi8 ||
- Opcode == ARM::t2STRD_PRE || Opcode == ARM::t2STRD_POST) {
- // Load/store dual.
- return DisassembleThumb2LdStDual(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
- if (Opcode == ARM::t2TBB || Opcode == ARM::t2TBH) {
- // Table branch.
- return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- }
- } else if (slice(op2, 6, 5) == 1) {
- // Data-processing (shifted register).
- return DisassembleThumb2DPSoReg(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- }
-
- // FIXME: A6.3.18 Coprocessor instructions
- // But see ThumbDisassembler::getInstruction().
-
- break;
- case 2:
- if (op == 0) {
- if (slice(op2, 5, 5) == 0)
- // Data-processing (modified immediate)
- return DisassembleThumb2DPModImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- if (Thumb2SaturateOpcode(Opcode))
- return DisassembleThumb2Sat(MI, Opcode, insn, NumOpsAdded, B);
-
- // Data-processing (plain binary immediate)
- return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
- // Branches and miscellaneous control on page A6-20.
- return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- case 3:
- switch (slice(op2, 6, 5)) {
- case 0:
- // Load/store instructions...
- if (slice(op2, 0, 0) == 0) {
- if (slice(op2, 4, 4) == 0) {
- // Store single data item on page A6-30
- return DisassembleThumb2LdSt(false, MI,Opcode,insn,NumOps,NumOpsAdded,
- B);
- } else {
- // FIXME: Advanced SIMD element or structure load/store instructions.
- // But see ThumbDisassembler::getInstruction().
- ;
- }
- } else {
- // Table A6-9 32-bit Thumb instruction encoding: Load byte|halfword|word
- return DisassembleThumb2LdSt(true, MI, Opcode, insn, NumOps,
- NumOpsAdded, B);
- }
- break;
- case 1:
- if (slice(op2, 4, 4) == 0) {
- // A6.3.12 Data-processing (register)
- return DisassembleThumb2DPReg(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- } else if (slice(op2, 3, 3) == 0) {
- // A6.3.16 Multiply, multiply accumulate, and absolute difference
- return DisassembleThumb2Mul(MI, Opcode, insn, NumOps, NumOpsAdded, B);
- } else {
- // A6.3.17 Long multiply, long multiply accumulate, and divide
- return DisassembleThumb2LongMul(MI, Opcode, insn, NumOps, NumOpsAdded,
- B);
- }
- break;
- default:
- // FIXME: A6.3.18 Coprocessor instructions
- // But see ThumbDisassembler::getInstruction().
- ;
- break;
- }
-
- break;
- default:
- assert(0 && "Thumb2 encoding error!");
- break;
- }
-
- return false;
-}
-
-static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
- unsigned short NumOps, unsigned &NumOpsAdded, BO Builder) {
-
- uint16_t HalfWord = slice(insn, 31, 16);
-
- if (HalfWord == 0) {
- // A6.2 16-bit Thumb instruction encoding
- // op = bits[15:10]
- uint16_t op = slice(insn, 15, 10);
- return DisassembleThumb1(op, MI, Opcode, insn, NumOps, NumOpsAdded,
- Builder);
- }
-
- unsigned bits15_11 = slice(HalfWord, 15, 11);
-
- // A6.1 Thumb instruction set encoding
- if (!(bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F)) {
- assert("Bits[15:11] first halfword of Thumb2 instruction is out of range");
- return false;
- }
-
- // A6.3 32-bit Thumb instruction encoding
-
- uint16_t op1 = slice(HalfWord, 12, 11);
- uint16_t op2 = slice(HalfWord, 10, 4);
- uint16_t op = slice(insn, 15, 15);
-
- return DisassembleThumb2(op1, op2, op, MI, Opcode, insn, NumOps, NumOpsAdded,
- Builder);
-}
diff --git a/lib/Target/ARM/Makefile b/lib/Target/ARM/Makefile
index eb8c603544..6d17fdbb0f 100644
--- a/lib/Target/ARM/Makefile
+++ b/lib/Target/ARM/Makefile
@@ -18,7 +18,7 @@ BUILT_SOURCES = ARMGenRegisterInfo.inc ARMGenInstrInfo.inc \
ARMGenCodeEmitter.inc ARMGenCallingConv.inc \
ARMGenDecoderTables.inc ARMGenEDInfo.inc \
ARMGenFastISel.inc ARMGenMCCodeEmitter.inc \
- ARMGenMCPseudoLowering.inc
+ ARMGenMCPseudoLowering.inc ARMGenDisassemblerTables.inc
DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc
diff --git a/test/MC/Disassembler/ARM/arm-tests.txt b/test/MC/Disassembler/ARM/arm-tests.txt
index 24df6e1b12..43e6e07557 100644
--- a/test/MC/Disassembler/ARM/arm-tests.txt
+++ b/test/MC/Disassembler/ARM/arm-tests.txt
@@ -60,11 +60,14 @@
# CHECK: ldrh r0, [r2], #0
0xb0 0x00 0xd2 0xe0
+# CHECK: ldrh r0, [r2]
+0xb0 0x00 0xd2 0xe1
+
# CHECK: ldrht r0, [r2], #15
0xbf 0x00 0xf2 0xe0
# CHECK: ldrsbtvs lr, [r2], -r9
-0xd9 0xe9 0x32 0x60
+0xd9 0xe0 0x32 0x60
# CHECK: lsls r0, r2, #31
0x82 0x0f 0xb0 0xe1
@@ -177,7 +180,7 @@
0x15 0xff 0x2f 0x01
# CHECK: uqadd16mi r6, r11, r8
-0x18 0x60 0x6b 0x46
+0x18 0x6F 0x6b 0x46
# CHECK: str r0, [sp, #4]
0x04 0x00 0x8d 0xe5
@@ -230,7 +233,7 @@
# CHECK: umull r1, r2, r3, r4
0x93 0x14 0x82 0xe0
-# CHECK: pld [pc, #-0]
+# CHECK: pldw [pc, #-0]
0x00 0xf0 0x1f 0xf5
# CHECK: pli [pc, #-0]
diff --git a/test/MC/Disassembler/ARM/invalid-BFI-arm.txt b/test/MC/Disassembler/ARM/invalid-BFI-arm.txt
index ca0c1abb77..e108d3872f 100644
--- a/test/MC/Disassembler/ARM/invalid-BFI-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-BFI-arm.txt
@@ -1,7 +1,8 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=60 Name=BFI Format=ARM_FORMAT_DPFRM(4)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 0| 0: 1: 1: 1| 1: 1: 0: 0| 1: 1: 1: 1| 1: 1: 1: 1| 0: 0: 0: 0| 0: 0: 0: 1| 0: 1: 1: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-Bcc-thumb.txt b/test/MC/Disassembler/ARM/invalid-Bcc-thumb.txt
index 66c43c2197..7a27eb68bf 100644
--- a/test/MC/Disassembler/ARM/invalid-Bcc-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-Bcc-thumb.txt
@@ -1,10 +1,11 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=2249 Name=tBcc Format=ARM_FORMAT_THUMBFRM(25)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 1: 0: 1| 1: 1: 1: 0| 0: 1: 1: 0| 1: 1: 1: 1|
# -------------------------------------------------------------------------------------------------
-#
+#
# if cond = '1110' then UNDEFINED
0x6f 0xde
diff --git a/test/MC/Disassembler/ARM/invalid-CPS2p-arm.txt b/test/MC/Disassembler/ARM/invalid-CPS2p-arm.txt
index 10748e9b12..d3a75cb80c 100644
--- a/test/MC/Disassembler/ARM/invalid-CPS2p-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-CPS2p-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# invalid imod value (0b01)
0xc0 0x67 0x4 0xf1
diff --git a/test/MC/Disassembler/ARM/invalid-CPS3p-arm.txt b/test/MC/Disassembler/ARM/invalid-CPS3p-arm.txt
index 5202217b6a..cc6062eae4 100644
--- a/test/MC/Disassembler/ARM/invalid-CPS3p-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-CPS3p-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# invalid (imod, M, iflags) combination
0x93 0x1c 0x02 0xf1
diff --git a/test/MC/Disassembler/ARM/invalid-DMB-thumb.txt b/test/MC/Disassembler/ARM/invalid-DMB-thumb.txt
index 0a4be6826c..b9fe9c7a4a 100644
--- a/test/MC/Disassembler/ARM/invalid-DMB-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-DMB-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1908 Name=t2DMB Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-DSB-arm.txt b/test/MC/Disassembler/ARM/invalid-DSB-arm.txt
index afa2baff61..85ea5c6960 100644
--- a/test/MC/Disassembler/ARM/invalid-DSB-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-DSB-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=102 Name=DSB Format=ARM_FORMAT_MISCFRM(26)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-LDC-form-arm.txt b/test/MC/Disassembler/ARM/invalid-LDC-form-arm.txt
index b966a9d773..0b0426b2da 100644
--- a/test/MC/Disassembler/ARM/invalid-LDC-form-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDC-form-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=0 Name=PHI Format=(42)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 0: 1| 1: 1: 0: 0| 0: 0: 0: 1| 1: 1: 1: 1| 1: 0: 1: 1| 0: 1: 0: 0| 1: 0: 0: 1| 0: 0: 1: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-LDRB_POST-arm.txt b/test/MC/Disassembler/ARM/invalid-LDRB_POST-arm.txt
index 7a35c2d6ce..032021362d 100644
--- a/test/MC/Disassembler/ARM/invalid-LDRB_POST-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDRB_POST-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=140 Name=LDRB_POST Format=ARM_FORMAT_LDFRM(6)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-LDRD_PRE-thumb.txt b/test/MC/Disassembler/ARM/invalid-LDRD_PRE-thumb.txt
index da2e6bed86..45f6aa81f5 100644
--- a/test/MC/Disassembler/ARM/invalid-LDRD_PRE-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDRD_PRE-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1930 Name=t2LDRD_PRE Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-LDRT-arm.txt b/test/MC/Disassembler/ARM/invalid-LDRT-arm.txt
index fb2ce20d2c..067dcb36a7 100644
--- a/test/MC/Disassembler/ARM/invalid-LDRT-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDRT-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=0 Name=PHI Format=(42)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 0| 0: 1: 1: 0| 0: 0: 1: 1| 0: 1: 1: 1| 0: 1: 0: 1| 0: 0: 0: 1| 0: 0: 0: 1| 0: 0: 0: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-LDR_POST-arm.txt b/test/MC/Disassembler/ARM/invalid-LDR_POST-arm.txt
index ad79986b25..eef2c45db5 100644
--- a/test/MC/Disassembler/ARM/invalid-LDR_POST-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDR_POST-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# LDR_PRE/POST has encoding Inst{4} = 0.
0xde 0x69 0x18 0x46
diff --git a/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt b/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt
index 36c1124bce..d6a7ea67e2 100644
--- a/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=165 Name=LDR_PRE Format=ARM_FORMAT_LDFRM(6)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-LSL-regform.txt b/test/MC/Disassembler/ARM/invalid-LSL-regform.txt
index 20293ada79..b3a7238ecb 100644
--- a/test/MC/Disassembler/ARM/invalid-LSL-regform.txt
+++ b/test/MC/Disassembler/ARM/invalid-LSL-regform.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=196 Name=MOVs Format=ARM_FORMAT_DPSOREGFRM(5)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-MCR-arm.txt b/test/MC/Disassembler/ARM/invalid-MCR-arm.txt
index d39b9c1d60..8343d549e1 100644
--- a/test/MC/Disassembler/ARM/invalid-MCR-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MCR-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=171 Name=MCR Format=ARM_FORMAT_BRFRM(2)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 0: 0: 1: 0| 1: 1: 1: 0| 1: 0: 1: 0| 0: 0: 0: 0| 0: 0: 0: 1| 1: 0: 1: 1| 0: 0: 0: 1| 1: 0: 1: 1|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-MOVTi16-arm.txt b/test/MC/Disassembler/ARM/invalid-MOVTi16-arm.txt
index 0b8a0776cc..0209f03895 100644
--- a/test/MC/Disassembler/ARM/invalid-MOVTi16-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MOVTi16-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=185 Name=MOVTi16 Format=ARM_FORMAT_DPFRM(4)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-MOVr-arm.txt b/test/MC/Disassembler/ARM/invalid-MOVr-arm.txt
index f82d3cb0b1..01c1466a28 100644
--- a/test/MC/Disassembler/ARM/invalid-MOVr-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MOVr-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=0 Name=PHI Format=(42)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 0: 0: 0: 1| 1: 0: 1: 1| 1: 1: 0: 0| 1: 1: 0: 1| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 1: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-MOVs-LSL-arm.txt b/test/MC/Disassembler/ARM/invalid-MOVs-LSL-arm.txt
index 3165ff794f..757d167594 100644
--- a/test/MC/Disassembler/ARM/invalid-MOVs-LSL-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MOVs-LSL-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=196 Name=MOVs Format=ARM_FORMAT_DPSOREGFRM(5)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 0: 1| 0: 0: 0: 1| 1: 0: 1: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 0: 1: 0| 1: 0: 0: 1| 0: 0: 1: 1|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-MOVs-arm.txt b/test/MC/Disassembler/ARM/invalid-MOVs-arm.txt
index cfbba43fd5..ba488776c0 100644
--- a/test/MC/Disassembler/ARM/invalid-MOVs-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MOVs-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=0 Name=PHI Format=(42)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 0: 0: 0: 1| 1: 0: 1: 1| 1: 1: 0: 0| 1: 1: 0: 1| 0: 0: 0: 1| 0: 0: 0: 0| 0: 0: 1: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-MSRi-arm.txt b/test/MC/Disassembler/ARM/invalid-MSRi-arm.txt
index e9d5deb043..66e74dba19 100644
--- a/test/MC/Disassembler/ARM/invalid-MSRi-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-MSRi-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=206 Name=MSRi Format=ARM_FORMAT_BRFRM(2)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-RFEorLDMIA-arm.txt b/test/MC/Disassembler/ARM/invalid-RFEorLDMIA-arm.txt
index 1fdfa8299c..cffd86dc1a 100644
--- a/test/MC/Disassembler/ARM/invalid-RFEorLDMIA-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-RFEorLDMIA-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=134 Name=LDMIA Format=ARM_FORMAT_LDSTMULFRM(10)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 1: 0: 0: 0| 1: 0: 0: 1| 1: 0: 0: 1| 1: 0: 1: 1| 0: 0: 0: 1| 0: 0: 1: 1| 0: 0: 1: 0|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-RSC-arm.txt b/test/MC/Disassembler/ARM/invalid-RSC-arm.txt
index e7992ae634..b74bcc94b5 100644
--- a/test/MC/Disassembler/ARM/invalid-RSC-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-RSC-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=261 Name=RSCrs Format=ARM_FORMAT_DPSOREGFRM(5)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-SBFX-arm.txt b/test/MC/Disassembler/ARM/invalid-SBFX-arm.txt
index 1ecd87df07..4939ebcb19 100644
--- a/test/MC/Disassembler/ARM/invalid-SBFX-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-SBFX-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=271 Name=SBFX Format=ARM_FORMAT_DPFRM(4)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-SMLAD-arm.txt b/test/MC/Disassembler/ARM/invalid-SMLAD-arm.txt
index c3dcf83fbd..e66104676f 100644
--- a/test/MC/Disassembler/ARM/invalid-SMLAD-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-SMLAD-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=284 Name=SMLAD Format=ARM_FORMAT_MULFRM(1)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-SRS-arm.txt b/test/MC/Disassembler/ARM/invalid-SRS-arm.txt
index fdca9f9eae..fc5c711a23 100644
--- a/test/MC/Disassembler/ARM/invalid-SRS-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-SRS-arm.txt
@@ -1,7 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=0 Name=PHI Format=(42)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 1: 0: 0: 0| 1: 1: 0: 0| 0: 1: 0: 1| 0: 0: 0: 1| 1: 1: 0: 0| 1: 0: 0: 0| 0: 0: 1: 1|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-SSAT-arm.txt b/test/MC/Disassembler/ARM/invalid-SSAT-arm.txt
index 9cc8351b78..a02e459eb6 100644
--- a/test/MC/Disassembler/ARM/invalid-SSAT-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-SSAT-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=322 Name=SSAT Format=ARM_FORMAT_SATFRM(13)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-STMIA_UPD-thumb.txt b/test/MC/Disassembler/ARM/invalid-STMIA_UPD-thumb.txt
index 0000c60ce4..b92ce72833 100644
--- a/test/MC/Disassembler/ARM/invalid-STMIA_UPD-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-STMIA_UPD-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=2313 Name=tSTMIA_UPD Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-STRBrs-arm.txt b/test/MC/Disassembler/ARM/invalid-STRBrs-arm.txt
index 5209323fa8..6d570ee016 100644
--- a/test/MC/Disassembler/ARM/invalid-STRBrs-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-STRBrs-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=355 Name=STRBrs Format=ARM_FORMAT_STFRM(7)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-SXTB-arm.txt b/test/MC/Disassembler/ARM/invalid-SXTB-arm.txt
index 4ec681daf9..4667edb4ca 100644
--- a/test/MC/Disassembler/ARM/invalid-SXTB-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-SXTB-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=390 Name=SXTBr_rot Format=ARM_FORMAT_EXTFRM(14)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-UMAAL-arm.txt b/test/MC/Disassembler/ARM/invalid-UMAAL-arm.txt
index 7a3ef3328a..c7cbd84487 100644
--- a/test/MC/Disassembler/ARM/invalid-UMAAL-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-UMAAL-arm.txt
@@ -1,11 +1,11 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=419 Name=UMAAL Format=ARM_FORMAT_MULFRM(1)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 0: 0: 0: 0| 0: 1: 0: 0| 1: 1: 1: 1| 1: 0: 1: 1| 1: 1: 1: 1| 1: 0: 0: 1| 1: 0: 0: 0|
# -------------------------------------------------------------------------------------------------
#
# A8.6.244 UMAAL
# if dLo == 15 || dHi == 15 || n == 15 || m == 15 then UNPREDICTABLE;
-0x98 0xbf 0x4f 0xf0
+0x98 0xbf 0x4f 0xf0
diff --git a/test/MC/Disassembler/ARM/invalid-UQADD8-arm.txt b/test/MC/Disassembler/ARM/invalid-UQADD8-arm.txt
index d3f508a1da..f4a46b27e8 100644
--- a/test/MC/Disassembler/ARM/invalid-UQADD8-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-UQADD8-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=426 Name=UQADD8 Format=ARM_FORMAT_DPFRM(4)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-VLD1DUPq8_UPD-arm.txt b/test/MC/Disassembler/ARM/invalid-VLD1DUPq8_UPD-arm.txt
index 56d9ad704a..4120779b99 100644
--- a/test/MC/Disassembler/ARM/invalid-VLD1DUPq8_UPD-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-VLD1DUPq8_UPD-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=737 Name=VLD1DUPq8_UPD Format=ARM_FORMAT_NLdSt(30)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-VLD3DUPd32_UPD-thumb.txt b/test/MC/Disassembler/ARM/invalid-VLD3DUPd32_UPD-thumb.txt
index 5fd0251799..bab32ca171 100644
--- a/test/MC/Disassembler/ARM/invalid-VLD3DUPd32_UPD-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-VLD3DUPd32_UPD-thumb.txt
@@ -1,11 +1,11 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=871 Name=VLD3DUPd32_UPD Format=ARM_FORMAT_NLdSt(30)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 0: 1: 0: 0| 1: 0: 1: 0| 0: 0: 1: 0| 0: 0: 1: 0| 1: 1: 1: 0| 1: 0: 0: 1| 0: 0: 1: 0|
# -------------------------------------------------------------------------------------------------
-#
+#
# A8.6.315 VLD3 (single 3-element structure to all lanes)
# The a bit must be encoded as 0.
0xa2 0xf9 0x92 0x2e
diff --git a/test/MC/Disassembler/ARM/invalid-VLDMSDB_UPD-arm.txt b/test/MC/Disassembler/ARM/invalid-VLDMSDB_UPD-arm.txt
index 887b983edd..f6ed684c08 100644
--- a/test/MC/Disassembler/ARM/invalid-VLDMSDB_UPD-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-VLDMSDB_UPD-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# core registers out of range
0xa5 0xba 0x72 0xed
diff --git a/test/MC/Disassembler/ARM/invalid-VQADD-arm.txt b/test/MC/Disassembler/ARM/invalid-VQADD-arm.txt
index eed012b0be..2c2e5ac1fe 100644
--- a/test/MC/Disassembler/ARM/invalid-VQADD-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-VQADD-arm.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1225 Name=VQADDsv16i8 Format=ARM_FORMAT_N3Reg(37)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-VST2b32_UPD-arm.txt b/test/MC/Disassembler/ARM/invalid-VST2b32_UPD-arm.txt
index 506250c3bc..5651860845 100644
--- a/test/MC/Disassembler/ARM/invalid-VST2b32_UPD-arm.txt
+++ b/test/MC/Disassembler/ARM/invalid-VST2b32_UPD-arm.txt
@@ -1,7 +1,8 @@
# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1641 Name=VST2b32_UPD Format=ARM_FORMAT_NLdSt(30)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 0: 1: 0: 0| 0: 0: 0: 0| 0: 0: 1: 1| 0: 0: 0: 0| 1: 0: 0: 1| 1: 0: 1: 1| 0: 0: 1: 1|
# -------------------------------------------------------------------------------------------------
diff --git a/test/MC/Disassembler/ARM/invalid-t2Bcc-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2Bcc-thumb.txt
index d0bc51ebaf..6482d2f559 100644
--- a/test/MC/Disassembler/ARM/invalid-t2Bcc-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2Bcc-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1894 Name=t2Bcc Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2LDRBT-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2LDRBT-thumb.txt
index 9befbd6b6f..e1f841b86d 100644
--- a/test/MC/Disassembler/ARM/invalid-t2LDRBT-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2LDRBT-thumb.txt
@@ -1,10 +1,10 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=1922 Name=t2LDRBT Format=ARM_FORMAT_THUMBFRM(25)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 1| 1: 0: 0: 0| 0: 0: 0: 1| 0: 0: 0: 0| 1: 1: 1: 1| 1: 1: 1: 0| 0: 0: 0: 0| 0: 0: 1: 1|
# -------------------------------------------------------------------------------------------------
-#
+#
# The unpriviledged Load/Store cannot have SP or PC as Rt.
0x10 0xf8 0x3 0xfe
diff --git a/test/MC/Disassembler/ARM/invalid-t2LDREXD-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2LDREXD-thumb.txt
index 598efd1bc7..790f354c17 100644
--- a/test/MC/Disassembler/ARM/invalid-t2LDREXD-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2LDREXD-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1934 Name=t2LDREXD Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2LDRSHi12-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2LDRSHi12-thumb.txt
index a501eb9cd5..f1420ba486 100644
--- a/test/MC/Disassembler/ARM/invalid-t2LDRSHi12-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2LDRSHi12-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1953 Name=t2LDRSHi12 Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2LDRSHi8-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2LDRSHi8-thumb.txt
index f886a6f074..5029f6f285 100644
--- a/test/MC/Disassembler/ARM/invalid-t2LDRSHi8-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2LDRSHi8-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=1954 Name=t2LDRSHi8 Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2STRD_PRE-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2STRD_PRE-thumb.txt
index c8f8ec294e..ce54ef3c28 100644
--- a/test/MC/Disassembler/ARM/invalid-t2STRD_PRE-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2STRD_PRE-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=2124 Name=t2STRD_PRE Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2STREXB-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2STREXB-thumb.txt
index 35ea651164..55a52cfef9 100644
--- a/test/MC/Disassembler/ARM/invalid-t2STREXB-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2STREXB-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=2127 Name=t2STREXB Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/invalid-t2STREXD-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2STREXD-thumb.txt
index 9b0cf24ffb..0f9a16ee54 100644
--- a/test/MC/Disassembler/ARM/invalid-t2STREXD-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2STREXD-thumb.txt
@@ -1,10 +1,10 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
# Opcode=2128 Name=t2STREXD Format=ARM_FORMAT_THUMBFRM(25)
-# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
# -------------------------------------------------------------------------------------------------
# | 1: 1: 1: 0| 1: 0: 0: 0| 1: 1: 0: 0| 0: 0: 1: 0| 0: 1: 1: 1| 1: 0: 0: 0| 0: 1: 1: 1| 1: 0: 0: 0|
# -------------------------------------------------------------------------------------------------
-#
+#
# if d == n || d == t || d == t2 then UNPREDICTABLE
mc-input.txt:1:1: warning: invalid instruction encoding
diff --git a/test/MC/Disassembler/ARM/invalid-t2STR_POST-thumb.txt b/test/MC/Disassembler/ARM/invalid-t2STR_POST-thumb.txt
index 129a2704d5..666d143a8c 100644
--- a/test/MC/Disassembler/ARM/invalid-t2STR_POST-thumb.txt
+++ b/test/MC/Disassembler/ARM/invalid-t2STR_POST-thumb.txt
@@ -1,4 +1,5 @@
# RUN: llvm-mc --disassemble %s -triple=thumb-apple-darwin9 |& grep {invalid instruction encoding}
+# XFAIL: *
# Opcode=2137 Name=t2STR_POST Format=ARM_FORMAT_THUMBFRM(25)
# 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
diff --git a/test/MC/Disassembler/ARM/neon-tests.txt b/test/MC/Disassembler/ARM/neon-tests.txt
index 4fa57230d7..7fce4e2362 100644
--- a/test/MC/Disassembler/ARM/neon-tests.txt
+++ b/test/MC/Disassembler/ARM/neon-tests.txt
@@ -24,7 +24,7 @@
# CHECK: vld1.32 {d3[], d4[]}, [r0, :32]!
0xbd 0x3c 0xa0 0xf4
-# CHECK: vld4.16 {d3[], d4[], d5[], d6[]}, [r0, :64]!
+# CHECK: vld4.16 {d3[], d5[], d7[], d9[]}, [r0, :64]!
0x7d 0x3f 0xa0 0xf4
# CHECK: vorr d0, d15, d15
@@ -87,5 +87,5 @@
# CHECK: usada8mi r8, r9, r5, r9
0x19 0x95 0x88 0x47
-# CHECK: vext.8 q4, q2, q1, #4
+# CHECK: vext.32 q4, q2, q1, #1
0x42 0x84 0xb4 0xf2
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 07313d19e8..126925369c 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -128,12 +128,5 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
return;
}
- // Fixed-instruction-length targets use a common disassembler.
- // ARM use its own implementation for now.
- if (Target.getName() == "ARM") {
- ARMDecoderEmitter(Records).run(OS);
- return;
- }
-
FixedLenDecoderEmitter(Records).run(OS);
}