[llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/
Bob Wilson
bob.wilson at apple.com
Tue Mar 16 10:01:13 PDT 2010
I've reverted this since it broke the buildbots. I'd like a chance to review this before you re-commit with fixes.
On Mar 16, 2010, at 9:36 AM, Johnny Chen wrote:
> Author: johnny
> Date: Tue Mar 16 11:36:54 2010
> New Revision: 98637
>
> URL: http://llvm.org/viewvc/llvm-project?rev=98637&view=rev
> Log:
> Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend
> (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb,
> and the disassembler core which invokes the decoder function and builds up the
> MCInst based on the decoded Opcode.
>
> Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm
> instructions to help disassembly.
>
> We also changed the output of the addressing modes to omit the '+' from the
> assembler syntax #+/-<imm> or +/-<Rm>. See, for example, A8.6.57/58/60.
>
> And modified test cases to not expect '+' in +reg or #+num. For example,
>
> ; CHECK: ldr.w r9, [r7, #28]
>
> Added:
> llvm/trunk/lib/Target/ARM/Disassembler/
> llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
> llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h
> llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
> llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
> llvm/trunk/lib/Target/ARM/Disassembler/Makefile
> llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc
> llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp
> llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h
> Modified:
> llvm/trunk/Makefile.rules
> llvm/trunk/lib/Target/ARM/ARMAddressingModes.h
> llvm/trunk/lib/Target/ARM/ARMInstrFormats.td
> llvm/trunk/lib/Target/ARM/ARMInstrNEON.td
> llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
> llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp
> llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h
> llvm/trunk/lib/Target/ARM/Makefile
> llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp
> llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll
> llvm/trunk/test/CodeGen/ARM/2009-10-30.ll
> llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll
> llvm/trunk/test/CodeGen/ARM/globals.ll
> llvm/trunk/test/CodeGen/ARM/ldrd.ll
> llvm/trunk/test/CodeGen/ARM/str_pre-2.ll
> llvm/trunk/test/CodeGen/ARM/tls2.ll
> llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll
> llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp
> llvm/trunk/utils/TableGen/TableGen.cpp
>
> Modified: llvm/trunk/Makefile.rules
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/Makefile.rules?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/Makefile.rules (original)
> +++ llvm/trunk/Makefile.rules Tue Mar 16 11:36:54 2010
> @@ -1614,6 +1614,11 @@
> $(Echo) "Building $(<F) intrinsics information with tblgen"
> $(Verb) $(TableGen) -gen-tgt-intrinsic -o $(call SYSPATH, $@) $<
>
> +$(ObjDir)/ARMDisassemblerTables.inc.tmp : ARM.td $(ObjDir)/.dir
> + $(Echo) "Building ARM disassembly tables with tblgen"
> + $(Verb) $(TableGen) -gen-risc-disassembler -o $(call SYSPATH, $@) $<
> +
> +
> clean-local::
> -$(Verb) $(RM) -f $(INCFiles)
>
>
> Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original)
> +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 11:36:54 2010
> @@ -35,6 +35,10 @@
> add = '+', sub = '-'
> };
>
> + static inline const char *getAddrOpcStr(AddrOpc Op) {
> + return Op == sub ? "-" : "";
> + }
> +
> static inline const char *getShiftOpcStr(ShiftOpc Op) {
> switch (Op) {
> default: assert(0 && "Unknown shift opc!");
> @@ -127,6 +131,20 @@
> return (Imm >> 8) * 2;
> }
>
> + /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter
> + /// operand, computing the rotate amount to use. If this immediate value
> + /// cannot be handled with a single shifter-op, return 0.
> + static inline unsigned getSOImmValOneRotate(unsigned Imm) {
> + // A5.2.4 Constants with multiple encodings
> + // The lowest unsigned value of rotation wins!
> + for (unsigned R = 1; R <= 15; ++R)
> + if ((Imm & rotr32(~255U, 2*R)) == 0)
> + return 2*R;
> +
> + // Failed to find a suitable rotate amount.
> + return 0;
> + }
> +
> /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
> /// computing the rotate amount to use. If this immediate value cannot be
> /// handled with a single shifter-op, determine a good rotate amount that will
> @@ -179,7 +197,7 @@
> // of zero.
> if ((Arg & ~255U) == 0) return Arg;
>
> - unsigned RotAmt = getSOImmValRotate(Arg);
> + unsigned RotAmt = getSOImmValOneRotate(Arg);
>
> // If this cannot be handled with a single shifter_op, bail out.
> if (rotr32(~255U, RotAmt) & Arg)
>
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Tue Mar 16 11:36:54 2010
> @@ -1464,6 +1464,29 @@
> // ARM NEON Instruction templates.
> //
>
> +// NSFormat specifies further details of a NEON instruction. This is used by
> +// the disassembler to classify NEONFrm instructions for disassembly purpose.
> +class NSFormat<bits<5> val> {
> + bits<5> Value = val;
> +}
> +def NSFormatNone : NSFormat<0>;
> +def VLDSTLaneFrm : NSFormat<1>;
> +def VLDSTLaneDblFrm : NSFormat<2>;
> +def VLDSTRQFrm : NSFormat<3>;
> +def NVdImmFrm : NSFormat<4>;
> +def NVdVmImmFrm : NSFormat<5>;
> +def NVdVmImmVCVTFrm : NSFormat<6>;
> +def NVdVmImmVDupLaneFrm : NSFormat<7>;
> +def NVdVmImmVSHLLFrm : NSFormat<8>;
> +def NVectorShuffleFrm : NSFormat<9>;
> +def NVectorShiftFrm : NSFormat<10>;
> +def NVectorShift2Frm : NSFormat<11>;
> +def NVdVnVmImmFrm : NSFormat<12>;
> +def NVdVnVmImmVectorShiftFrm : NSFormat<13>;
> +def NVdVnVmImmVectorExtractFrm : NSFormat<14>;
> +def NVdVnVmImmMulScalarFrm : NSFormat<15>;
> +def VTBLFrm : NSFormat<16>;
> +
> class NeonI<dag oops, dag iops, AddrMode am, IndexMode im, InstrItinClass itin,
> string opc, string dt, string asm, string cstr, list<dag> pattern>
> : InstARM<am, Size4Bytes, im, NEONFrm, NeonDomain, cstr, itin> {
> @@ -1474,6 +1497,8 @@
> !strconcat("\t", asm));
> let Pattern = pattern;
> list<Predicate> Predicates = [HasNEON];
> + NSFormat NSF = NSFormatNone; // For disassembly.
> + bits<5> NSForm = NSFormatNone.Value; // For disassembly.
> }
>
> // Same as NeonI except it does not have a "data type" specifier.
> @@ -1485,6 +1510,8 @@
> let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm));
> let Pattern = pattern;
> list<Predicate> Predicates = [HasNEON];
> + NSFormat NSF = NSFormatNone; // For disassembly.
> + bits<5> NSForm = NSFormatNone.Value; // For disassembly.
> }
>
> class NI<dag oops, dag iops, InstrItinClass itin, string opc, string asm,
> @@ -1497,6 +1524,8 @@
> string asm, list<dag> pattern>
> : NeonXI<oops, iops, AddrMode4, IndexModeNone, itin, opc, asm, "",
> pattern> {
> + let NSF = VLDSTRQFrm; // For disassembly.
> + let NSForm = VLDSTRQFrm.Value; // For disassembly.
> }
>
> class NLdSt<bit op23, bits<2> op21_20, bits<4> op11_8, bits<4> op7_4,
> @@ -1509,6 +1538,8 @@
> let Inst{21-20} = op21_20;
> let Inst{11-8} = op11_8;
> let Inst{7-4} = op7_4;
> + let NSF = VLDSTLaneFrm; // For disassembly.
> + let NSForm = VLDSTLaneFrm.Value; // For disassembly.
> }
>
> class NDataI<dag oops, dag iops, InstrItinClass itin,
> @@ -1538,6 +1569,8 @@
> let Inst{6} = op6;
> let Inst{5} = op5;
> let Inst{4} = op4;
> + let NSF = NVdImmFrm; // For disassembly.
> + let NSForm = NVdImmFrm.Value; // For disassembly.
> }
>
> // NEON 2 vector register format.
> @@ -1553,6 +1586,8 @@
> let Inst{11-7} = op11_7;
> let Inst{6} = op6;
> let Inst{4} = op4;
> + let NSF = NVdVmImmFrm; // For disassembly.
> + let NSForm = NVdVmImmFrm.Value; // For disassembly.
> }
>
> // Same as N2V except it doesn't have a datatype suffix.
> @@ -1568,6 +1603,8 @@
> let Inst{11-7} = op11_7;
> let Inst{6} = op6;
> let Inst{4} = op4;
> + let NSF = NVdVmImmFrm; // For disassembly.
> + let NSForm = NVdVmImmFrm.Value; // For disassembly.
> }
>
> // NEON 2 vector register with immediate.
> @@ -1581,6 +1618,8 @@
> let Inst{7} = op7;
> let Inst{6} = op6;
> let Inst{4} = op4;
> + let NSF = NVdVmImmFrm; // For disassembly.
> + let NSForm = NVdVmImmFrm.Value; // For disassembly.
> }
>
> // NEON 3 vector register format.
> @@ -1594,6 +1633,8 @@
> let Inst{11-8} = op11_8;
> let Inst{6} = op6;
> let Inst{4} = op4;
> + let NSF = NVdVnVmImmFrm; // For disassembly.
> + let NSForm = NVdVnVmImmFrm.Value; // For disassembly.
> }
>
> // Same as N3VX except it doesn't have a data type suffix.
> @@ -1607,6 +1648,8 @@
> let Inst{11-8} = op11_8;
> let Inst{6} = op6;
> let Inst{4} = op4;
> + let NSF = NVdVnVmImmFrm; // For disassembly.
> + let NSForm = NVdVnVmImmFrm.Value; // For disassembly.
> }
>
> // NEON VMOVs between scalar and core registers.
>
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrNEON.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrNEON.td?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrNEON.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Tue Mar 16 11:36:54 2010
> @@ -213,7 +213,10 @@
> class VLD2Ddbl<bits<4> op7_4, string OpcodeStr, string Dt>
> : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2),
> (ins addrmode6:$addr), IIC_VLD2,
> - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>;
> + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">;
> def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">;
> @@ -228,7 +231,10 @@
> : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb),
> (ins addrmode6:$addr), IIC_VLD3,
> OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr",
> - "$addr.addr = $wb", []>;
> + "$addr.addr = $wb", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VLD3d8 : VLD3D<0b0000, "vld3", "8">;
> def VLD3d16 : VLD3D<0b0100, "vld3", "16">;
> @@ -260,7 +266,10 @@
> (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb),
> (ins addrmode6:$addr), IIC_VLD4,
> OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr",
> - "$addr.addr = $wb", []>;
> + "$addr.addr = $wb", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VLD4d8 : VLD4D<0b0000, "vld4", "8">;
> def VLD4d16 : VLD4D<0b0100, "vld4", "16">;
> @@ -297,12 +306,28 @@
> def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; }
>
> // vld2 to double-spaced even registers.
> -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; }
> -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; }
> +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // vld2 to double-spaced odd registers.
> -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; }
> -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; }
> +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // VLD3LN : Vector Load (single 3-element structure to one lane)
> class VLD3LN<bits<4> op11_8, string OpcodeStr, string Dt>
> @@ -318,7 +343,11 @@
> def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; }
>
> // vld3 to double-spaced even registers.
> -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; }
> +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> {
> + let Inst{5-4} = 0b10;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; }
>
> // vld3 to double-spaced odd registers.
> @@ -340,12 +369,28 @@
> def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; }
>
> // vld4 to double-spaced even registers.
> -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; }
> -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; }
> +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // vld4 to double-spaced odd registers.
> -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; }
> -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; }
> +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // VLD1DUP : Vector Load (single element to all lanes)
> // VLD2DUP : Vector Load (single 2-element structure to all lanes)
> @@ -433,7 +478,10 @@
> class VST2Ddbl<bits<4> op7_4, string OpcodeStr, string Dt>
> : NLdSt<0, 0b00, 0b1001, op7_4, (outs),
> (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST,
> - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>;
> + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">;
> def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">;
> @@ -448,7 +496,10 @@
> : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb),
> (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST,
> OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr",
> - "$addr.addr = $wb", []>;
> + "$addr.addr = $wb", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VST3d8 : VST3D<0b0000, "vst3", "8">;
> def VST3d16 : VST3D<0b0100, "vst3", "16">;
> @@ -478,7 +529,10 @@
> : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb),
> (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4),
> IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr",
> - "$addr.addr = $wb", []>;
> + "$addr.addr = $wb", []> {
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> def VST4d8 : VST4D<0b0000, "vst4", "8">;
> def VST4d16 : VST4D<0b0100, "vst4", "16">;
> @@ -515,12 +569,28 @@
> def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; }
>
> // vst2 to double-spaced even registers.
> -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; }
> -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; }
> +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // vst2 to double-spaced odd registers.
> -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; }
> -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; }
> +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // VST3LN : Vector Store (single 3-element structure from one lane)
> class VST3LN<bits<4> op11_8, string OpcodeStr, string Dt>
> @@ -535,12 +605,28 @@
> def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; }
>
> // vst3 to double-spaced even registers.
> -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; }
> -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; }
> +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> {
> + let Inst{5-4} = 0b10;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> {
> + let Inst{6-4} = 0b100;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // vst3 to double-spaced odd registers.
> -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; }
> -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; }
> +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> {
> + let Inst{5-4} = 0b10;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> {
> + let Inst{6-4} = 0b100;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // VST4LN : Vector Store (single 4-element structure from one lane)
> class VST4LN<bits<4> op11_8, string OpcodeStr, string Dt>
> @@ -556,12 +642,28 @@
> def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; }
>
> // vst4 to double-spaced even registers.
> -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; }
> -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; }
> +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> // vst4 to double-spaced odd registers.
> -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; }
> -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; }
> +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> {
> + let Inst{5} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
> +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> {
> + let Inst{6} = 1;
> + let NSF = VLDSTLaneDblFrm; // For disassembly.
> + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
> +}
>
> } // mayStore = 1, hasExtraSrcRegAllocReq = 1
>
> @@ -668,12 +770,18 @@
> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2),
> (ins DPR:$src1, DPR:$src2), IIC_VPERMD,
> OpcodeStr, Dt, "$dst1, $dst2",
> - "$src1 = $dst1, $src2 = $dst2", []>;
> + "$src1 = $dst1, $src2 = $dst2", []> {
> + let NSF = NVectorShuffleFrm; // For disassembly.
> + let NSForm = NVectorShuffleFrm.Value; // For disassembly.
> +}
> class N2VQShuffle<bits<2> op19_18, bits<5> op11_7,
> InstrItinClass itin, string OpcodeStr, string Dt>
> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2),
> (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2",
> - "$src1 = $dst1, $src2 = $dst2", []>;
> + "$src1 = $dst1, $src2 = $dst2", []> {
> + let NSF = NVectorShuffleFrm; // For disassembly.
> + let NSForm = NVectorShuffleFrm.Value; // For disassembly.
> +}
>
> // Basic 3-register operations: single-, double- and quad-register.
> class N3VS<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
> @@ -715,6 +823,8 @@
> (Ty (ShOp (Ty DPR:$src1),
> (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
> class N3VDSL16<bits<2> op21_20, bits<4> op11_8,
> string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp>
> @@ -725,6 +835,8 @@
> (Ty (ShOp (Ty DPR:$src1),
> (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
>
> class N3VQ<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
> @@ -756,6 +868,8 @@
> (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
> class N3VQSL16<bits<2> op21_20, bits<4> op11_8, string OpcodeStr, string Dt,
> ValueType ResTy, ValueType OpTy, SDNode ShOp>
> @@ -767,6 +881,8 @@
> (ResTy (NEONvduplane (OpTy DPR_8:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
>
> // Basic 3-register intrinsics, both double- and quad-register.
> @@ -789,6 +905,8 @@
> (Ty (NEONvduplane (Ty DPR_VFP2:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
> class N3VDIntSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
> string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp>
> @@ -800,6 +918,8 @@
> (Ty (NEONvduplane (Ty DPR_8:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
>
> class N3VQInt<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
> @@ -822,6 +942,8 @@
> (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
> class N3VQIntSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
> string OpcodeStr, string Dt,
> @@ -834,6 +956,8 @@
> (ResTy (NEONvduplane (OpTy DPR_8:$src2),
> imm:$lane)))))]> {
> let isCommutable = 0;
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> }
>
> // Multiply-Add/Sub operations: single-, double- and quad-register.
> @@ -864,7 +988,10 @@
> (Ty (ShOp (Ty DPR:$src1),
> (Ty (MulOp DPR:$src2,
> (Ty (NEONvduplane (Ty DPR_VFP2:$src3),
> - imm:$lane)))))))]>;
> + imm:$lane)))))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
> class N3VDMulOpSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
> string OpcodeStr, string Dt,
> ValueType Ty, SDNode MulOp, SDNode ShOp>
> @@ -876,7 +1003,10 @@
> (Ty (ShOp (Ty DPR:$src1),
> (Ty (MulOp DPR:$src2,
> (Ty (NEONvduplane (Ty DPR_8:$src3),
> - imm:$lane)))))))]>;
> + imm:$lane)))))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
>
> class N3VQMulOp<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
> InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty,
> @@ -897,7 +1027,10 @@
> (ResTy (ShOp (ResTy QPR:$src1),
> (ResTy (MulOp QPR:$src2,
> (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3),
> - imm:$lane)))))))]>;
> + imm:$lane)))))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
> class N3VQMulOpSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
> string OpcodeStr, string Dt,
> ValueType ResTy, ValueType OpTy,
> @@ -910,7 +1043,10 @@
> (ResTy (ShOp (ResTy QPR:$src1),
> (ResTy (MulOp QPR:$src2,
> (ResTy (NEONvduplane (OpTy DPR_8:$src3),
> - imm:$lane)))))))]>;
> + imm:$lane)))))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
>
> // Neon 3-argument intrinsics, both double- and quad-register.
> // The destination register is also used as the first source operand register.
> @@ -996,7 +1132,10 @@
> [(set (ResTy QPR:$dst),
> (ResTy (IntOp (OpTy DPR:$src1),
> (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2),
> - imm:$lane)))))]>;
> + imm:$lane)))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
> class N3VLIntSL16<bit op24, bits<2> op21_20, bits<4> op11_8,
> InstrItinClass itin, string OpcodeStr, string Dt,
> ValueType ResTy, ValueType OpTy, Intrinsic IntOp>
> @@ -1006,7 +1145,10 @@
> [(set (ResTy QPR:$dst),
> (ResTy (IntOp (OpTy DPR:$src1),
> (OpTy (NEONvduplane (OpTy DPR_8:$src2),
> - imm:$lane)))))]>;
> + imm:$lane)))))]> {
> + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
> + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
> +}
>
> // Wide 3-register intrinsics.
> class N3VWInt<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
> @@ -1055,6 +1197,10 @@
> OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst",
> [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>;
>
> +// This is a big let * in block to mark these instructions NVectorShiftFrm to
> +// help the disassembler.
> +let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in {
> +
> // Shift by immediate,
> // both double- and quad-register.
> class N2VDSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4,
> @@ -1072,16 +1218,6 @@
> OpcodeStr, Dt, "$dst, $src, $SIMM", "",
> [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>;
>
> -// Long shift by immediate.
> -class N2VLSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
> - string OpcodeStr, string Dt,
> - ValueType ResTy, ValueType OpTy, SDNode OpNode>
> - : N2VImm<op24, op23, op11_8, op7, op6, op4,
> - (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD,
> - OpcodeStr, Dt, "$dst, $src, $SIMM", "",
> - [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src),
> - (i32 imm:$SIMM))))]>;
> -
> // Narrow shift by immediate.
> class N2VNSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
> InstrItinClass itin, string OpcodeStr, string Dt,
> @@ -1124,8 +1260,26 @@
> OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst",
> [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>;
>
> +} // End of "let NSF = NVectorShiftFrm, ..."
> +
> +// Long shift by immediate.
> +class N2VLSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
> + string OpcodeStr, string Dt,
> + ValueType ResTy, ValueType OpTy, SDNode OpNode>
> + : N2VImm<op24, op23, op11_8, op7, op6, op4,
> + (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD,
> + OpcodeStr, Dt, "$dst, $src, $SIMM", "",
> + [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src),
> + (i32 imm:$SIMM))))]> {
> + // This has a different interpretation of the shift amount encoding than
> + // NVectorShiftFrm.
> + let NSF = NVectorShift2Frm; // For disassembly.
> + let NSForm = NVectorShift2Frm.Value; // For disassembly.
> +}
> +
> // Convert, with fractional bits immediate,
> // both double- and quad-register.
> +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in {
> class N2VCvtD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4,
> string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy,
> Intrinsic IntOp>
> @@ -1140,6 +1294,7 @@
> (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ,
> OpcodeStr, Dt, "$dst, $src, $SIMM", "",
> [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>;
> +}
>
> //===----------------------------------------------------------------------===//
> // Multiclasses
> @@ -1350,6 +1505,60 @@
> v2i64, v2i64, IntOp, Commutable>;
> }
>
> +// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions.
> +// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand)
> +// This helps the disassembler.
> +let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in {
> +multiclass N3VInt_HS2<bit op24, bit op23, bits<4> op11_8, bit op4,
> + InstrItinClass itinD16, InstrItinClass itinD32,
> + InstrItinClass itinQ16, InstrItinClass itinQ32,
> + string OpcodeStr, string Dt,
> + Intrinsic IntOp, bit Commutable = 0> {
> + // 64-bit vector types.
> + def v4i16 : N3VDInt<op24, op23, 0b01, op11_8, op4, itinD16,
> + OpcodeStr, !strconcat(Dt, "16"),
> + v4i16, v4i16, IntOp, Commutable>;
> + def v2i32 : N3VDInt<op24, op23, 0b10, op11_8, op4, itinD32,
> + OpcodeStr, !strconcat(Dt, "32"),
> + v2i32, v2i32, IntOp, Commutable>;
> +
> + // 128-bit vector types.
> + def v8i16 : N3VQInt<op24, op23, 0b01, op11_8, op4, itinQ16,
> + OpcodeStr, !strconcat(Dt, "16"),
> + v8i16, v8i16, IntOp, Commutable>;
> + def v4i32 : N3VQInt<op24, op23, 0b10, op11_8, op4, itinQ32,
> + OpcodeStr, !strconcat(Dt, "32"),
> + v4i32, v4i32, IntOp, Commutable>;
> +}
> +multiclass N3VInt_QHS2<bit op24, bit op23, bits<4> op11_8, bit op4,
> + InstrItinClass itinD16, InstrItinClass itinD32,
> + InstrItinClass itinQ16, InstrItinClass itinQ32,
> + string OpcodeStr, string Dt,
> + Intrinsic IntOp, bit Commutable = 0>
> + : N3VInt_HS2<op24, op23, op11_8, op4, itinD16, itinD32, itinQ16, itinQ32,
> + OpcodeStr, Dt, IntOp, Commutable> {
> + def v8i8 : N3VDInt<op24, op23, 0b00, op11_8, op4, itinD16,
> + OpcodeStr, !strconcat(Dt, "8"),
> + v8i8, v8i8, IntOp, Commutable>;
> + def v16i8 : N3VQInt<op24, op23, 0b00, op11_8, op4, itinQ16,
> + OpcodeStr, !strconcat(Dt, "8"),
> + v16i8, v16i8, IntOp, Commutable>;
> +}
> +multiclass N3VInt_QHSD2<bit op24, bit op23, bits<4> op11_8, bit op4,
> + InstrItinClass itinD16, InstrItinClass itinD32,
> + InstrItinClass itinQ16, InstrItinClass itinQ32,
> + string OpcodeStr, string Dt,
> + Intrinsic IntOp, bit Commutable = 0>
> + : N3VInt_QHS2<op24, op23, op11_8, op4, itinD16, itinD32, itinQ16, itinQ32,
> + OpcodeStr, Dt, IntOp, Commutable> {
> + def v1i64 : N3VDInt<op24, op23, 0b11, op11_8, op4, itinD32,
> + OpcodeStr, !strconcat(Dt, "64"),
> + v1i64, v1i64, IntOp, Commutable>;
> + def v2i64 : N3VQInt<op24, op23, 0b11, op11_8, op4, itinQ32,
> + OpcodeStr, !strconcat(Dt, "64"),
> + v2i64, v2i64, IntOp, Commutable>;
> +}
> +}
>
> // Neon Narrowing 3-register vector intrinsics,
> // source operand element sizes of 16, 32 and 64 bits:
> @@ -1619,6 +1828,47 @@
> // imm6 = xxxxxx
> }
>
> +// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of
> +// the shift amount. This helps the disassembler.
> +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in {
> +multiclass N2VSh_QHSD2<bit op24, bit op23, bits<4> op11_8, bit op4,
> + InstrItinClass itin, string OpcodeStr, string Dt,
> + SDNode OpNode> {
> + // 64-bit vector types.
> + def v8i8 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "8"), v8i8, OpNode> {
> + let Inst{21-19} = 0b001; // imm6 = 001xxx
> + }
> + def v4i16 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "16"), v4i16, OpNode> {
> + let Inst{21-20} = 0b01; // imm6 = 01xxxx
> + }
> + def v2i32 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "32"), v2i32, OpNode> {
> + let Inst{21} = 0b1; // imm6 = 1xxxxx
> + }
> + def v1i64 : N2VDSh<op24, op23, op11_8, 1, op4, itin,
> + OpcodeStr, !strconcat(Dt, "64"), v1i64, OpNode>;
> + // imm6 = xxxxxx
> +
> + // 128-bit vector types.
> + def v16i8 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "8"), v16i8, OpNode> {
> + let Inst{21-19} = 0b001; // imm6 = 001xxx
> + }
> + def v8i16 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "16"), v8i16, OpNode> {
> + let Inst{21-20} = 0b01; // imm6 = 01xxxx
> + }
> + def v4i32 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
> + OpcodeStr, !strconcat(Dt, "32"), v4i32, OpNode> {
> + let Inst{21} = 0b1; // imm6 = 1xxxxx
> + }
> + def v2i64 : N2VQSh<op24, op23, op11_8, 1, op4, itin,
> + OpcodeStr, !strconcat(Dt, "64"), v2i64, OpNode>;
> + // imm6 = xxxxxx
> +}
> +}
>
> // Neon Shift-Accumulate vector operations,
> // element sizes of 8, 16, 32 and 64 bits:
> @@ -1699,6 +1949,47 @@
> // imm6 = xxxxxx
> }
>
> +// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation
> +// of the shift amount. This helps the disassembler.
> +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in {
> +multiclass N2VShIns_QHSD2<bit op24, bit op23, bits<4> op11_8, bit op4,
> + string OpcodeStr, SDNode ShOp> {
> + // 64-bit vector types.
> + def v8i8 : N2VDShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "8", v8i8, ShOp> {
> + let Inst{21-19} = 0b001; // imm6 = 001xxx
> + }
> + def v4i16 : N2VDShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "16", v4i16, ShOp> {
> + let Inst{21-20} = 0b01; // imm6 = 01xxxx
> + }
> + def v2i32 : N2VDShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "32", v2i32, ShOp> {
> + let Inst{21} = 0b1; // imm6 = 1xxxxx
> + }
> + def v1i64 : N2VDShIns<op24, op23, op11_8, 1, op4,
> + OpcodeStr, "64", v1i64, ShOp>;
> + // imm6 = xxxxxx
> +
> + // 128-bit vector types.
> + def v16i8 : N2VQShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "8", v16i8, ShOp> {
> + let Inst{21-19} = 0b001; // imm6 = 001xxx
> + }
> + def v8i16 : N2VQShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "16", v8i16, ShOp> {
> + let Inst{21-20} = 0b01; // imm6 = 01xxxx
> + }
> + def v4i32 : N2VQShIns<op24, op23, op11_8, 0, op4,
> + OpcodeStr, "32", v4i32, ShOp> {
> + let Inst{21} = 0b1; // imm6 = 1xxxxx
> + }
> + def v2i64 : N2VQShIns<op24, op23, op11_8, 1, op4,
> + OpcodeStr, "64", v2i64, ShOp>;
> + // imm6 = xxxxxx
> +}
> +}
> +
> // Neon Shift Long operations,
> // element sizes of 8, 16, 32 bits:
> multiclass N2VLSh_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6,
> @@ -2329,18 +2620,21 @@
> // Vector Shifts.
>
> // VSHL : Vector Shift
> -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
> - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>;
> -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
> - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>;
> +defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
> + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>;
> +defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
> + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>;
> // VSHL : Vector Shift Left (Immediate)
> -defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> +defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>;
> // VSHR : Vector Shift Right (Immediate)
> defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>;
> defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>;
>
> // VSHLL : Vector Shift Left Long
> +// (disassembly note: this has a different interpretation of the shift amont)
> defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>;
>
> // VSHLL : Vector Shift Left Long (with maximum shift count)
> @@ -2350,6 +2644,8 @@
> : N2VLSh<op24, op23, op11_8, op7, op6, op4, OpcodeStr, Dt,
> ResTy, OpTy, OpNode> {
> let Inst{21-16} = op21_16;
> + let NSF = NVdVmImmVSHLLFrm; // For disassembly.
> + let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly.
> }
> def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8",
> v8i16, v8i8, NEONvshlli>;
> @@ -2363,10 +2659,10 @@
> NEONvshrn>;
>
> // VRSHL : Vector Rounding Shift
> -defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>;
> -defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>;
> +defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>;
> +defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>;
> // VRSHR : Vector Rounding Shift Right
> defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>;
> defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>;
> @@ -2376,15 +2672,18 @@
> NEONvrshrn>;
>
> // VQSHL : Vector Saturating Shift
> -defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>;
> -defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>;
> +defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>;
> +defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>;
> // VQSHL : Vector Saturating Shift Left (Immediate)
> -defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>;
> -defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> +defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> +defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>;
> // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned)
> -defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> +defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>;
>
> // VQSHRN : Vector Saturating Shift Right and Narrow
> defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s",
> @@ -2397,12 +2696,12 @@
> NEONvqshrnsu>;
>
> // VQRSHL : Vector Saturating Rounding Shift
> -defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vqrshl", "s",
> - int_arm_neon_vqrshifts, 0>;
> -defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> - IIC_VSHLi4Q, "vqrshl", "u",
> - int_arm_neon_vqrshiftu, 0>;
> +defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q, "vqrshl", "s",
> + int_arm_neon_vqrshifts, 0>;
> +defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
> + IIC_VSHLi4Q, "vqrshl", "u",
> + int_arm_neon_vqrshiftu, 0>;
>
> // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow
> defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s",
> @@ -2422,7 +2721,8 @@
> defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>;
>
> // VSLI : Vector Shift Left and Insert
> -defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>;
> +// (disassembly note: this has a different interpretation of the shift amont)
> +defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>;
> // VSRI : Vector Shift Right and Insert
> defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>;
>
> @@ -2518,10 +2818,13 @@
>
> // VMOV : Vector Move (Register)
>
> +// Mark these instructions as 2-register instructions to help the disassembler.
> +let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in {
> def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src),
> IIC_VMOVD, "vmov", "$dst, $src", "", []>;
> def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src),
> IIC_VMOVD, "vmov", "$dst, $src", "", []>;
> +}
>
> // VMOV : Vector Move (Immediate)
>
> @@ -2762,6 +3065,7 @@
>
> // VDUP : Vector Duplicate Lane (from scalar to all elements)
>
> +let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in {
> class VDUPLND<bits<2> op19_18, bits<2> op17_16,
> string OpcodeStr, string Dt, ValueType Ty>
> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0,
> @@ -2775,6 +3079,7 @@
> (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD,
> OpcodeStr, Dt, "$dst, $src[$lane]", "",
> [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>;
> +}
>
> // Inst{19-16} is partially specified depending on the element size.
>
> @@ -2843,24 +3148,37 @@
>
> // Vector Conversions.
>
> +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in {
> +class N2VDX<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18,
> + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr,
> + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode>
> + : N2VD<op24_23, op21_20, op19_18, op17_16, op11_7, op4, OpcodeStr, Dt,
> + ResTy, OpTy, OpNode>;
> +class N2VQX<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18,
> + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr,
> + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode>
> + : N2VQ<op24_23, op21_20, op19_18, op17_16, op11_7, op4, OpcodeStr, Dt,
> + ResTy, OpTy, OpNode>;
> +}
> +
> // VCVT : Vector Convert Between Floating-Point and Integers
> -def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
> - v2i32, v2f32, fp_to_sint>;
> -def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
> - v2i32, v2f32, fp_to_uint>;
> -def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
> - v2f32, v2i32, sint_to_fp>;
> -def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
> - v2f32, v2i32, uint_to_fp>;
> -
> -def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
> - v4i32, v4f32, fp_to_sint>;
> -def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
> - v4i32, v4f32, fp_to_uint>;
> -def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
> - v4f32, v4i32, sint_to_fp>;
> -def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
> - v4f32, v4i32, uint_to_fp>;
> +def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
> + v2i32, v2f32, fp_to_sint>;
> +def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
> + v2i32, v2f32, fp_to_uint>;
> +def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
> + v2f32, v2i32, sint_to_fp>;
> +def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
> + v2f32, v2i32, uint_to_fp>;
> +
> +def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
> + v4i32, v4f32, fp_to_sint>;
> +def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
> + v4i32, v4f32, fp_to_uint>;
> +def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
> + v4f32, v4i32, sint_to_fp>;
> +def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
> + v4f32, v4i32, uint_to_fp>;
>
> // VCVT : Vector Convert Between Floating-Point and Fixed-Point.
> def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32",
> @@ -2945,6 +3263,8 @@
>
> // VEXT : Vector Extract
>
> +let NSF = NVdVnVmImmVectorExtractFrm,
> + NSForm = NVdVnVmImmVectorExtractFrm.Value in {
> class VEXTd<string OpcodeStr, string Dt, ValueType Ty>
> : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst),
> (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD,
> @@ -2958,6 +3278,7 @@
> OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "",
> [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs),
> (Ty QPR:$rhs), imm:$index)))]>;
> +}
>
> def VEXTd8 : VEXTd<"vext", "8", v8i8>;
> def VEXTd16 : VEXTd<"vext", "16", v4i16>;
> @@ -3001,6 +3322,8 @@
>
> // Vector Table Lookup and Table Extension.
>
> +let NSF = VTBLFrm, NSForm = VTBLFrm.Value in {
> +
> // VTBL : Vector Table Lookup
> def VTBL1
> : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst),
> @@ -3057,6 +3380,8 @@
> DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>;
> } // hasExtraSrcRegAllocReq = 1
>
> +} // End of "let NSF = VTBLFrm, ..."
> +
> //===----------------------------------------------------------------------===//
> // NEON instructions for single-precision FP math
> //===----------------------------------------------------------------------===//
>
> Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 11:36:54 2010
> @@ -120,7 +120,7 @@
> void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum);
> void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum);
> void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum);
> - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {}
> + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum);
> void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum);
>
> void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {}
> @@ -431,16 +431,16 @@
> O << "[" << getRegisterName(MO1.getReg());
>
> if (!MO2.getReg()) {
> - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
> + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
> O << ", #"
> - << (char)ARM_AM::getAM2Op(MO3.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
> << ARM_AM::getAM2Offset(MO3.getImm());
> O << "]";
> return;
> }
>
> O << ", "
> - << (char)ARM_AM::getAM2Op(MO3.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
> << getRegisterName(MO2.getReg());
>
> if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
> @@ -458,12 +458,12 @@
> unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
> assert(ImmOffs && "Malformed indexed load / store!");
> O << "#"
> - << (char)ARM_AM::getAM2Op(MO2.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
> << ImmOffs;
> return;
> }
>
> - O << (char)ARM_AM::getAM2Op(MO2.getImm())
> + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
> << getRegisterName(MO1.getReg());
>
> if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
> @@ -490,7 +490,7 @@
>
> if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
> O << ", #"
> - << (char)ARM_AM::getAM3Op(MO3.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
> << ImmOffs;
> O << "]";
> }
> @@ -508,7 +508,7 @@
> unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
> assert(ImmOffs && "Malformed indexed load / store!");
> O << "#"
> - << (char)ARM_AM::getAM3Op(MO2.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm()))
> << ImmOffs;
> }
>
> @@ -558,7 +558,7 @@
>
> if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
> O << ", #"
> - << (char)ARM_AM::getAM5Op(MO2.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
> << ImmOffs*4;
> }
> O << "]";
> @@ -594,7 +594,7 @@
>
> const MachineOperand &MO1 = MI->getOperand(Op);
> assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
> - O << "[pc, +" << getRegisterName(MO1.getReg()) << "]";
> + O << "[pc, " << getRegisterName(MO1.getReg()) << "]";
> }
>
> void
> @@ -617,10 +617,11 @@
> ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) {
> // (3 - the number of trailing zeros) is the number of then / else.
> unsigned Mask = MI->getOperand(Op).getImm();
> + unsigned CondBit0 = Mask >> 4 & 1;
> unsigned NumTZ = CountTrailingZeros_32(Mask);
> assert(NumTZ <= 3 && "Invalid IT mask!");
> for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
> - bool T = (Mask & (1 << Pos)) == 0;
> + bool T = ((Mask >> Pos) & 1) == CondBit0;
> if (T)
> O << 't';
> else
> @@ -652,7 +653,7 @@
> if (MO3.getReg())
> O << ", " << getRegisterName(MO3.getReg());
> else if (unsigned ImmOffs = MO2.getImm())
> - O << ", #+" << ImmOffs * Scale;
> + O << ", #" << ImmOffs * Scale;
> O << "]";
> }
>
> @@ -674,7 +675,7 @@
> const MachineOperand &MO2 = MI->getOperand(Op+1);
> O << "[" << getRegisterName(MO1.getReg());
> if (unsigned ImmOffs = MO2.getImm())
> - O << ", #+" << ImmOffs*4;
> + O << ", #" << ImmOffs*4;
> O << "]";
> }
>
> @@ -710,7 +711,7 @@
>
> unsigned OffImm = MO2.getImm();
> if (OffImm) // Don't print +0.
> - O << ", #+" << OffImm;
> + O << ", #" << OffImm;
> O << "]";
> }
>
> @@ -726,7 +727,7 @@
> if (OffImm < 0)
> O << ", #-" << -OffImm;
> else if (OffImm > 0)
> - O << ", #+" << OffImm;
> + O << ", #" << OffImm;
> O << "]";
> }
>
> @@ -742,7 +743,7 @@
> if (OffImm < 0)
> O << ", #-" << -OffImm * 4;
> else if (OffImm > 0)
> - O << ", #+" << OffImm * 4;
> + O << ", #" << OffImm * 4;
> O << "]";
> }
>
> @@ -754,7 +755,18 @@
> if (OffImm < 0)
> O << "#-" << -OffImm;
> else if (OffImm > 0)
> - O << "#+" << OffImm;
> + O << "#" << OffImm;
> +}
> +
> +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI,
> + int OpNum) {
> + const MachineOperand &MO1 = MI->getOperand(OpNum);
> + int32_t OffImm = (int32_t)MO1.getImm() / 4;
> + // Don't print +0.
> + if (OffImm < 0)
> + O << "#-" << -OffImm * 4;
> + else if (OffImm > 0)
> + O << "#" << OffImm * 4;
> }
>
> void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
>
> Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 11:36:54 2010
> @@ -28,7 +28,165 @@
> #undef MachineInstr
> #undef ARMAsmPrinter
>
> -void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); }
> +static unsigned NextReg(unsigned Reg) {
> + switch (Reg) {
> + case ARM::D0:
> + return ARM::D1;
> + case ARM::D1:
> + return ARM::D2;
> + case ARM::D2:
> + return ARM::D3;
> + case ARM::D3:
> + return ARM::D4;
> + case ARM::D4:
> + return ARM::D5;
> + case ARM::D5:
> + return ARM::D6;
> + case ARM::D6:
> + return ARM::D7;
> + case ARM::D7:
> + return ARM::D8;
> + case ARM::D8:
> + return ARM::D9;
> + case ARM::D9:
> + return ARM::D10;
> + case ARM::D10:
> + return ARM::D11;
> + case ARM::D11:
> + return ARM::D12;
> + case ARM::D12:
> + return ARM::D13;
> + case ARM::D13:
> + return ARM::D14;
> + case ARM::D14:
> + return ARM::D15;
> + case ARM::D15:
> + return ARM::D16;
> + case ARM::D16:
> + return ARM::D17;
> + case ARM::D17:
> + return ARM::D18;
> + case ARM::D18:
> + return ARM::D19;
> + case ARM::D19:
> + return ARM::D20;
> + case ARM::D20:
> + return ARM::D21;
> + case ARM::D21:
> + return ARM::D22;
> + case ARM::D22:
> + return ARM::D23;
> + case ARM::D23:
> + return ARM::D24;
> + case ARM::D24:
> + return ARM::D25;
> + case ARM::D25:
> + return ARM::D26;
> + case ARM::D26:
> + return ARM::D27;
> + case ARM::D27:
> + return ARM::D28;
> + case ARM::D28:
> + return ARM::D29;
> + case ARM::D29:
> + return ARM::D30;
> + case ARM::D30:
> + return ARM::D31;
> +
> + default:
> + assert(0 && "Unexpected register enum");
> + }
> +}
> +
> +void ARMInstPrinter::printInst(const MCInst *MI) {
> + // Check for MOVs and print canonical forms, instead.
> + if (MI->getOpcode() == ARM::MOVs) {
> + const MCOperand &Dst = MI->getOperand(0);
> + const MCOperand &MO1 = MI->getOperand(1);
> + const MCOperand &MO2 = MI->getOperand(2);
> + const MCOperand &MO3 = MI->getOperand(3);
> +
> + O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm()));
> + printSBitModifierOperand(MI, 6);
> + printPredicateOperand(MI, 4);
> +
> + O << '\t' << getRegisterName(Dst.getReg())
> + << ", " << getRegisterName(MO1.getReg());
> +
> + if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx)
> + return;
> +
> + O << ", ";
> +
> + if (MO2.getReg()) {
> + O << getRegisterName(MO2.getReg());
> + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
> + } else {
> + O << "#" << ARM_AM::getSORegOffset(MO3.getImm());
> + }
> + return;
> + }
> +
> + // A8.6.123 PUSH
> + if ((MI->getOpcode() == ARM::STM || MI->getOpcode() == ARM::t2STM_UPD) &&
> + MI->getOperand(0).getReg() == ARM::SP) {
> + const unsigned IdxOffset = MI->getOpcode() == ARM::STM ? 0 : 1;
> + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1);
> + if (ARM_AM::getAM4WBFlag(MO1.getImm()) &&
> + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) {
> + O << '\t' << "push";
> + printPredicateOperand(MI, IdxOffset + 2);
> + O << '\t';
> + printRegisterList(MI, IdxOffset + 4);
> + return;
> + }
> + }
> +
> + // A8.6.122 POP
> + if ((MI->getOpcode() == ARM::LDM || MI->getOpcode() == ARM::t2LDM_UPD) &&
> + MI->getOperand(0).getReg() == ARM::SP) {
> + const unsigned IdxOffset = MI->getOpcode() == ARM::LDM ? 0 : 1;
> + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1);
> + if (ARM_AM::getAM4WBFlag(MO1.getImm()) &&
> + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) {
> + O << '\t' << "pop";
> + printPredicateOperand(MI, IdxOffset + 2);
> + O << '\t';
> + printRegisterList(MI, IdxOffset + 4);
> + return;
> + }
> + }
> +
> + // A8.6.355 VPUSH
> + if ((MI->getOpcode() == ARM::VSTMS || MI->getOpcode() == ARM::VSTMD) &&
> + MI->getOperand(0).getReg() == ARM::SP) {
> + const MCOperand &MO1 = MI->getOperand(1);
> + if (ARM_AM::getAM5WBFlag(MO1.getImm()) &&
> + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) {
> + O << '\t' << "vpush";
> + printPredicateOperand(MI, 2);
> + O << '\t';
> + printRegisterList(MI, 4);
> + return;
> + }
> + }
> +
> + // A8.6.354 VPOP
> + if ((MI->getOpcode() == ARM::VLDMS || MI->getOpcode() == ARM::VLDMD) &&
> + MI->getOperand(0).getReg() == ARM::SP) {
> + const MCOperand &MO1 = MI->getOperand(1);
> + if (ARM_AM::getAM5WBFlag(MO1.getImm()) &&
> + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) {
> + O << '\t' << "vpop";
> + printPredicateOperand(MI, 2);
> + O << '\t';
> + printRegisterList(MI, 4);
> + return;
> + }
> + }
> +
> + printInstruction(MI);
> + }
>
> void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
> const char *Modifier) {
> @@ -36,6 +194,9 @@
> if (Op.isReg()) {
> unsigned Reg = Op.getReg();
> if (Modifier && strcmp(Modifier, "dregpair") == 0) {
> + O << '{' << getRegisterName(Reg) << ", "
> + << getRegisterName(NextReg(Reg)) << '}';
> +#if 0
> // FIXME: Breaks e.g. ARM/vmul.ll.
> assert(0);
> /*
> @@ -44,6 +205,7 @@
> O << '{'
> << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi)
> << '}';*/
> +#endif
> } else if (Modifier && strcmp(Modifier, "lane") == 0) {
> assert(0);
> /*
> @@ -56,7 +218,9 @@
> O << getRegisterName(Reg);
> }
> } else if (Op.isImm()) {
> - assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
> + bool isCallOp = Modifier && !strcmp(Modifier, "call");
> + assert(isCallOp ||
> + ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"));
> O << '#' << Op.getImm();
> } else {
> assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
> @@ -142,17 +306,17 @@
> O << "[" << getRegisterName(MO1.getReg());
>
> if (!MO2.getReg()) {
> - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
> + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
> O << ", #"
> - << (char)ARM_AM::getAM2Op(MO3.getImm())
> - << ARM_AM::getAM2Offset(MO3.getImm());
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
> + << ARM_AM::getAM2Offset(MO3.getImm());
> O << "]";
> return;
> }
>
> O << ", "
> - << (char)ARM_AM::getAM2Op(MO3.getImm())
> - << getRegisterName(MO2.getReg());
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
> + << getRegisterName(MO2.getReg());
>
> if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
> O << ", "
> @@ -169,11 +333,14 @@
> if (!MO1.getReg()) {
> unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
> assert(ImmOffs && "Malformed indexed load / store!");
> - O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs;
> + O << '#'
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
> + << ImmOffs;
> return;
> }
>
> - O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg());
> + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
> + << getRegisterName(MO1.getReg());
>
> if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
> O << ", "
> @@ -196,8 +363,8 @@
>
> if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
> O << ", #"
> - << (char)ARM_AM::getAM3Op(MO3.getImm())
> - << ImmOffs;
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
> + << ImmOffs;
> O << ']';
> }
>
> @@ -214,9 +381,9 @@
>
> unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
> assert(ImmOffs && "Malformed indexed load / store!");
> - O << "#"
> - << (char)ARM_AM::getAM3Op(MO2.getImm())
> - << ImmOffs;
> + O << '#'
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm()))
> + << ImmOffs;
> }
>
>
> @@ -264,7 +431,7 @@
>
> if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
> O << ", #"
> - << (char)ARM_AM::getAM5Op(MO2.getImm())
> + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
> << ImmOffs*4;
> }
> O << "]";
> @@ -303,14 +470,56 @@
>
> void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) {
> O << "{";
> - // Always skip the first operand, it's the optional (and implicit writeback).
> - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) {
> - if (i != OpNum+1) O << ", ";
> + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) {
> + if (i != OpNum) O << ", ";
> O << getRegisterName(MI->getOperand(i).getReg());
> }
> O << "}";
> }
>
> +void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {
> + const MCOperand &Op = MI->getOperand(OpNum);
> + unsigned option = Op.getImm();
> + unsigned mode = option & 31;
> + bool changemode = option >> 5 & 1;
> + unsigned AIF = option >> 6 & 7;
> + unsigned imod = option >> 9 & 3;
> + if (imod == 2)
> + O << "ie";
> + else if (imod == 3)
> + O << "id";
> + O << '\t';
> + if (imod > 1) {
> + if (AIF & 4) O << 'a';
> + if (AIF & 2) O << 'i';
> + if (AIF & 1) O << 'f';
> + if (AIF > 0 && changemode) O << ", ";
> + }
> + if (changemode)
> + O << '#' << mode;
> +}
> +
> +void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {
> + const MCOperand &Op = MI->getOperand(OpNum);
> + unsigned Mask = Op.getImm();
> + if (Mask) {
> + O << '_';
> + if (Mask & 8) O << 'f';
> + if (Mask & 4) O << 's';
> + if (Mask & 2) O << 'x';
> + if (Mask & 1) O << 'c';
> + }
> +}
> +
> +void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){
> + const MCOperand &Op = MI->getOperand(OpNum);
> + O << '#';
> + if (Op.getImm() < 0)
> + O << '-' << (-Op.getImm() - 1);
> + else
> + O << Op.getImm();
> +}
> +
> void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) {
> ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
> if (CC != ARMCC::AL)
> @@ -352,3 +561,191 @@
> void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) {
> O << "#" << MI->getOperand(OpNum).getImm() * 4;
> }
> +
> +void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) {
> + // (3 - the number of trailing zeros) is the number of then / else.
> + unsigned Mask = MI->getOperand(OpNum).getImm();
> + unsigned CondBit0 = Mask >> 4 & 1;
> + unsigned NumTZ = CountTrailingZeros_32(Mask);
> + assert(NumTZ <= 3 && "Invalid IT mask!");
> + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
> + bool T = ((Mask >> Pos) & 1) == CondBit0;
> + if (T)
> + O << 't';
> + else
> + O << 'e';
> + }
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op)
> +{
> + const MCOperand &MO1 = MI->getOperand(Op);
> + const MCOperand &MO2 = MI->getOperand(Op+1);
> + O << "[" << getRegisterName(MO1.getReg());
> + O << ", " << getRegisterName(MO2.getReg()) << "]";
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op,
> + unsigned Scale) {
> + const MCOperand &MO1 = MI->getOperand(Op);
> + const MCOperand &MO2 = MI->getOperand(Op+1);
> + const MCOperand &MO3 = MI->getOperand(Op+2);
> +
> + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
> + printOperand(MI, Op);
> + return;
> + }
> +
> + O << "[" << getRegisterName(MO1.getReg());
> + if (MO3.getReg())
> + O << ", " << getRegisterName(MO3.getReg());
> + else if (unsigned ImmOffs = MO2.getImm())
> + O << ", #" << ImmOffs * Scale;
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op)
> +{
> + printThumbAddrModeRI5Operand(MI, Op, 1);
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op)
> +{
> + printThumbAddrModeRI5Operand(MI, Op, 2);
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op)
> +{
> + printThumbAddrModeRI5Operand(MI, Op, 4);
> +}
> +
> +void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) {
> + const MCOperand &MO1 = MI->getOperand(Op);
> + const MCOperand &MO2 = MI->getOperand(Op+1);
> + O << "[" << getRegisterName(MO1.getReg());
> + if (unsigned ImmOffs = MO2.getImm())
> + O << ", #" << ImmOffs*4;
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) {
> + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg());
> + if (MI->getOpcode() == ARM::t2TBH)
> + O << ", lsl #1";
> + O << ']';
> +}
> +
> +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2
> +// register with shift forms.
> +// REG 0 0 - e.g. R5
> +// REG IMM, SH_OPC - e.g. R5, LSL #3
> +void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + const MCOperand &MO2 = MI->getOperand(OpNum+1);
> +
> + unsigned Reg = MO1.getReg();
> + O << getRegisterName(Reg);
> +
> + // Print the shift opc.
> + O << ", "
> + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm()))
> + << " ";
> +
> + assert(MO2.isImm() && "Not a valid t2_so_reg value!");
> + O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
> +}
> +
> +void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + const MCOperand &MO2 = MI->getOperand(OpNum+1);
> +
> + O << "[" << getRegisterName(MO1.getReg());
> +
> + unsigned OffImm = MO2.getImm();
> + if (OffImm) // Don't print +0.
> + O << ", #" << OffImm;
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + const MCOperand &MO2 = MI->getOperand(OpNum+1);
> +
> + O << "[" << getRegisterName(MO1.getReg());
> +
> + int32_t OffImm = (int32_t)MO2.getImm();
> + // Don't print +0.
> + if (OffImm < 0)
> + O << ", #-" << -OffImm;
> + else if (OffImm > 0)
> + O << ", #" << OffImm;
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + const MCOperand &MO2 = MI->getOperand(OpNum+1);
> +
> + O << "[" << getRegisterName(MO1.getReg());
> +
> + int32_t OffImm = (int32_t)MO2.getImm() / 4;
> + // Don't print +0.
> + if (OffImm < 0)
> + O << ", #-" << -OffImm * 4;
> + else if (OffImm > 0)
> + O << ", #" << OffImm * 4;
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + int32_t OffImm = (int32_t)MO1.getImm();
> + // Don't print +0.
> + if (OffImm < 0)
> + O << "#-" << -OffImm;
> + else if (OffImm > 0)
> + O << "#" << OffImm;
> +}
> +
> +void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + int32_t OffImm = (int32_t)MO1.getImm() / 4;
> + // Don't print +0.
> + if (OffImm < 0)
> + O << "#-" << -OffImm * 4;
> + else if (OffImm > 0)
> + O << "#" << OffImm * 4;
> +}
> +
> +void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI,
> + unsigned OpNum) {
> + const MCOperand &MO1 = MI->getOperand(OpNum);
> + const MCOperand &MO2 = MI->getOperand(OpNum+1);
> + const MCOperand &MO3 = MI->getOperand(OpNum+2);
> +
> + O << "[" << getRegisterName(MO1.getReg());
> +
> + assert(MO2.getReg() && "Invalid so_reg load / store address!");
> + O << ", " << getRegisterName(MO2.getReg());
> +
> + unsigned ShAmt = MO3.getImm();
> + if (ShAmt) {
> + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!");
> + O << ", lsl #" << ShAmt;
> + }
> + O << "]";
> +}
> +
> +void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) {
> + O << '#' << MI->getOperand(OpNum).getImm();
> +}
> +
> +void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) {
> + O << '#' << MI->getOperand(OpNum).getImm();
> +}
> +
>
> Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original)
> +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Tue Mar 16 11:36:54 2010
> @@ -54,26 +54,26 @@
> void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum);
>
> void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum);
> - void printThumbITMask(const MCInst *MI, unsigned OpNum) {}
> - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {}
> + void printThumbITMask(const MCInst *MI, unsigned OpNum);
> + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum);
> void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum,
> - unsigned Scale) {}
> - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {}
> - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {}
> - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {}
> - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {}
> + unsigned Scale);
> + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum);
> + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum);
> + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum);
> + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum);
>
> - void printT2SOOperand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {}
> - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {}
> + void printT2SOOperand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum);
> + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum);
>
> - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {}
> - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {}
> - void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {}
> + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum);
> + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum);
> + void printNegZeroOperand(const MCInst *MI, unsigned OpNum);
> void printPredicateOperand(const MCInst *MI, unsigned OpNum);
> void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum);
> void printSBitModifierOperand(const MCInst *MI, unsigned OpNum);
> @@ -82,10 +82,10 @@
> const char *Modifier);
> void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {}
> void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {}
> - void printTBAddrMode(const MCInst *MI, unsigned OpNum) {}
> + void printTBAddrMode(const MCInst *MI, unsigned OpNum);
> void printNoHashImmediate(const MCInst *MI, unsigned OpNum);
> - void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {}
> - void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {}
> + void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum);
> + void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum);
> void printHex8ImmOperand(const MCInst *MI, int OpNum) {}
> void printHex16ImmOperand(const MCInst *MI, int OpNum) {}
> void printHex32ImmOperand(const MCInst *MI, int OpNum) {}
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,513 @@
> +//===- ARMDisassembler.cpp - Disassembler for ARM/Thumb ISA ----*- 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 translate the data produced by the decoder into MCInsts.
> +// Documentation for the disassembler can be found in ARMDisassembler.h.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#define DEBUG_TYPE "arm-disassembler"
> +
> +#include "ARMDisassembler.h"
> +#include "ARMDisassemblerCore.h"
> +
> +#include "llvm/MC/MCInst.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"
> +
> +/// ARMDisassemblerTables.inc - ARMDisassemblerTables.inc is tblgen'ed from
> +/// RISCDisassemblerEmitter.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 "../ARMGenDisassemblerTables.inc"
> +
> +namespace llvm {
> +
> +namespace ARMDisassembler {
> +
> +/// showBitVector - Use the raw_ostream to log a diagnostic message describing
> +/// the inidividual bits of the instruction. This is a sample output:
> +///
> +/// 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: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0|
> +/// -------------------------------------------------------------------------------------------------
> +///
> +static inline void showBitVector(raw_ostream &os, const uint32_t &insn) {
> + 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';
> + 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 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 slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr;
> +
> + // 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 ARM::STRHT;
> + default:
> + break; // fallthrough
> + }
> + break;
> + case 3:
> + switch (slice(insn, 7, 4)) {
> + case 11:
> + return ARM::LDRHT;
> + case 13:
> + return ARM::LDRSBT;
> + case 15:
> + return ARM::LDRSHT;
> + default:
> + break; // fallthrough
> + }
> + break;
> + default:
> + break; // fallthrough
> + }
> + }
> +
> + // 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
> + }
> + 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
> + }
> + 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
> + }
> + break;
> + default:
> + break; // fallthrough
> + }
> + }
> +
> + // 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
> + }
> + 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
> + }
> + 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
> + }
> + break;
> + default:
> + break; // fallthrough
> + }
> + }
> +
> +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 passing it on.
> +static unsigned T2Morph2LoadLiteral(unsigned Opcode) {
> + switch (Opcode) {
> + default:
> + return Opcode; // Return unmorphed opcode.
> +
> + case ARM::t2LDRDi8:
> + return ARM::t2LDRDpci;
> +
> + case ARM::t2LDR_POST: case ARM::t2LDR_PRE:
> + case ARM::t2LDRi12: case ARM::t2LDRi8:
> + case ARM::t2LDRs:
> + return ARM::t2LDRpci;
> +
> + case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE:
> + case ARM::t2LDRBi12: case ARM::t2LDRBi8:
> + case ARM::t2LDRBs:
> + return ARM::t2LDRBpci;
> +
> + case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE:
> + case ARM::t2LDRHi12: case ARM::t2LDRHi8:
> + case ARM::t2LDRHs:
> + return ARM::t2LDRHpci;
> +
> + case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE:
> + case ARM::t2LDRSBi12: case ARM::t2LDRSBi8:
> + case ARM::t2LDRSBs:
> + return ARM::t2LDRSBpci;
> +
> + case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE:
> + case ARM::t2LDRSHi12: case ARM::t2LDRSHi8:
> + case ARM::t2LDRSHs:
> + return ARM::t2LDRSHpci;
> + }
> +}
> +
> +/// 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, uint32_t &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);
> + }
> +
> + 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);
> + }
> + // --------- Transform End Marker ---------
> +
> + // 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 passing it on to our delegate.
> + if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1
> + && slice(insn, 19, 16) == 15)
> + return T2Morph2LoadLiteral(decodeThumbInstruction(insn));
> +
> + // One last check for NEON/VFP instructions.
> + if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1)
> + return decodeInstruction(insn);
> +
> + // Fall through.
> + }
> +
> + return decodeThumbInstruction(insn);
> +}
> +
> +static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) {
> + switch (Opcode) {
> + default:
> + return false;
> + case ARM::t2PLDi12: case ARM::t2PLDi8:
> + case ARM::t2PLDr: case ARM::t2PLDs:
> + case ARM::t2PLDWi12: case ARM::t2PLDWi8:
> + case ARM::t2PLDWr: case ARM::t2PLDWs:
> + case ARM::t2PLIi12: case ARM::t2PLIi8:
> + case ARM::t2PLIr: case ARM::t2PLIs:
> + return true;
> + }
> +}
> +
> +static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) {
> + switch (Opcode) {
> + default:
> + return 0;
> + case ARM::t2PLDi12: case ARM::t2PLDi8:
> + case ARM::t2PLDr: case ARM::t2PLDs:
> + return ARM::t2PLDpci;
> + case ARM::t2PLDWi12: case ARM::t2PLDWi8:
> + case ARM::t2PLDWr: case ARM::t2PLDWs:
> + return ARM::t2PLDWpci;
> + case ARM::t2PLIi12: case ARM::t2PLIi8:
> + case ARM::t2PLIr: case ARM::t2PLIs:
> + return ARM::t2PLIpci;
> + }
> +}
> +
> +//
> +// Public interface for the disassembler
> +//
> +
> +bool ARMDisassembler::getInstruction(MCInst &MI,
> + uint64_t &Size,
> + const MemoryObject &Region,
> + uint64_t Address,
> + raw_ostream &os) const {
> + // The machine instruction.
> + uint32_t insn;
> +
> + // We want to read exactly 4 bytes of data.
> + if (Region.readBytes(Address, 4, (uint8_t*)&insn, NULL) == -1)
> + return false;
> +
> + unsigned Opcode = decodeARMInstruction(insn);
> + ARMFormat Format = ARMFormats[Opcode];
> + NSFormat NSF = NSFormats[Opcode];
> + Size = 4;
> +
> + DEBUG({
> + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode)
> + << " Format=" << stringForARMFormat(Format) << " NSFormat="
> + << stringForNSFormat(NSF) << '\n';
> + showBitVector(errs(), insn);
> + });
> +
> + AbstractARMMCBuilder *Builder =
> + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF);
> +
> + if (!Builder)
> + return false;
> +
> + if (!Builder->Build(MI, insn))
> + return false;
> +
> + delete Builder;
> +
> + return true;
> +}
> +
> +bool ThumbDisassembler::getInstruction(MCInst &MI,
> + uint64_t &Size,
> + const MemoryObject &Region,
> + uint64_t Address,
> + raw_ostream &os) const {
> + // The machine instruction.
> + uint32_t insn = 0;
> + uint32_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.
> + if (Region.readBytes(Address, 2, (uint8_t*)&insn, NULL) == -1)
> + return false;
> +
> + unsigned bits15_11 = slice(insn, 15, 11);
> + bool IsThumb2 = false;
> +
> + // 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*)&insn1, NULL) == -1)
> + return false;
> + 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);
> +
> + // A8.6.117/119/120/121.
> + // PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant.
> + if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15)
> + Opcode = T2Morph2Preload2PCI(Opcode);
> +
> + ARMFormat Format = ARMFormats[Opcode];
> + NSFormat NSF = NSFormats[Opcode];
> + Size = IsThumb2 ? 4 : 2;
> +
> + DEBUG({
> + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode)
> + << " Format=" << stringForARMFormat(Format) << " NSFormat="
> + << stringForNSFormat(NSF) << '\n';
> + showBitVector(errs(), insn);
> + });
> +
> + AbstractARMMCBuilder *Builder =
> + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF);
> +
> + if (!Builder)
> + return false;
> +
> + if (!Builder->Build(MI, insn))
> + return false;
> +
> + delete Builder;
> +
> + return true;
> +}
> +
> +} // namespace ARM Disassembler
> +
> +static const MCDisassembler *createARMDisassembler(const Target &T) {
> + return new ARMDisassembler::ARMDisassembler;
> +}
> +
> +static const MCDisassembler *createThumbDisassembler(const Target &T) {
> + return new ARMDisassembler::ThumbDisassembler;
> +}
> +
> +extern "C" void LLVMInitializeARMDisassembler() {
> + // Register the disassembler.
> + TargetRegistry::RegisterMCDisassembler(TheARMTarget,
> + createARMDisassembler);
> + TargetRegistry::RegisterMCDisassembler(TheThumbTarget,
> + createThumbDisassembler);
> +}
> +
> +} // namespace llvm
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,71 @@
> +//===- X86Disassembler.h - Disassembler for x86 and x86_64 ------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef ARMDISASSEMBLER_H
> +#define ARMDISASSEMBLER_H
> +
> +#include "llvm/MC/MCDisassembler.h"
> +
> +namespace llvm {
> +
> +class MCInst;
> +class MemoryObject;
> +class raw_ostream;
> +
> +namespace ARMDisassembler {
> +
> +/// ARMDisassembler - ARM disassembler for all ARM platforms.
> +class ARMDisassembler : public MCDisassembler {
> +public:
> + /// Constructor - Initializes the disassembler.
> + ///
> + ARMDisassembler() :
> + MCDisassembler() {
> + }
> +
> + ~ARMDisassembler() {
> + }
> +
> + /// getInstruction - See MCDisassembler.
> + bool getInstruction(MCInst &instr,
> + uint64_t &size,
> + const MemoryObject ®ion,
> + uint64_t address,
> + raw_ostream &vStream) const;
> +private:
> +};
> +
> +/// ThumbDisassembler - Thumb disassembler for all ARM platforms.
> +class ThumbDisassembler : public MCDisassembler {
> +public:
> + /// Constructor - Initializes the disassembler.
> + ///
> + ThumbDisassembler() :
> + MCDisassembler() {
> + }
> +
> + ~ThumbDisassembler() {
> + }
> +
> + /// getInstruction - See MCDisassembler.
> + bool getInstruction(MCInst &instr,
> + uint64_t &size,
> + const MemoryObject ®ion,
> + uint64_t address,
> + raw_ostream &vStream) const;
> +private:
> +};
> +
> +} // namespace ARMDisassembler
> +
> +} // namespace llvm
> +
> +#endif
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,3351 @@
> +//===- 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, Builder Factory,
> +// as well as the Algorithm to solve the problem of disassembling an ARM instr.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ARMAddressingModes.h"
> +#include "ARMDisassemblerCore.h"
> +#include <map>
> +
> +/// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const
> +/// TargetInstrDesc ARMInsts[] definition and the TargetOperandInfo[]'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 TargetOperandInfo[] of:
> +///
> +/// { 0, 0|(1<<TOI::Predicate), 0 },
> +/// { ARM::CCRRegClassID, 0|(1<<TOI::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 TargetOperandInfo of:
> +///
> +/// { ARM::CCRRegClassID, 0|(1<<TOI::OptionalDef), 0 }
> +///
> +/// And this maps to one MCOperand with the regsiter kind of ARM::CPSR.
> +#include "ARMGenInstrInfo.inc"
> +
> +using namespace llvm;
> +
> +const char *ARMUtils::OpcodeName(unsigned Opcode) {
> + return ARMInsts[Opcode].Name;
> +}
> +
> +// There is a more efficient way than the following. It is fragile, though.
> +// See the code snippet after this function.
> +static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister,
> + bool DRegPair = false) {
> +
> + if (DRegPair && RegClassID == ARM::QPRRegClassID) {
> + // LLVM expects { Dd, Dd+1 } to form a super register; this is not specified
> + // in the ARM Architecture Manual as far as I understand it (A8.6.307).
> + // Therefore, we morph the RegClassID to be the sub register class and don't
> + // subsequently transform the RawRegister encoding when calculating RegNum.
> + //
> + // See also ARMinstPrinter::printOperand() wrt "dregpair" modifier part
> + // where this workaround is meant for.
> + RegClassID = ARM::DPRRegClassID;
> + }
> +
> + // See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm().
> + 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;
> + }
> + llvm_unreachable("Invalid (RegClassID, RawRegister) combination");
> +}
> +
> +// This is efficient but fragile.
> +/*
> +// See ARMGenRegisterInfo.h.inc for more info.
> +static const TargetRegisterClass* const ARMRegisterClasses[] = {
> + NULL,
> + &ARM::CCRRegClass, // CCRRegClassID = 1,
> + &ARM::DPRRegClass, // DPRRegClassID = 2,
> + &ARM::DPR_8RegClass, // DPR_8RegClassID = 3,
> + &ARM::DPR_VFP2RegClass, // DPR_VFP2RegClassID = 4,
> + &ARM::GPRRegClass, // GPRRegClassID = 5,
> + &ARM::QPRRegClass, // QPRRegClassID = 6,
> + &ARM::QPR_8RegClass, // QPR_8RegClassID = 7,
> + &ARM::QPR_VFP2RegClass, // QPR_VFP2RegClassID = 8,
> + &ARM::SPRRegClass, // SPRRegClassID = 9,
> + &ARM::SPR_8RegClass, // SPR_8RegClassID = 10,
> + &ARM::SPR_INVALIDRegClass, // SPR_INVALIDRegClassID = 11,
> + &ARM::tGPRRegClass, // tGPRRegClassID = 12
> +};
> +
> +// Return the register enum given register class id and raw register value.
> +static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister) {
> + assert(RegClassID < array_lengthof(ARMRegisterClasses) &&
> + "Register Class ID out of range");
> + return ARMRegisterClasses[RegClassID]->getRegister(RawRegister);
> +}
> +*/
> +
> +/// 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);
> +
> +///////////////////////////////
> +// //
> +// 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;
> +}
> +
> +namespace {
> +// Sign extend 5 bit number x to r.
> +// Usage: int r = signextend<signed int, 5>(x);
> +template <typename T, unsigned B> inline T signextend(const T x) {
> + struct {T x:B;} s;
> + return s.x = x;
> +}
> +}
> +
> +// 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.
> +//
> +// A8-12: DecodeRegShift()
> +static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) {
> + switch (bits) {
> + default: assert(0 && "No such value");
> + 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 type == 0b11 and imm5 == 0, we have an rrx, instead.
> + if (ShOp == ARM_AM::ror && ShImm == 0)
> + ShOp = ARM_AM::rrx;
> + // If (lsr or asr) and imm5 == 0, shift amount is 32.
> + if ((ShOp == ARM_AM::lsr || ShOp == ARM_AM::asr) && ShImm == 0)
> + ShImm = 32;
> +}
> +
> +// getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding
> +// bits Inst{24-23} (P(24) and U(23)) into llvm enums for AMSubMode.
> +static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) {
> + switch (bits) {
> + default: assert(0 && "No such value");
> + 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 class method named
> +/// TryPredicateAndSBitModifier.
> +
> +static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + if (Opcode == ARM::Int_MemBarrierV7 || Opcode == ARM::Int_SyncBarrierV7)
> + return true;
> +
> + assert(0 && "Unexpected pseudo instruction!");
> + return false;
> +}
> +
> +// Multiply Instructions.
> +// MLA, MLS, SMLABB, SMLABT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMMLA, SMMLS:
> +// Rd{19-16} Rn{3-0} Rm{11-8} Ra{15-12}
> +//
> +// MUL, SMMUL, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, SMULWT:
> +// Rd{19-16} Rn{3-0} Rm{11-8}
> +//
> +// SMLAL, SMULL, UMAAL, UMLAL, UMULL, SMLALBB, SMLALBT, SMLALTB, SMLALTT:
> +// 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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + const TargetOperandInfo *OpInfo = TID.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);
> +
> + // Instructions with two destination registers have RdLo{15-12} first.
> + if (NumDefs == 2) {
> + assert(NumOps >= 4 && OpInfo[3].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> + }
> +
> + // The destination register: RdHi{19-16} or Rd{19-16}.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + // The two src regsiters: Rn{3-0}, then Rm{11-8}.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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(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) {
> +
> + assert(NumOps >= 5);
> +
> + unsigned &OpIdx = NumOpsAdded;
> + 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);
> +
> + OpIdx = 0;
> +
> + MI.addOperand(MCOperand::CreateImm(GetCoprocessor(insn)));
> +
> + 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(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + if (PW) {
> + MI.addOperand(MCOperand::CreateReg(0));
> + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
> + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, slice(insn, 7, 0) << 2,
> + ARM_AM::no_shift);
> + MI.addOperand(MCOperand::CreateImm(Offset));
> + OpIdx = 5;
> + } else {
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 0)));
> + OpIdx = 4;
> + }
> + } else {
> + MI.addOperand(MCOperand::CreateImm(OneCopOpc ? GetCopOpc(insn)
> + : GetCopOpc1(insn, NoGPR)));
> +
> + MI.addOperand(NoGPR ? MCOperand::CreateImm(decodeRd(insn))
> + : MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> +
> + MI.addOperand(OneCopOpc ? MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn)))
> + : MCOperand::CreateImm(decodeRn(insn)));
> +
> + MI.addOperand(MCOperand::CreateImm(decodeRm(insn)));
> +
> + OpIdx = 5;
> +
> + if (!OneCopOpc) {
> + MI.addOperand(MCOperand::CreateImm(GetCopOpc2(insn)));
> + ++OpIdx;
> + }
> + }
> +
> + return true;
> +}
> +
> +// Branch Instructions.
> +// BLr9: SignExtend(Imm24:'00', 32)
> +// Bcc, BLr9_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
> +// SRSW/SRS: addrmode4:$addr mode_imm
> +// RFEW/RFE: addrmode4:$addr Rn
> +static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + if (CoprocessorOpcode(Opcode))
> + return DisassembleCoprocessor(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + // MRS and MRSsys take one GPR reg Rd.
> + if (Opcode == ARM::MRS || Opcode == ARM::MRSsys) {
> + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + NumOpsAdded = 1;
> + return true;
> + }
> + // MSR and MSRsys take one GPR reg Rm, followed by the mask.
> + if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) {
> + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16)));
> + NumOpsAdded = 2;
> + return true;
> + }
> + // MSRi and MSRsysi take one so_imm operand, followed by the mask.
> + if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) {
> + // 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)));
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16)));
> + NumOpsAdded = 2;
> + return true;
> + }
> + // SRSW and SRS requires addrmode4:$addr for ${addr:submode}, followed by the
> + // mode immediate (Inst{4-0}).
> + if (Opcode == ARM::SRSW || Opcode == ARM::SRS ||
> + Opcode == ARM::RFEW || Opcode == ARM::RFE) {
> + // ARMInstPrinter::printAddrMode4Operand() prints special mode string
> + // if the base register is SP; so don't set ARM::SP.
> + MI.addOperand(MCOperand::CreateReg(0));
> + bool WB = (Opcode == ARM::SRSW);
> + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn));
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB)));
> +
> + if (Opcode == ARM::SRSW || Opcode == ARM::SRS)
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));
> + else
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + NumOpsAdded = 3;
> + return true;
> + }
> +
> + assert(Opcode == ARM::Bcc || Opcode == ARM::BLr9 || Opcode == ARM::BLr9_pred
> + || Opcode == ARM::SMC || Opcode == ARM::SVC);
> +
> + assert(NumOps >= 1 && OpInfo[0].RegClass == 0);
> +
> + 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);
> +
> + // When executing an ARM instruction, PC reads as the address of the current
> + // instruction plus 8. The assembler subtracts 8 from the difference
> + // between the branch instruction and the target address, disassembler has
> + // to add 8 to compensate.
> + Imm32 += 8;
> + }
> +
> + MI.addOperand(MCOperand::CreateImm(Imm32));
> + NumOpsAdded = 1;
> +
> + return true;
> +}
> +
> +// Misc. Branch Instructions.
> +// BR_JTadd, BR_JTr, BR_JTm
> +// BLXr9, BXr9
> +// BRIND, BX_RET
> +static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + // BX_RET has only two predicate operands, do an early return.
> + if (Opcode == ARM::BX_RET)
> + return true;
> +
> + // BLXr9 and BRIND take one GPR reg.
> + if (Opcode == ARM::BLXr9 || Opcode == ARM::BRIND) {
> + assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + OpIdx = 1;
> + return true;
> + }
> +
> + // BR_JTadd is an ADD with Rd = PC, (Rn, Rm) as the target and index regs.
> + if (Opcode == ARM::BR_JTadd) {
> + // InOperandList with GPR:$target and GPR:$idx regs.
> +
> + assert(NumOps == 4);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> +
> + // Fill in the two remaining imm operands to signify build completion.
> + MI.addOperand(MCOperand::CreateImm(0));
> + MI.addOperand(MCOperand::CreateImm(0));
> +
> + OpIdx = 4;
> + return true;
> + }
> +
> + // BR_JTr is a MOV with Rd = PC, and Rm as the source register.
> + if (Opcode == ARM::BR_JTr) {
> + // InOperandList with GPR::$target reg.
> +
> + assert(NumOps == 3);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> +
> + // Fill in the two remaining imm operands to signify build completion.
> + MI.addOperand(MCOperand::CreateImm(0));
> + MI.addOperand(MCOperand::CreateImm(0));
> +
> + OpIdx = 3;
> + return true;
> + }
> +
> + // BR_JTm is an LDR with Rt = PC.
> + if (Opcode == ARM::BR_JTm) {
> + // This is the reg/reg form, with base reg followed by +/- reg shop imm.
> + // See also ARMAddressingModes.h (Addressing Mode #2).
> +
> + assert(NumOps == 5 && getIBit(insn) == 1);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
> +
> + // Disassemble the offset reg (Rm), shift type, and immediate shift length.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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)));
> +
> + // Fill in the two remaining imm operands to signify build completion.
> + MI.addOperand(MCOperand::CreateImm(0));
> + MI.addOperand(MCOperand::CreateImm(0));
> +
> + OpIdx = 5;
> + return true;
> + }
> +
> + assert(0 && "Unexpected BrMiscFrm Opcode");
> + return false;
> +}
> +
> +static inline uint32_t getBFCInvMask(uint32_t insn) {
> + uint32_t lsb = slice(insn, 11, 7);
> + uint32_t msb = slice(insn, 20, 16);
> + uint32_t Val = 0;
> + assert(lsb <= msb && "Encoding error: lsb > msb");
> + for (uint32_t i = lsb; i <= msb; ++i)
> + Val |= (1 << i);
> + return ~Val;
> +}
> +
> +static inline bool SaturateOpcode(unsigned Opcode) {
> + switch (Opcode) {
> + case ARM::SSATlsl: case ARM::SSATasr: case ARM::SSAT16:
> + case ARM::USATlsl: case ARM::USATasr: case ARM::USAT16:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +static inline unsigned decodeSaturatePos(unsigned Opcode, uint32_t insn) {
> + switch (Opcode) {
> + case ARM::SSATlsl:
> + case ARM::SSATasr:
> + return slice(insn, 20, 16) + 1;
> + case ARM::SSAT16:
> + return slice(insn, 19, 16) + 1;
> + case ARM::USATlsl:
> + case ARM::USATasr:
> + return slice(insn, 20, 16);
> + case ARM::USAT16:
> + return slice(insn, 19, 16);
> + default:
> + llvm_unreachable("Invalid opcode passed in");
> + return 0;
> + }
> +}
> +
> +// 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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + bool isUnary = isUnaryDP(TID.TSFlags);
> + const TargetOperandInfo *OpInfo = TID.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(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> + }
> +
> + // Now disassemble the src operands.
> + if (OpIdx >= NumOps)
> + return false;
> +
> + // SSAT/SSAT16/USAT/USAT16 has imm operand after Rd.
> + if (SaturateOpcode(Opcode)) {
> + MI.addOperand(MCOperand::CreateImm(decodeSaturatePos(Opcode, insn)));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> +
> + if (Opcode == ARM::SSAT16 || Opcode == ARM::USAT16) {
> + OpIdx += 2;
> + return true;
> + }
> +
> + // For SSAT operand reg (Rm) has been disassembled above.
> + // Now disassemble the shift amount.
> +
> + // Inst{11-7} encodes the imm5 shift amount.
> + unsigned ShAmt = slice(insn, 11, 7);
> +
> + // A8.6.183. Possible ASR shift amount of 32...
> + if (Opcode == ARM::SSATasr && ShAmt == 0)
> + ShAmt = 32;
> +
> + MI.addOperand(MCOperand::CreateImm(ShAmt));
> +
> + OpIdx += 3;
> + return true;
> + }
> +
> + // Special-case handling of BFC/BFI/SBFX/UBFX.
> + if (Opcode == ARM::BFC || Opcode == ARM::BFI) {
> + // TIED_TO operand skipped for BFC and Inst{3-0} (Reg) for BFI.
> + MI.addOperand(MCOperand::CreateReg(Opcode == ARM::BFC ? 0
> + : getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + MI.addOperand(MCOperand::CreateImm(getBFCInvMask(insn)));
> + OpIdx += 2;
> + return true;
> + }
> + if (Opcode == ARM::SBFX || Opcode == ARM::UBFX) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 7)));
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 16) + 1));
> + 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);
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + RmRn ? decodeRm(insn) : decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // If this is a two-address operand, skip it, e.g., MOVCCr operand 1.
> + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::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");
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + RmRn? decodeRn(insn) : decodeRm(insn))));
> + ++OpIdx;
> + } else if (Opcode == ARM::MOVi16 || Opcode == ARM::MOVTi16) {
> + // 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);
> + 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 DisassembleDPSoRegFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + bool isUnary = isUnaryDP(TID.TSFlags);
> + const TargetOperandInfo *OpInfo = TID.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(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);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // If this is a two-address operand, skip it, e.g., MOVCCs operand 1.
> + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::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));
> +
> + // Register-controlled shifts have Inst{7} = 0 and Inst{4} = 1.
> + unsigned Rs = slice(insn, 4, 4);
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + if (Rs) {
> + // Register-controlled shifts: [Rm, Rs, shift].
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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 DisassembleLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + bool isPrePost = isPrePostLdSt(TID.TSFlags);
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost)));
> +
> + // Operand 0 of a pre- and post-indexed store is the address base writeback.
> + if (isPrePost && isStore) {
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // Disassemble the dst/src operand.
> + if (OpIdx >= NumOps)
> + return false;
> +
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // Disassemble the base operand.
> + if (OpIdx >= NumOps)
> + return false;
> +
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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;
> +
> + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) &&
> + (OpInfo[OpIdx+1].RegClass == 0));
> +
> + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
> + if (getIBit(insn) == 0) {
> + MI.addOperand(MCOperand::CreateReg(0));
> +
> + // Disassemble the 12-bit immediate offset.
> + unsigned Imm12 = slice(insn, 11, 0);
> + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, Imm12, ARM_AM::no_shift);
> + MI.addOperand(MCOperand::CreateImm(Offset));
> + } else {
> + // Disassemble the offset reg (Rm), shift type, and immediate shift length.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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)));
> + }
> + OpIdx += 2;
> +
> + return true;
> +}
> +
> +static bool DisassembleLdFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false);
> +}
> +
> +static bool DisassembleStFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true);
> +}
> +
> +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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + bool isPrePost = isPrePostLdSt(TID.TSFlags);
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost)));
> +
> + // Operand 0 of a pre- and post-indexed store is the address base writeback.
> + if (isPrePost && isStore) {
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + bool DualReg = HasDualReg(Opcode);
> +
> + // Disassemble the dst/src operand.
> + if (OpIdx >= NumOps)
> + return false;
> +
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> +
> + // Fill in LDRD and STRD's second operand.
> + if (DualReg) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // Disassemble the base operand.
> + if (OpIdx >= NumOps)
> + return false;
> +
> + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> +
> + // For reg/reg form, base reg is followed by +/- reg.
> + // For immediate form, it is followed by +/- imm8.
> + // See also ARMAddressingModes.h (Addressing Mode #3).
> + if (OpIdx + 1 >= NumOps)
> + return false;
> +
> + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) &&
> + (OpInfo[OpIdx+1].RegClass == 0));
> +
> + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
> + if (getAM3IBit(insn) == 1) {
> + MI.addOperand(MCOperand::CreateReg(0));
> +
> + // Disassemble the 8-bit immediate offset.
> + unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF;
> + unsigned Imm4L = insn & 0xF;
> + unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L);
> + MI.addOperand(MCOperand::CreateImm(Offset));
> + } else {
> + // Disassemble the offset reg (Rm).
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + 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) {
> + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false);
> +}
> +
> +static bool DisassembleStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true);
> +}
> +
> +// The algorithm for disassembly of LdStMulFrm is different from others because
> +// it explicitly populates the two predicate operands after operand 0 (the base)
> +// and operand 1 (the AM4 mode imm). After operand 3, 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) {
> +
> + assert(NumOps == 5 && "LdStMulFrm expects NumOps of 5");
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn));
> + MI.addOperand(MCOperand::CreateReg(Base));
> +
> + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn));
> + bool WB = getWBit(insn) == 1;
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB)));
> +
> + // Handling the two predicate operands before the reglist.
> + int64_t CondVal = insn >> ARMII::CondShift;
> + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal));
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> +
> + OpIdx = 4;
> +
> + // 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(ARM::GPRRegClassID,
> + i)));
> + ++OpIdx;
> + }
> + }
> +
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2
> + && OpInfo[0].RegClass == ARM::GPRRegClassID
> + && OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + bool isStore = slice(insn, 20, 20) == 0;
> + bool isDW = (Opcode == ARM::LDREXD || Opcode == ARM::STREXD);
> +
> + // Add the destination operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> +
> + // Store register Exclusive needs a source operand.
> + if (isStore) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + ++OpIdx;
> +
> + if (isDW) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn)+1)));
> + ++OpIdx;
> + }
> + } else if (isDW) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn)+1)));
> + ++OpIdx;
> + }
> +
> + // Finally add the pointer operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2
> + && OpInfo[0].RegClass == ARM::GPRRegClassID
> + && OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> +
> + if (ThreeReg) {
> + assert(NumOps >= 4);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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;
> + MI.addOperand(MCOperand::CreateImm(ShiftAmt));
> + ++OpIdx;
> + }
> +
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2
> + && OpInfo[0].RegClass == ARM::GPRRegClassID
> + && OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> +
> + if (ThreeReg) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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;
> + // Rotation by 8, 16, or 24 bits.
> + MI.addOperand(MCOperand::CreateImm(rot << 3));
> + ++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
> +#if 0
> +static uint64_t 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 |= 0xffL << 54;
> + else
> + Result |= 0x1L << 62;
> + }
> + return Result;
> +}
> +#endif
> +
> +// 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) {
> +
> + assert(NumOps >= 1 && "VFPUnaryFrm expects NumOps >= 1");
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + unsigned RegClass = OpInfo[OpIdx].RegClass;
> + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID);
> + bool isSP = (RegClass == ARM::SPRRegClassID);
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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);
> + isSP = (RegClass == ARM::SPRRegClassID);
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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) {
> +
> + assert(NumOps >= 3 && "VFPBinaryFrm expects NumOps >= 3");
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + unsigned RegClass = OpInfo[OpIdx].RegClass;
> + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID);
> + bool isSP = (RegClass == ARM::SPRRegClassID);
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(RegClass, decodeVFPRd(insn, isSP))));
> + ++OpIdx;
> +
> + // Skip tied_to operand constraint.
> + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) {
> + assert(NumOps >= 4);
> + MI.addOperand(MCOperand::CreateReg(0));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(RegClass, decodeVFPRn(insn, isSP))));
> + ++OpIdx;
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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) {
> +
> + assert(NumOps >= 2 && "VFPConv1Frm expects NumOps >= 2");
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + 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);
> + 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(RegClassID,
> + decodeVFPRd(insn, SP))));
> +
> + assert(TID.getOperandConstraint(1, TOI::TIED_TO) != -1);
> + MI.addOperand(MI.getOperand(0));
> +
> + assert(OpInfo[2].RegClass == 0 && !OpInfo[2].isPredicate() &&
> + !OpInfo[2].isOptionalDef());
> + 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(ARM::SPRRegClassID, d)));
> + m = decodeVFPRm(insn, SP);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, m)));
> + } else {
> + d = decodeVFPRd(insn, SP);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, d)));
> + m = decodeVFPRm(insn, true /* Is Single Precision */);
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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) {
> +
> + assert(NumOps >= 2 && "VFPConv2Frm expects NumOps >= 2");
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(NumOps >= 3 && "VFPConv3Frm expects NumOps >= 3");
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + OpIdx = 2;
> +
> + if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) {
> + unsigned Sm = decodeVFPRm(insn, true);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID,
> + Sm)));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID,
> + Sm+1)));
> + OpIdx += 2;
> + } else {
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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) {
> +
> + assert(NumOps >= 2 && "VFPConv4Frm expects NumOps >= 2");
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID,
> + decodeVFPRn(insn, true))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(NumOps >= 3 && "VFPConv5Frm expects NumOps >= 3");
> +
> + const TargetOperandInfo *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(ARM::SPRRegClassID,
> + Sm)));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID,
> + Sm+1)));
> + OpIdx += 2;
> + } else {
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::DPRRegClassID,
> + decodeVFPRm(insn, false))));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3");
> +
> + bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS) ? true : false;
> + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID;
> +
> + // Extract Dd/Sd for operand 0.
> + unsigned RegD = decodeVFPRd(insn, isSPVFP);
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, RegD)));
> +
> + unsigned Base = getRegisterEnum(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.
> +// This is similar to the algorithm for LDM/STM in that operand 0 (the base) and
> +// operand 1 (the AM5 mode imm) is followed by two predicate operands. It is
> +// followed by a reglist of either DPR(s) or SPR(s).
> +//
> +// VLDMD, VLDMS, VSTMD, VSTMS
> +static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + assert(NumOps == 5 && "VFPLdStMulFrm expects NumOps of 5");
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn));
> + MI.addOperand(MCOperand::CreateReg(Base));
> +
> + // Next comes the AM5 Opcode.
> + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn));
> + bool WB = getWBit(insn) == 1;
> + unsigned char Imm8 = insn & 0xFF;
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(SubMode, WB, Imm8)));
> +
> + // Handling the two predicate operands before the reglist.
> + int64_t CondVal = insn >> ARMII::CondShift;
> + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal));
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> +
> + OpIdx = 4;
> +
> + bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VSTMS) ? true : false;
> + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID;
> +
> + // Extract Dd/Sd.
> + unsigned RegD = decodeVFPRd(insn, isSPVFP);
> +
> + // Fill the variadic part of reglist.
> + unsigned Regs = isSPVFP ? Imm8 : Imm8/2;
> + for (unsigned i = 0; i < Regs; ++i) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + if (Opcode == ARM::FMSTAT)
> + return true;
> +
> + assert(NumOps >= 2);
> +
> + unsigned RegEnum = 0;
> + switch (OpInfo[0].RegClass) {
> + case ARM::DPRRegClassID:
> + RegEnum = getRegisterEnum(ARM::DPRRegClassID, decodeVFPRd(insn, false));
> + break;
> + case ARM::SPRRegClassID:
> + RegEnum = getRegisterEnum(ARM::SPRRegClassID, decodeVFPRd(insn, true));
> + break;
> + case ARM::GPRRegClassID:
> + RegEnum = getRegisterEnum(ARM::GPRRegClassID, decodeRd(insn));
> + break;
> + default:
> + llvm_unreachable("Invalid reg class id");
> + }
> +
> + 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 before-expanded <imm>.
> + // Not VFPExpandImm(slice(insn,19,16) << 4 | slice(insn, 3, 0),
> + // Opcode == ARM::FCONSTD ? 64 : 32)
> + MI.addOperand(MCOperand::CreateImm(slice(insn,19,16)<<4 | slice(insn,3,0)));
> + ++OpIdx;
> + }
> +
> + return true;
> +}
> +
> +// DisassembleThumbFrm() is defined in ThumbDisassemblerCore.cpp.inc file.
> +#include "ThumbDisassemblerCore.cpp.inc"
> +
> +/////////////////////////////////////////////////////
> +// //
> +// 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);
> +
> + 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 cmode = (insn >> 8) & 0xF;
> + unsigned char Imm8 = ((insn >> 24) & 1) << 7 |
> + ((insn >> 16) & 7) << 4 |
> + (insn & 0xF);
> + uint64_t Imm64 = 0;
> +
> + switch (esize) {
> + case ESize8:
> + Imm64 = Imm8;
> + break;
> + case ESize16:
> + Imm64 = Imm8 << 8*(cmode >> 1 & 1);
> + break;
> + case ESize32: {
> + if (cmode == 12)
> + Imm64 = (Imm8 << 8) | 0xFF;
> + else if (cmode == 13)
> + Imm64 = (Imm8 << 16) | 0xFFFF;
> + else {
> + // Imm8 to be shifted left by how many bytes...
> + Imm64 = Imm8 << 8*(cmode >> 1 & 3);
> + }
> + break;
> + }
> + case ESize64: {
> + for (unsigned i = 0; i < 8; ++i)
> + if ((Imm8 >> i) & 1)
> + Imm64 |= 0xFF << 8*i;
> + break;
> + }
> + default:
> + assert(0 && "Unreachable code!");
> + return 0;
> + }
> +
> + return Imm64;
> +}
> +
> +// 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}
> +//
> +// NormalShift == true (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
> +//
> +// NormalShift == false (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
> +//
> +static unsigned decodeNVSAmt(uint32_t insn, bool NormalShift) {
> + 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 (NormalShift)
> + return esize == ESize64 ? (esize - imm6) : (2*esize - imm6);
> + else
> + return esize == ESize64 ? imm6 : (imm6 - esize);
> +}
> +
> +// A8.6.305 VEXT
> +// Imm4 = Inst{11-8}
> +static unsigned decodeN3VImm(uint32_t insn) {
> + return (insn >> 8) & 0xF;
> +}
> +
> +static bool DisassembleNSFormatNone(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + assert(0 && "Unexpected NEON Sub-Format of NSFormatNone");
> + return false;
> +}
> +
> +// VLD*
> +// D[d] D[d2] ... R[addr] [TIED_TO] R[update] AM6 align(ignored)
> +// VLD*LN*
> +// D[d] D[d2] ... R[addr] R[update] AM6 align(ignored) TIED_TO ... imm(idx)
> +// VST*
> +// R[addr] [TIED_TO] R[update] AM6 align(ignored) D[d] D[d2] ...
> +// VST*LN*
> +// R[addr] R[update] AM6 align(ignored) D[d] D[d2] ... [imm(idx)]
> +//
> +// Correctly set VLD*/VST*'s TIED_TO GPR, as the asm printer needs it.
> +static bool DisassembleVLDSTLane0(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded, bool Store, bool DblSpaced) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + // At least one DPR register plus addressing mode #6.
> + assert(NumOps >= 5);
> +
> + 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(ARM::GPRRegClassID, Rm);
> +
> + if (Store) {
> + // Consume AddrMode6 (possible TIED_TO Rn), the DPR/QPR's, then possible
> + // lane index.
> + assert(OpIdx < NumOps && OpInfo[0].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + Rn)));
> + ++OpIdx;
> + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) {
> + // TIED_TO operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + Rn)));
> + ++OpIdx;
> + }
> +
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(RmEnum));
> + ++OpIdx;
> + assert(OpIdx < NumOps &&
> + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0);
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB)));
> + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored?
> + OpIdx += 2;
> +
> + assert(OpIdx < NumOps &&
> + (OpInfo[OpIdx].RegClass == ARM::DPRRegClassID ||
> + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID));
> +
> + RegClass = OpInfo[OpIdx].RegClass;
> + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) {
> + if (Opcode >= ARM::VST1q16 && Opcode <= ARM::VST1q8)
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true)));
> + else
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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, AddrMode6 (possible TIED_TO Rn), possible TIED_TO
> + // DPR/QPR's (ignored), then possible lane index.
> + RegClass = OpInfo[0].RegClass;
> +
> + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) {
> + if (Opcode >= ARM::VLD1q16 && Opcode <= ARM::VLD1q8)
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true)));
> + else
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd)));
> + Rd += Inc;
> + ++OpIdx;
> + }
> +
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + Rn)));
> + ++OpIdx;
> + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) {
> + // TIED_TO operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + Rn)));
> + ++OpIdx;
> + }
> +
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(RmEnum));
> + ++OpIdx;
> + assert(OpIdx < NumOps &&
> + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0);
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB)));
> + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored?
> + OpIdx += 2;
> +
> + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) {
> + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1);
> + 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;
> + }
> + }
> +
> + return true;
> +}
> +
> +// A7.7
> +// If L (Inst{21}) == 0, store instructions.
> +// DblSpaced = false.
> +static bool DisassembleVLDSTLane(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded,
> + slice(insn, 21, 21) == 0, false);
> +}
> +// A7.7
> +// If L (Inst{21}) == 0, store instructions.
> +// DblSpaced = true.
> +static bool DisassembleVLDSTLaneDbl(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded,
> + slice(insn, 21, 21) == 0, true);
> +}
> +
> +// VLDRQ (vldmia), VSTRQ (vstmia)
> +// Qd Rn imm (AM4)
> +static bool DisassembleVLDSTRQ(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::QPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID &&
> + OpInfo[2].RegClass == 0);
> +
> + // Qd = Inst{22:15-12} => NEON Rd
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::QPRRegClassID,
> + decodeNEONRd(insn), true)));
> +
> + // Rn = Inst{19-16} => ARM Rn
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + // Next comes the AM4 Opcode.
> + assert(Opcode == ARM::VLDRQ || Opcode == ARM::VSTRQ);
> + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn));
> + bool WB = getWBit(insn) == 1;
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB)));
> +
> + NumOpsAdded = 3;
> + return true;
> +}
> +
> +// VMOV (immediate)
> +// Qd/Dd imm
> +static bool DisassembleNVdImm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 2 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[1].RegClass == 0));
> +
> + // Qd/Dd = Inst{22:15-12} => NEON Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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:
> + esize = ESize16;
> + break;
> + case ARM::VMOVv2i32:
> + case ARM::VMOVv4i32:
> + esize = ESize32;
> + break;
> + case ARM::VMOVv1i64:
> + case ARM::VMOVv2i64:
> + esize = ESize64;
> + default:
> + assert(0 && "Unreachable code!");
> + return false;
> + }
> +
> + // One register and a modified immediate value.
> + // Add the imm operand.
> + MI.addOperand(MCOperand::CreateImm(decodeN1VImm(insn, esize)));
> +
> + NumOpsAdded = 2;
> + return true;
> +}
> +
> +namespace {
> +enum N2VFlag {
> + N2V_None,
> + N2V_VectorDupLane,
> + N2V_VectorShiftLeftLong,
> + 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 Shift Left Long (with maximum shift count) Instructions.
> +// VSHLLi16, VSHLLi32, VSHLLi8: Qd Dm imm (== size)
> +//
> +// Vector Move Long:
> +// Qd Dm
> +//
> +// Vector Move Narrow:
> +// Dd Qm
> +//
> +// Others
> +static bool DisassembleNVdVmImm0(MCInst &MI, unsigned Opc, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded, N2VFlag Flag = N2V_None) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opc];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 2 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[1].RegClass == ARM::DPRRegClassID ||
> + OpInfo[1].RegClass == ARM::QPRRegClassID));
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + ElemSize esize = ESizeNA;
> + if (Flag == N2V_VectorShiftLeftLong) {
> + // VSHLL has maximum shift count as the imm, inferred from its size.
> + assert(Opc == ARM::VSHLLi16 || Opc == ARM::VSHLLi32 || Opc == ARM::VSHLLi8);
> + esize = Opc == ARM::VSHLLi8 ? ESize8
> + : (Opc == ARM::VSHLLi16 ? ESize16
> + : ESize32);
> + }
> + if (Flag == N2V_VectorDupLane) {
> + // VDUPLN has its index embedded. Its size can be inferred from the Opcode.
> + assert(Opc >= ARM::VDUPLN16d && Opc <= ARM::VDUPLN8q);
> + 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(OpInfo[OpIdx].RegClass,
> + decodeNEONRd(insn))));
> + ++OpIdx;
> +
> + // VPADAL...
> + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) {
> + // TIED_TO operand.
> + MI.addOperand(MCOperand::CreateReg(0));
> + ++OpIdx;
> + }
> +
> + // Dm = Inst{5:3-0} => NEON Rm
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass,
> + decodeNEONRm(insn))));
> + ++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_VectorShiftLeftLong)
> + imm = static_cast<unsigned>(esize);
> + if (Flag == N2V_VectorDupLane)
> + imm = decodeNVLaneDupIndex(insn, esize);
> + if (Flag == N2V_VectorConvert_Between_Float_Fixed)
> + imm = decodeVCVTFractionBits(insn);
> +
> + assert(imm != 0xFFFFFFFF);
> + MI.addOperand(MCOperand::CreateImm(imm));
> + ++OpIdx;
> + }
> +
> + return true;
> +}
> +
> +static bool DisassembleNVdVmImm(MCInst &MI, unsigned Opc, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded);
> +}
> +static bool DisassembleNVdVmImmVCVT(MCInst &MI, unsigned Opc, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded,
> + N2V_VectorConvert_Between_Float_Fixed);
> +}
> +static bool DisassembleNVdVmImmVDupLane(MCInst &MI, unsigned Opc, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded,
> + N2V_VectorDupLane);
> +}
> +static bool DisassembleNVdVmImmVSHLL(MCInst &MI, unsigned Opc, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded,
> + N2V_VectorShiftLeftLong);
> +}
> +
> +// Vector Transpose/Unzip/Zip Instructions
> +// Qd/Dd Qm/Dm [Qd/Dd (TIED_TO)] [Qm/Dm (TIED_TO)]
> +static bool DisassembleNVectorShuffle(MCInst &MI,unsigned Opcode,uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 4 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[1].RegClass == ARM::DPRRegClassID ||
> + OpInfo[1].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[2].RegClass == ARM::DPRRegClassID ||
> + OpInfo[2].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[3].RegClass == ARM::DPRRegClassID ||
> + OpInfo[3].RegClass == ARM::QPRRegClassID));
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + // Qd/Dd = Inst{22:15-12} => NEON Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass,
> + decodeNEONRd(insn))));
> + ++OpIdx;
> +
> + // Dm = Inst{5:3-0} => NEON Rm
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass,
> + decodeNEONRm(insn))));
> + ++OpIdx;
> +
> + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1 &&
> + TID.getOperandConstraint(OpIdx+1, TOI::TIED_TO) != -1);
> +
> + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx;
> + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx;
> +
> + return true;
> +}
> +
> +// Vector Shift [Accumulate] Instructions.
> +// Qd/Dd [Qd/Dd (TIED_TO)] Qm/Dm ShiftAmt
> +static bool DisassembleNVectorShift0(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded, bool NormalShift = true) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 3 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[1].RegClass == ARM::DPRRegClassID ||
> + OpInfo[1].RegClass == ARM::QPRRegClassID));
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + // Qd/Dd = Inst{22:15-12} => NEON Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass,
> + decodeNEONRd(insn))));
> + ++OpIdx;
> +
> + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) {
> + // TIED_TO operand.
> + MI.addOperand(MCOperand::CreateReg(0));
> + ++OpIdx;
> + }
> +
> + assert(OpInfo[OpIdx].RegClass == ARM::DPRRegClassID ||
> + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID);
> +
> + // Qm/Dm = Inst{5:3-0} => NEON Rm
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass,
> + decodeNEONRm(insn))));
> + ++OpIdx;
> +
> + assert(OpInfo[OpIdx].RegClass == 0);
> +
> + // Add the imm operand.
> + MI.addOperand(MCOperand::CreateImm(decodeNVSAmt(insn, NormalShift)));
> + ++OpIdx;
> +
> + return true;
> +}
> +
> +// Normal shift amount interpretation.
> +static bool DisassembleNVectorShift(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, true);
> +}
> +// Different shift amount interpretation.
> +static bool DisassembleNVectorShift2(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, false);
> +}
> +
> +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 DisassembleNVdVnVmImm0(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded, N3VFlag Flag = N3V_None) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 3 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[1].RegClass == ARM::DPRRegClassID ||
> + OpInfo[1].RegClass == ARM::QPRRegClassID) &&
> + (OpInfo[2].RegClass != 0));
> +
> + 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(OpInfo[OpIdx].RegClass,
> + decodeNEONRd(insn))));
> + ++OpIdx;
> +
> + // VABA, VABAL, VBSLd, VBSLq, ...
> + if (TID.getOperandConstraint(OpIdx, TOI::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(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(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!");
> +
> + MI.addOperand(MCOperand::CreateImm(Imm));
> + ++OpIdx;
> + }
> +
> + return true;
> +}
> +
> +static bool DisassembleNVdVnVmImm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded);
> +}
> +static bool DisassembleNVdVnVmImmVectorShift(MCInst &MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded,
> + N3V_VectorShift);
> +}
> +static bool DisassembleNVdVnVmImmVectorExtract(MCInst &MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded,
> + N3V_VectorExtract);
> +}
> +static bool DisassembleNVdVnVmImmMulScalar(MCInst &MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded,
> + N3V_Multiply_By_Scalar);
> +}
> +
> +// 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 DisassembleVTBL(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::DPRRegClassID &&
> + OpInfo[1].RegClass == ARM::DPRRegClassID &&
> + OpInfo[2].RegClass == ARM::DPRRegClassID);
> +
> + 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(ARM::DPRRegClassID,
> + decodeNEONRd(insn))));
> + ++OpIdx;
> +
> + // Process tied_to operand constraint.
> + int Idx;
> + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::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);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID,
> + Rn + i)));
> + ++OpIdx;
> + }
> +
> + // Dm (the index vector)
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID,
> + decodeNEONRm(insn))));
> + ++OpIdx;
> +
> + return true;
> +}
> +
> +/// NEONFuncPtrs - NEONFuncPtrs maps NSFormat to 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 NEONFuncPtrs[] = {
> + // This will assert().
> + &DisassembleNSFormatNone,
> +
> + // VLD and VST (including one lane) Instructions.
> + &DisassembleVLDSTLane,
> +
> + // VLD and VST (including one lane) Double-Spaced Instructions.
> + &DisassembleVLDSTLaneDbl,
> +
> + // A8.6.319 VLDM & A8.6.399 VSTM
> + // LLVM defines VLDRQ/VSTRQ to load/store a Q register as a D register pair.
> + &DisassembleVLDSTRQ,
> +
> + // A7.4.6 One register and a modified immediate value
> + // 1-Register Instructions with imm.
> + // LLVM only defines VMOVv instructions.
> + &DisassembleNVdImm,
> +
> + // 2-Register Instructions with no imm.
> + &DisassembleNVdVmImm,
> +
> + // 2-Register Instructions with imm (vector convert float/fixed point).
> + &DisassembleNVdVmImmVCVT,
> +
> + // 2-Register Instructions with imm (vector dup lane).
> + &DisassembleNVdVmImmVDupLane,
> +
> + // 2-Register Instructions with imm (vector shift left long).
> + &DisassembleNVdVmImmVSHLL,
> +
> + // Vector Transpose/Unzip/Zip Instructions.
> + &DisassembleNVectorShuffle,
> +
> + // Vector Shift [Narrow Accumulate] Instructions.
> + &DisassembleNVectorShift,
> +
> + // Vector Shift Instructions with different interpretation of shift amount.
> + &DisassembleNVectorShift2,
> +
> + // 3-Register Data-Processing Instructions.
> + &DisassembleNVdVnVmImm,
> +
> + // Vector Shift (Register) Instructions.
> + // D:Vd M:Vm N:Vn (notice that M:Vm is the first operand)
> + &DisassembleNVdVnVmImmVectorShift,
> +
> + // Vector Extract Instructions.
> + &DisassembleNVdVnVmImmVectorExtract,
> +
> + // Vector [Saturating Rounding Doubling] Multiply [Accumulate/Subtract] [Long]
> + // By Scalar Instructions.
> + &DisassembleNVdVnVmImmMulScalar,
> +
> + // Vector Table Lookup uses byte indexes in a control vector to look up byte
> + // values in a table and generate a new vector.
> + &DisassembleVTBL,
> + NULL,
> +};
> +
> +static bool DisassembleNEONFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + assert(0 && "Code is not reachable");
> + return false;
> +}
> +
> +// Vector Get Lane (move scalar to ARM core register) Instructions.
> +// VGETLNi32, VGETLNs16, VGETLNs8, VGETLNu16, VGETLNu8: Rt Dn index
> +static bool DisassembleNEONGetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumDefs == 1 && NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == ARM::DPRRegClassID &&
> + OpInfo[2].RegClass == 0);
> +
> + ElemSize esize =
> + Opcode == ARM::VGETLNi32 ? ESize32
> + : ((Opcode == ARM::VGETLNs16 || Opcode == ARM::VGETLNu16) ? ESize16
> + : ESize32);
> +
> + // Rt = Inst{15-12} => ARM Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> +
> + // Dn = Inst{7:19-16} => NEON Rn
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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 DisassembleNEONSetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + unsigned short NumDefs = TID.getNumDefs();
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> +
> + assert(NumDefs == 1 && NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::DPRRegClassID &&
> + OpInfo[1].RegClass == ARM::DPRRegClassID &&
> + TID.getOperandConstraint(1, TOI::TIED_TO) != -1 &&
> + OpInfo[2].RegClass == ARM::GPRRegClassID &&
> + OpInfo[3].RegClass == 0);
> +
> + ElemSize esize =
> + Opcode == ARM::VSETLNi8 ? ESize8
> + : (Opcode == ARM::VSETLNi16 ? ESize16
> + : ESize32);
> +
> + // Dd = Inst{7:19-16} => NEON Rn
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID,
> + decodeNEONRn(insn))));
> +
> + // TIED_TO operand.
> + MI.addOperand(MCOperand::CreateReg(0));
> +
> + // Rt = Inst{15-12} => ARM Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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 DisassembleNEONDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 2 &&
> + (OpInfo[0].RegClass == ARM::DPRRegClassID ||
> + OpInfo[0].RegClass == ARM::QPRRegClassID) &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + unsigned RegClass = OpInfo[0].RegClass;
> +
> + // Qd/Dd = Inst{7:19-16} => NEON Rn
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,
> + decodeNEONRn(insn))));
> +
> + // Rt = Inst{15-12} => ARM Rd
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> +
> + NumOpsAdded = 2;
> + return true;
> +}
> +
> +// A8.6.41 DMB
> +// A8.6.42 DSB
> +// A8.6.49 ISB
> +static inline bool MemBarrierInstr(uint32_t insn) {
> + unsigned op7_4 = slice(insn, 7, 4);
> + if (slice(insn, 31, 20) == 0xf57 && (op7_4 >= 4 && op7_4 <= 6))
> + return true;
> +
> + return false;
> +}
> +
> +static inline bool PreLoadOpcode(unsigned Opcode) {
> + switch(Opcode) {
> + case ARM::PLDi: case ARM::PLDr:
> + case ARM::PLDWi: case ARM::PLDWr:
> + case ARM::PLIi: case ARM::PLIr:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + // Preload Data/Instruction requires either 2 or 4 operands.
> + // PLDi, PLDWi, PLIi: Rn [+/-]imm12 add = (U == '1')
> + // PLDr[a|m], PLDWr[a|m], PLIr[a|m]: Rn Rm addrmode2_opc
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + if (Opcode == ARM::PLDi || Opcode == ARM::PLDWi || Opcode == ARM::PLIi) {
> + unsigned Imm12 = slice(insn, 11, 0);
> + bool Negative = getUBit(insn) == 0;
> + int Offset = Negative ? -1 - Imm12 : 1 * Imm12;
> + MI.addOperand(MCOperand::CreateImm(Offset));
> + NumOpsAdded = 2;
> + } else {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + if (MemBarrierInstr(insn))
> + return true;
> +
> + switch (Opcode) {
> + case ARM::CLREX:
> + case ARM::NOP:
> + case ARM::TRAP:
> + case ARM::YIELD:
> + case ARM::WFE:
> + case ARM::WFI:
> + case ARM::SEV:
> + case ARM::SETENDBE:
> + case ARM::SETENDLE:
> + return true;
> + default:
> + break;
> + }
> +
> + // CPS has a singleton $opt operand that contains the following information:
> + // opt{4-0} = mode from Inst{4-0}
> + // opt{5} = changemode from Inst{17}
> + // opt{8-6} = AIF from Inst{8-6}
> + // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
> + if (Opcode == ARM::CPS) {
> + unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 |
> + slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9;
> + MI.addOperand(MCOperand::CreateImm(Option));
> + 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);
> +
> + assert(0 && "Unexpected misc instruction!");
> + return false;
> +}
> +
> +static bool DisassembleThumbMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + assert(0 && "Unexpected thumb 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,
> + &DisassembleDPSoRegFrm,
> + &DisassembleLdFrm,
> + &DisassembleStFrm,
> + &DisassembleLdMiscFrm,
> + &DisassembleStMiscFrm,
> + &DisassembleLdStMulFrm,
> + &DisassembleArithMiscFrm,
> + &DisassembleExtFrm,
> + &DisassembleVFPUnaryFrm,
> + &DisassembleVFPBinaryFrm,
> + &DisassembleVFPConv1Frm,
> + &DisassembleVFPConv2Frm,
> + &DisassembleVFPConv3Frm,
> + &DisassembleVFPConv4Frm,
> + &DisassembleVFPConv5Frm,
> + &DisassembleVFPLdStFrm,
> + &DisassembleVFPLdStMulFrm,
> + &DisassembleVFPMiscFrm,
> + &DisassembleThumbFrm,
> + &DisassembleNEONFrm,
> + &DisassembleNEONGetLnFrm,
> + &DisassembleNEONSetLnFrm,
> + &DisassembleNEONDupFrm,
> + &DisassembleLdStExFrm,
> + &DisassembleMiscFrm,
> + &DisassembleThumbMiscFrm,
> + NULL,
> +};
> +
> +/// ARMAlgorithm - ARMAlgorithm implements ARMDisassemblyAlgorithm for solving
> +/// the problem of building the MCOperands of an MCInst. Construction of
> +/// ARMAlgorithm requires passing in a function pointer with the DisassembleFP
> +/// data type.
> +class ARMAlgorithm : public ARMDisassemblyAlgorithm {
> + /// Algorithms - Algorithms stores a map from Format to ARMAlgorithm*.
> + static std::vector<ARMAlgorithm*> Algorithms;
> + /// NSAlgorithms - NSAlgorithms stores a map from NSFormat to ARMAlgorithm*.
> + static std::vector<ARMAlgorithm*> NSAlgorithms;
> +
> + DisassembleFP Disassemble;
> +
> +public:
> + /// GetInstance - GetInstance returns an instance of ARMAlgorithm given the
> + /// encoding Format. API clients should not free up the returned instance.
> + static ARMAlgorithm *GetInstance(ARMFormat Format, NSFormat NSF) {
> + /// Init the first time.
> + if (Algorithms.size() == 0) {
> + Algorithms.resize(array_lengthof(FuncPtrs));
> + for (unsigned i = 0, num = array_lengthof(FuncPtrs); i < num; ++i)
> + if (FuncPtrs[i])
> + Algorithms[i] = new ARMAlgorithm(FuncPtrs[i]);
> + else
> + Algorithms[i] = NULL;
> + }
> + if (NSAlgorithms.size() == 0) {
> + NSAlgorithms.resize(array_lengthof(NEONFuncPtrs));
> + for (unsigned i = 0, num = array_lengthof(NEONFuncPtrs); i < num; ++i)
> + if (NEONFuncPtrs[i])
> + NSAlgorithms[i] = new ARMAlgorithm(NEONFuncPtrs[i]);
> + else
> + NSAlgorithms[i] = NULL;
> + }
> +
> + if (Format != ARM_FORMAT_NEONFRM)
> + return Algorithms[Format];
> + else
> + return NSAlgorithms[NSF];
> + }
> +
> + virtual bool Solve(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) const {
> + if (Disassemble == NULL)
> + return false;
> +
> + return (*Disassemble)(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> +
> +private:
> + ARMAlgorithm(DisassembleFP fp) :
> + ARMDisassemblyAlgorithm(), Disassemble(fp) {}
> +
> + ARMAlgorithm(ARMAlgorithm &AA) :
> + ARMDisassemblyAlgorithm(), Disassemble(AA.Disassemble) {}
> +
> + virtual ~ARMAlgorithm() {}
> +};
> +
> +// Define the symbol here.
> +std::vector<ARMAlgorithm*> ARMAlgorithm::Algorithms;
> +
> +// Define the symbol here.
> +std::vector<ARMAlgorithm*> ARMAlgorithm::NSAlgorithms;
> +
> +// Define the symbol here.
> +unsigned ARMBasicMCBuilder::ITCounter = 0;
> +
> +// Define the symbol here.
> +unsigned ARMBasicMCBuilder::ITState = 0;
> +
> +// A8.6.50
> +static unsigned short CountITSize(unsigned ITMask) {
> + // First count the trailing zeros of the IT mask.
> + unsigned TZ = CountTrailingZeros_32(ITMask);
> + assert(TZ <= 3);
> + return (4 - TZ);
> +}
> +
> +/// 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 Algo (ARM Disassemble Algorithm) object to perform Format-specific
> +/// disassembly, followed by class method 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 ARM Disassembly Algorithm to build the operand list.
> + unsigned NumOpsAdded = 0;
> + bool OK = Algo.Solve(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + if (!OK) 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);
> +}
> +
> +bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOpsRemaining) {
> +
> + assert(NumOpsRemaining > 0);
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + const std::string &Name = ARMInsts[Opcode].Name;
> + unsigned Idx = MI.getNumOperands();
> +
> + // First, we check whether this instr specifies the PredicateOperand through
> + // a pair of TargetOperandInfos 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
> + if (Name == "t2Bcc")
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 25, 22)));
> + else if (Name == "tBcc")
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8)));
> + else
> + MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
> + } else {
> + // ARM Instructions. Check condition field.
> + int64_t CondVal = getCondField(insn);
> + if (CondVal == 0xF)
> + MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
> + else
> + MI.addOperand(MCOperand::CreateImm(CondVal));
> + }
> + }
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> + Idx += 2;
> + NumOpsRemaining -= 2;
> + if (NumOpsRemaining == 0)
> + return true;
> + }
> +
> + assert(NumOpsRemaining > 0);
> +
> + // 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 (Opcode == ARM::t2IT) {
> + ARMBasicMCBuilder::ITCounter = CountITSize(slice(insn, 3, 0));
> + ARMBasicMCBuilder::InitITState(slice(insn, 7, 0));
> + } else if (InITBlock())
> + ARMBasicMCBuilder::UpdateITState();
> +
> + return Status;
> +}
> +
> +AbstractARMMCBuilder *ARMMCBuilderFactory::CreateMCBuilder(unsigned Opcode,
> + ARMFormat Format, NSFormat NSF) {
> +
> + ARMAlgorithm *Algo = ARMAlgorithm::GetInstance(Format, NSF);
> + if (!Algo)
> + return NULL;
> +
> + return new ARMBasicMCBuilder(Opcode, Format, NSF,
> + ARMInsts[Opcode].getNumOperands(), *Algo);
> +}
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,301 @@
> +//===- 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, Builder Factory,
> +// as well as the Algorithm to solve the problem of disassembling an ARM instr.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef ARMDISASSEMBLERCORE_H
> +#define ARMDISASSEMBLERCORE_H
> +
> +#include "llvm/MC/MCInst.h"
> +#include "llvm/Target/TargetInstrInfo.h"
> +#include "ARMInstrInfo.h"
> +
> +namespace llvm {
> +
> +class ARMUtils {
> +public:
> + static const char *OpcodeName(unsigned Opcode);
> +};
> +
> +#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_DPSOREGFRM, 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_ARITHMISCFRM, 11) \
> + ENTRY(ARM_FORMAT_EXTFRM, 12) \
> + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \
> + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \
> + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \
> + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \
> + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \
> + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \
> + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \
> + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \
> + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \
> + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \
> + ENTRY(ARM_FORMAT_THUMBFRM, 23) \
> + ENTRY(ARM_FORMAT_NEONFRM, 24) \
> + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \
> + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \
> + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \
> + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \
> + ENTRY(ARM_FORMAT_MISCFRM, 29) \
> + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30)
> +
> +// 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
> +}
> +
> +#define NS_FORMATS \
> + ENTRY(NS_FORMAT_NONE, 0) \
> + ENTRY(NS_FORMAT_VLDSTLane, 1) \
> + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \
> + ENTRY(NS_FORMAT_VLDSTRQ, 3) \
> + ENTRY(NS_FORMAT_NVdImm, 4) \
> + ENTRY(NS_FORMAT_NVdVmImm, 5) \
> + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \
> + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \
> + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \
> + ENTRY(NS_FORMAT_NVectorShuffle, 9) \
> + ENTRY(NS_FORMAT_NVectorShift, 10) \
> + ENTRY(NS_FORMAT_NVectorShift2, 11) \
> + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \
> + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \
> + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \
> + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \
> + ENTRY(NS_FORMAT_VTBL, 16)
> +
> +// NEON instruction sub-format further classify the NEONFrm instruction.
> +#define ENTRY(n, v) n = v,
> +typedef enum {
> + NS_FORMATS
> + NS_FORMAT_NA
> +} NSFormat;
> +#undef ENTRY
> +
> +// Converts enum to const char*.
> +static const inline char *stringForNSFormat(NSFormat form) {
> +#define ENTRY(n, v) case n: return #n;
> + switch(form) {
> + NS_FORMATS
> + case NS_FORMAT_NA:
> + return "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(uint32_t &Bits, unsigned From, unsigned To,
> + uint32_t Val) {
> + assert(From < 32 && To < 32 && From >= To);
> + uint32_t Mask = ((1 << (From - To + 1)) - 1);
> + Bits &= ~(Mask << To);
> + Bits |= (Val & Mask) << To;
> +}
> +
> +/// Various utilities for checking the target specific flags.
> +
> +/// A unary data processing instruction doesn't have an Rn operand.
> +static inline bool isUnaryDP(unsigned TSFlags) {
> + return (TSFlags & ARMII::UnaryDP);
> +}
> +
> +/// This four-bit field describes the addressing mode used.
> +/// See also ARMBaseInstrInfo.h.
> +static inline unsigned getAddrMode(unsigned TSFlags) {
> + return (TSFlags & ARMII::AddrModeMask);
> +}
> +
> +/// {IndexModePre, IndexModePost}
> +/// Only valid for load and store ops.
> +/// See also ARMBaseInstrInfo.h.
> +static inline unsigned getIndexMode(unsigned TSFlags) {
> + return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
> +}
> +
> +/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList.
> +static inline bool isPrePostLdSt(unsigned TSFlags) {
> + return (TSFlags & ARMII::IndexModeMask) != 0;
> +}
> +
> +/// AbstractARMMCBuilder - AbstractARMMCBuilder represents an interface of ARM
> +/// MCInst builder that knows how to build up the MCOperand list.
> +class AbstractARMMCBuilder {
> +public:
> + /// Build - Build the MCInst fully and return true. Return false if any
> + /// failure occurs.
> + virtual bool Build(MCInst &MI, uint32_t insn) { return false; }
> +};
> +
> +/// ARMDisassemblyAlgorithm - ARMDisassemblyAlgorithm represents an interface of
> +/// ARM disassembly algorithm that relies on the entries of target operand info,
> +/// among other things, to solve the problem of disassembling an ARM machine
> +/// instruction.
> +class ARMDisassemblyAlgorithm {
> +public:
> + /// Return true if this algorithm successfully disassembles the instruction.
> + /// NumOpsAdded is updated to reflect the number of operands added by the
> + /// algorithm. NumOpsAdded may be less than NumOps, in which case, there are
> + /// operands unaccounted for which need to be dealt with by the API client.
> + virtual bool Solve(MCInst& MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) const
> + = 0;
> +};
> +
> +/// ARMBasicMCBuilder - ARMBasicMCBuilder represents a concrete subclass of
> +/// ARMAbstractMCBuilder.
> +class ARMBasicMCBuilder : public AbstractARMMCBuilder {
> + unsigned Opcode;
> + ARMFormat Format;
> + NSFormat NSF;
> + unsigned short NumOps;
> + const ARMDisassemblyAlgorithm &Algo;
> + static unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4.
> + static unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially.
> +
> +public:
> + ARMBasicMCBuilder(ARMBasicMCBuilder &MCB) : AbstractARMMCBuilder(),
> + Opcode(MCB.Opcode), Format(MCB.Format), NSF(MCB.NSF), NumOps(MCB.NumOps),
> + Algo(MCB.Algo) {}
> +
> + /// Opcode, Format, NSF, NumOperands, and Algo make an ARM Basic MCBuilder.
> + ARMBasicMCBuilder(unsigned opc, ARMFormat format, NSFormat NSF,
> + unsigned short num, const ARMDisassemblyAlgorithm &algo)
> + : AbstractARMMCBuilder(), Opcode(opc), Format(format), NumOps(num),
> + Algo(algo) {}
> +
> + /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process
> + /// the possible Predicate and SBitModifier, to build the remaining MCOperand
> + /// constituents.
> + static bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOpsRemaning);
> +
> + /// InITBlock - InITBlock returns true if we are inside an IT block.
> + static bool InITBlock() {
> + return ITCounter > 0;
> + }
> +
> + /// 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 Algo (ARM Disassemble Algorithm) object to perform Format-specific
> + /// disassembly, followed by class method TryPredicateAndSBitModifier() to do
> + /// 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.
> + static unsigned GetITCond() {
> + return slice(ITState, 7, 4);
> + }
> +
> + /// Init ITState.
> + static void InitITState(unsigned short bits7_0) {
> + ITState = bits7_0;
> + }
> +
> + /// Update ITState if necessary.
> + static void UpdateITState() {
> + assert(ITCounter);
> + --ITCounter;
> + if (ITCounter == 0)
> + ITState = 0;
> + else {
> + unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1;
> + setSlice(ITState, 4, 0, NewITState4_0);
> + }
> + }
> +};
> +
> +/// ARMMCBuilderFactory - ARMMCBuilderFactory represents the factory class that
> +/// vends out ARMAbstractMCBuilder instances through its class method.
> +class ARMMCBuilderFactory {
> +private:
> + ARMMCBuilderFactory(); // DO NOT IMPLEMENT.
> +
> +public:
> + /// CreateMCBuilder - Return an AbstractARMMCBuilder 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.
> + static AbstractARMMCBuilder *CreateMCBuilder(unsigned Opcode,
> + ARMFormat Format, NSFormat NSF);
> +};
> +
> +} // namespace llvm
> +
> +#endif
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/Makefile
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/Makefile?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/Makefile (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/Makefile Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,17 @@
> +##===- lib/Target/ARM/Disassembler/Makefile ----------------*- Makefile -*-===##
> +#
> +# The LLVM Compiler Infrastructure
> +#
> +# This file is distributed under the University of Illinois Open Source
> +# License. See LICENSE.TXT for details.
> +#
> +##===----------------------------------------------------------------------===##
> +
> +LEVEL = ../../../..
> +LIBRARYNAME = LLVMARMDisassembler
> +CXXFLAGS = -fno-rtti
> +
> +# Hack: we need to include 'main' arm target directory to grab private headers
> +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
> +
> +include $(LEVEL)/Makefile.common
>
> Added: llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc (added)
> +++ llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,2158 @@
> +//===- ThumbDisassemblerCore.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 for disassembling a Thumb instr.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +///////////////////////////////
> +// //
> +// 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 ]
> +*/
> +
> +static bool InITBlock() {
> + return ARMBasicMCBuilder::InITBlock();
> +}
> +
> +// 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;
> +}
> +
> +// Utilities for 32-bit Thumb instructions.
> +
> +// 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 uint32_t getBitfieldInvMask(uint32_t insn) {
> + uint32_t lsb = getImm3(insn) << 2 | getImm2(insn);
> + uint32_t msb = getMsb(insn);
> + uint32_t Val = 0;
> + assert(lsb <= msb && "Encoding error: lsb > msb");
> + for (uint32_t i = lsb; i <= msb; ++i)
> + Val |= (1 << i);
> + return ~Val;
> +}
> +
> +// 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);
> + switch (bits2) {
> + default: assert(0 && "No such value");
> + case 0:
> + ShOp = 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);
> +
> + // 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 signextend<signed int, 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 signextend<signed int, 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 signextend<signed int, 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 signextend<signed int, 25>(Imm25);
> +}
> +
> +// See, for example, A8.6.221 SXTAB16.
> +static inline unsigned decodeRotate(uint32_t insn) {
> + unsigned rotate = slice(insn, 5, 4);
> + return rotate << 3;
> +}
> +
> +///////////////////////////////////////////////
> +// //
> +// 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID);
> +
> + 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(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());
> + MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR));
> + ++OpIdx;
> + }
> +
> + // Check whether the next operand to be added is a Thumb1 Register.
> + assert(OpIdx < NumOps);
> + if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) {
> + // For UseRt, the reg operand is tied to the first reg operand.
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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(ARM::tGPRRegClassID,
> + getT1tRm(insn))));
> + } else {
> + assert(OpInfo[OpIdx].RegClass == 0 &&
> + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef());
> + MI.addOperand(MCOperand::CreateImm(UseRt ? getT1Imm8(insn)
> + : (Imm3 ? getT1Imm3(insn)
> + : getT1Imm5(insn))));
> + }
> + ++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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + (OpInfo[1].RegClass == ARM::CCRRegClassID
> + || OpInfo[1].RegClass == ARM::tGPRRegClassID));
> +
> + // Add the destination operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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());
> + MI.addOperand(MCOperand::CreateReg(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);
> + int Idx;
> + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::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(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_RET: 0 operand
> +// tBX_RET_vararg: Rm
> +// tBLXr_r9: Rm
> +static bool DisassembleThumb1Special(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + // tBX_RET has 0 operand.
> + if (NumOps == 0)
> + return true;
> +
> + // BX/BLX has 1 reg operand: Rm.
> + if (NumOps == 1) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + getT1Rm(insn))));
> + NumOpsAdded = 1;
> + return true;
> + }
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + // Add the destination operand.
> + unsigned RegClass = OpInfo[OpIdx].RegClass;
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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);
> + int Idx;
> + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::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);
> + RegClass = OpInfo[OpIdx].RegClass;
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + (OpInfo[1].RegClass == 0 &&
> + !OpInfo[1].isPredicate() &&
> + !OpInfo[1].isOptionalDef()));
> +
> + // Add the destination operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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
> +//
> +
> +// 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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + // 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.
> + bool Imm5 = (opA != 5);
> +
> + assert(NumOps >= 2
> + && OpInfo[0].RegClass == ARM::tGPRRegClassID
> + && OpInfo[1].RegClass == ARM::tGPRRegClassID);
> +
> + // Add the destination reg and the base reg.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID,
> + getT1tRd(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID,
> + getT1tRn(insn))));
> + OpIdx = 2;
> +
> + // We have either { imm5, tRm } or { tRm } remaining.
> + // Process the imm5 first. Note that STR/LDR (register) should skip the imm5
> + // offset operand for t_addrmode_s[1|2|4].
> +
> + assert(OpIdx < NumOps);
> +
> + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() &&
> + !OpInfo[OpIdx].isOptionalDef()) {
> +
> + MI.addOperand(MCOperand::CreateImm(Imm5 ? getT1Imm5(insn) : 0));
> + ++OpIdx;
> + }
> +
> + // The next reg operand is tRm, the offset.
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID);
> + MI.addOperand(MCOperand::CreateReg(Imm5 ? 0
> + : getRegisterEnum(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) {
> +
> + assert(Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi);
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID &&
> + (OpInfo[2].RegClass == 0 &&
> + !OpInfo[2].isPredicate() &&
> + !OpInfo[2].isOptionalDef()));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(Opcode == ARM::tADDrPCi);
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + (OpInfo[1].RegClass == 0 &&
> + !OpInfo[1].isPredicate() &&
> + !OpInfo[1].isOptionalDef()));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(Opcode == ARM::tADDrSPi);
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID &&
> + (OpInfo[2].RegClass == 0 &&
> + !OpInfo[2].isPredicate() &&
> + !OpInfo[2].isOptionalDef()));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + assert(Opcode == ARM::tPUSH || Opcode == ARM::tPOP);
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + // Handling the two predicate operands before the reglist.
> + MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> + OpIdx = 2;
> +
> + // Fill the variadic part of reglist.
> + unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15)
> + | slice(insn, 7, 0);
> + for (unsigned i = 0; i < 16; ++i) {
> + if ((RegListBits >> i) & 1) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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)
> +// tSETENDBE, tSETENDLE, :
> +// no operand
> +// Others: tRd tRn
> +static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + if (NumOps == 0)
> + return true;
> +
> + if (Opcode == ARM::tPUSH || Opcode == ARM::tPOP)
> + return DisassembleThumb1PushPop(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + const TargetOperandInfo *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:
> + // opt{4-0} = don't care
> + // opt{5} = 0 (false)
> + // opt{8-6} = AIF from Inst{2-0}
> + // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable
> + if (Opcode == ARM::tCPS) {
> + unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10;
> + MI.addOperand(MCOperand::CreateImm(Option));
> + NumOpsAdded = 1;
> + return true;
> + }
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID &&
> + (OpInfo[1].RegClass==0 || OpInfo[1].RegClass==ARM::tGPRRegClassID));
> +
> + // Add the destination operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID,
> + getT1tRd(insn))));
> +
> + if (OpInfo[1].RegClass == ARM::tGPRRegClassID) {
> + // Two register instructions.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID,
> + getT1tRn(insn))));
> + } else {
> + // CBNZ, CBZ
> + assert(Opcode == ARM::tCBNZ || Opcode == ARM::tCBZ);
> + MI.addOperand(MCOperand::CreateImm(getT1Imm6(insn) * 2));
> + }
> +
> + NumOpsAdded = 2;
> +
> + return true;
> +}
> +
> +// A8.6.53 LDM / LDMIA
> +// A8.6.189 STM / STMIA
> +//
> +// 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) {
> +
> + assert(Opcode == ARM::tLDM || Opcode == ARM::tSTM_UPD);
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + unsigned tRt = getT1tRt(insn);
> + unsigned RegListBits = slice(insn, 7, 0);
> +
> + OpIdx = 0;
> +
> + // For STM, WB is always true.
> + if (Opcode == ARM::tSTM_UPD) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + tRt)));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + tRt)));
> + ++OpIdx;
> +
> + // A8.6.53 LDM / LDMIA / LDMFD - Encoding T1
> + // WB is true if tRt is not specified as a member of the register list.
> + // For STM, WB is always true.
> + bool WB = Ld ? ((RegListBits >> tRt) & 1) == 0 : true;
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(ARM_AM::ia, WB)));
> + ++OpIdx;
> +
> + // Handling the two predicate operands before the reglist.
> + MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> + OpIdx += 2;
> +
> + // Fill the variadic part of reglist.
> + for (unsigned i = 0; i < 8; ++i) {
> + if ((RegListBits >> i) & 1) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID,
> + i)));
> + ++OpIdx;
> + }
> + }
> +
> + return true;
> +}
> +
> +static bool DisassembleThumb1LdMul(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + return DisassembleThumb1LdStMul(true, MI, Opcode, insn, NumOps, NumOpsAdded);
> +}
> +
> +static bool DisassembleThumb1StMul(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> + return DisassembleThumb1LdStMul(false, MI, Opcode, insn, NumOps, NumOpsAdded);
> +}
> +
> +// 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) {
> +
> + if (Opcode == ARM::tTRAP)
> + return true;
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + assert(NumOps == 3 && OpInfo[0].RegClass == 0 &&
> + OpInfo[1].isPredicate() && OpInfo[2].RegClass == ARM::CCRRegClassID);
> +
> + unsigned Imm8 = getT1Imm8(insn);
> + MI.addOperand(MCOperand::CreateImm(
> + Opcode == ARM::tBcc ? signextend<signed int, 9>(Imm8 << 1) + 4
> + : (int)Imm8));
> +
> + // Predicate operands by ARMBasicMCBuilder::TryPredicateAndSBitModifier().
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + assert(NumOps == 1 && OpInfo[0].RegClass == 0);
> +
> + unsigned Imm11 = getT1Imm11(insn);
> +
> + // When executing a Thumb instruction, PC reads as the address of the current
> + // instruction plus 4. The assembler subtracts 4 from the difference between
> + // the branch instruction and the target address, disassembler has to add 4 to
> + // to compensate.
> + MI.addOperand(MCOperand::CreateImm(
> + signextend<signed int, 12>(Imm11 << 1) + 4));
> +
> + 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) {
> +
> + 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);
> + case 1:
> + switch (op2) {
> + case 0:
> + switch (op3) {
> + case 0:
> + // A6.2.2 Data-processing
> + return DisassembleThumb1DP(MI, Opcode, insn, NumOps, NumOpsAdded);
> + case 1:
> + // A6.2.3 Special data instructions and branch and exchange
> + return DisassembleThumb1Special(MI, Opcode, insn, NumOps, NumOpsAdded);
> + default:
> + // A8.6.59 LDR (literal)
> + return DisassembleThumb1LdPC(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + break;
> + default:
> + // A6.2.4 Load/store single data item
> + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded);
> + break;
> + }
> + break;
> + case 2:
> + switch (op2) {
> + case 0:
> + // A6.2.4 Load/store single data item
> + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded);
> + case 1:
> + // A6.2.4 Load/store single data item
> + return DisassembleThumb1LdStSP(MI, Opcode, insn, NumOps, NumOpsAdded);
> + case 2:
> + if (op3 <= 1) {
> + // A8.6.10 ADR
> + return DisassembleThumb1AddPCi(MI, Opcode, insn, NumOps, NumOpsAdded);
> + } else {
> + // A8.6.8 ADD (SP plus immediate)
> + return DisassembleThumb1AddSPi(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + default:
> + // A6.2.5 Miscellaneous 16-bit instructions
> + return DisassembleThumb1Misc(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + break;
> + case 3:
> + switch (op2) {
> + case 0:
> + if (op3 <= 1) {
> + // A8.6.189 STM / STMIA / STMEA
> + return DisassembleThumb1StMul(MI, Opcode, insn, NumOps, NumOpsAdded);
> + } else {
> + // A8.6.53 LDM / LDMIA / LDMFD
> + return DisassembleThumb1LdMul(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + case 1:
> + // A6.2.6 Conditional branch, and Supervisor Call
> + return DisassembleThumb1CondBr(MI, Opcode, insn, NumOps, NumOpsAdded);
> + case 2:
> + // Unconditional Branch, see B on page A8-44
> + return DisassembleThumb1Br(MI, Opcode, insn, NumOps, NumOpsAdded);
> + 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) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + NumOpsAdded = 1;
> + return true;
> +}
> +
> +static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + if (Thumb2SRSOpcode(Opcode))
> + return DisassembleThumb2SRS(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + if (Thumb2RFEOpcode(Opcode))
> + return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + assert(Opcode == ARM::t2LDM || Opcode == ARM::t2LDM_UPD ||
> + Opcode == ARM::t2STM || Opcode == ARM::t2STM_UPD);
> + assert(NumOps >= 5 && "Thumb2 LdStMul expects NumOps of 5");
> +
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn));
> +
> + // Writeback to base.
> + if (Opcode == ARM::t2LDM_UPD || Opcode == ARM::t2STM_UPD) {
> + MI.addOperand(MCOperand::CreateReg(Base));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(Base));
> + ++OpIdx;
> +
> + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn));
> + bool WB = getWBit(insn) == 1;
> + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB)));
> + ++OpIdx;
> +
> + // Handling the two predicate operands before the reglist.
> + MI.addOperand(MCOperand::CreateImm(ARMCC::AL));
> + MI.addOperand(MCOperand::CreateReg(ARM::CPSR));
> + OpIdx += 2;
> +
> + // 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(ARM::GPRRegClassID,
> + i)));
> + ++OpIdx;
> + }
> + }
> +
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2
> + && OpInfo[0].RegClass == ARM::GPRRegClassID
> + && OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + bool isStore = (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH);
> + bool isSW = (Opcode == ARM::t2LDREX || Opcode == ARM::t2STREX);
> + bool isDW = (Opcode == ARM::t2LDREXD || Opcode == ARM::t2STREXD);
> +
> + // Add the destination operand for store.
> + if (isStore) {
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + isSW ? decodeRs(insn) : decodeRm(insn))));
> + ++OpIdx;
> + }
> +
> + // Source operand for store and destination operand for load.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + ++OpIdx;
> +
> + // Thumb2 doubleword complication: with an extra source/destination operand.
> + if (isDW) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> + ++OpIdx;
> + }
> +
> + // Finally add the pointer operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> +
> + return true;
> +}
> +
> +// LLVM, as of Jan-05-2010, does not output <Rt2>, i.e., Rs, in the asm.
> +// Whereas the ARM Arch. Manual does not require that t2 = t+1 like in ARM ISA.
> +//
> +// 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 4
> + && OpInfo[0].RegClass == ARM::GPRRegClassID
> + && OpInfo[1].RegClass == ARM::GPRRegClassID
> + && OpInfo[2].RegClass == ARM::GPRRegClassID
> + && OpInfo[3].RegClass == 0);
> +
> + // Add the <Rt> <Rt2> operands.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + // 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 = 4;
> +
> + return true;
> +}
> +
> +// PC-based defined for Codegen, which do not get decoded by design:
> +//
> +// t2TBB, t2TBH: Rm immDontCare immDontCare
> +//
> +// Generic version defined for disassembly:
> +//
> +// t2TBBgen, t2TBHgen: Rn Rm Pred-Imm Pred-CCR
> +static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + assert(NumOps >= 2);
> +
> + // The generic version of TBB/TBH needs a base register.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + // Add the index register.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.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);
> + // Only need to populate the src reg operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(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[1].RegClass == ARM::GPRRegClassID);
> +
> + bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID);
> + bool NoDstReg = (decodeRs(insn) == 0xF);
> +
> + // Build the register operands, followed by the constant shift specifier.
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + NoDstReg ? decodeRn(insn) : decodeRs(insn))));
> + ++OpIdx;
> +
> + if (ThreeReg) {
> + int Idx;
> + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) {
> + // Process tied_to operand constraint.
> + MI.addOperand(MI.getOperand(Idx));
> + } else {
> + assert(!NoDstReg);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + }
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + ++OpIdx;
> +
> + if (NumOps == OpIdx)
> + return true;
> +
> + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate()
> + && !OpInfo[OpIdx].isOptionalDef()) {
> +
> + if (Thumb2ShiftOpcode(Opcode))
> + MI.addOperand(MCOperand::CreateImm(getShiftAmtBits(insn)));
> + else {
> + // Build the constant shift specifier operand.
> + unsigned bits2 = getShiftTypeBits(insn);
> + unsigned imm5 = getShiftAmtBits(insn);
> + ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift;
> + unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp);
> +
> + // PKHBT/PKHTB are special in that we need the decodeImmShift() call to
> + // decode the shift amount from raw imm5 and bits2, but we DO NOT need
> + // to encode the ShOp, as it's in the asm string already.
> + if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB)
> + MI.addOperand(MCOperand::CreateImm(ShAmt));
> + else
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID);
> +
> + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID);
> + bool NoDstReg = (decodeRs(insn) == 0xF);
> +
> + // Build the register operands, followed by the modified immediate.
> +
> + MI.addOperand(MCOperand::CreateReg(
> + getRegisterEnum(ARM::GPRRegClassID,
> + NoDstReg ? decodeRn(insn) : decodeRs(insn))));
> + ++OpIdx;
> +
> + if (TwoReg) {
> + assert(!NoDstReg);
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + // The modified immediate operand should come next.
> + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 &&
> + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef());
> +
> + // 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::t2SSATlsl: case ARM::t2SSATasr: case ARM::t2SSAT16:
> + case ARM::t2USATlsl: case ARM::t2USATasr: case ARM::t2USAT16:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) {
> + switch (Opcode) {
> + case ARM::t2SSATlsl:
> + case ARM::t2SSATasr:
> + return slice(insn, 4, 0) + 1;
> + case ARM::t2SSAT16:
> + return slice(insn, 3, 0) + 1;
> + case ARM::t2USATlsl:
> + case ARM::t2USATasr:
> + return slice(insn, 4, 0);
> + case ARM::t2USAT16:
> + return slice(insn, 3, 0);
> + default:
> + llvm_unreachable("Invalid opcode passed in");
> + return 0;
> + }
> +}
> +
> +// 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) (Currently not defined in LLVM as of Jan-07-2010)
> +// 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
> +//
> +// [Signed|Unsigned] Saturate [16]
> +//
> +// o t2SSAT[lsl|asr], t2USAT[lsl|asr]: Rs sat_pos Rn shamt
> +// o t2SSAT16, t2USAT16: Rs sat_pos Rn
> +static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
> + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID);
> +
> + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + // Build the register operand(s), followed by the immediate(s).
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> + ++OpIdx;
> +
> + // t2SSAT/t2SSAT16/t2USAT/t2USAT16 has imm operand after Rd.
> + if (Thumb2SaturateOpcode(Opcode)) {
> + MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn)));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) {
> + OpIdx += 2;
> + return true;
> + }
> +
> + // For SSAT operand reg (Rn) has been disassembled above.
> + // Now disassemble the shift amount.
> +
> + // Inst{14-12:7-6} encodes the imm5 shift amount.
> + unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6);
> +
> + MI.addOperand(MCOperand::CreateImm(ShAmt));
> +
> + OpIdx += 3;
> + return true;
> + }
> +
> + if (TwoReg) {
> + assert(NumOps >= 3);
> + int Idx;
> + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) {
> + // Process tied_to operand constraint.
> + MI.addOperand(MI.getOperand(Idx));
> + } else {
> + // Add src reg operand.
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + }
> + ++OpIdx;
> + }
> +
> + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate()
> + && !OpInfo[OpIdx].isOptionalDef());
> +
> + // 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)
> + MI.addOperand(MCOperand::CreateImm(getImm16(insn)));
> + else if (Opcode == ARM::t2BFC)
> + MI.addOperand(MCOperand::CreateImm(getBitfieldInvMask(insn)));
> + else {
> + // Handle the case of: lsb width
> + assert(Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX ||
> + Opcode == ARM::t2BFI);
> + MI.addOperand(MCOperand::CreateImm(getLsb(insn)));
> + if (Opcode == ARM::t2BFI) {
> + assert(getMsb(insn) >= getLsb(insn));
> + MI.addOperand(MCOperand::CreateImm(getMsb(insn) - getLsb(insn) + 1));
> + } else
> + MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1));
> +
> + ++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): tBLr9, tBLXi_r9 -> imm operand
> +//
> +// A8.6.26
> +// t2BXJ -> Rn
> +//
> +// Miscellaneous control: t2Int_MemBarrierV7 (and its t2DMB variants),
> +// t2Int_SyncBarrierV7 (and its t2DSB varianst), t2ISBsy, t2CLREX
> +// -> 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) {
> +
> + if (NumOps == 0)
> + return true;
> +
> + 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;
> + }
> +
> + // CPS has a singleton $opt operand that contains the following information:
> + // opt{4-0} = mode from Inst{4-0}
> + // opt{5} = changemode from Inst{8}
> + // opt{8-6} = AIF from Inst{7-5}
> + // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable
> + if (Opcode == ARM::t2CPS) {
> + unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 |
> + slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9;
> + MI.addOperand(MCOperand::CreateImm(Option));
> + 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(ARM::GPRRegClassID,
> + decodeRs(insn))));
> + NumOpsAdded = 1;
> + return true;
> + }
> + // BXJ takes one GPR reg Rn.
> + if (Opcode == ARM::t2BXJ) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + NumOpsAdded = 1;
> + return true;
> + }
> + // MSR and MSRsys take one GPR reg Rn, followed by the mask.
> + if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8)));
> + NumOpsAdded = 2;
> + return true;
> + }
> + // SMC take imm4.
> + if (Opcode == ARM::t2SMC) {
> + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16)));
> + NumOpsAdded = 1;
> + return true;
> + }
> +
> + // Add the imm operand.
> + int Offset = 0;
> +
> + switch (Opcode) {
> + default:
> + assert(0 && "Unreachable code");
> + case ARM::t2B:
> + Offset = decodeImm32_B_EncodingT4(insn);
> + break;
> + case ARM::t2Bcc:
> + Offset = decodeImm32_B_EncodingT3(insn);
> + break;
> + case ARM::tBLr9:
> + Offset = decodeImm32_BL(insn);
> + break;
> + case ARM::tBLXi_r9:
> + Offset = decodeImm32_BLX(insn);
> + break;
> + }
> + // When executing a Thumb instruction, PC reads as the address of the current
> + // instruction plus 4. The assembler subtracts 4 from the difference between
> + // the branch instruction and the target address, disassembler has to add 4 to
> + // to compensate.
> + MI.addOperand(MCOperand::CreateImm(Offset + 4));
> +
> + NumOpsAdded = 1;
> +
> + return true;
> +}
> +
> +static inline bool Thumb2PreloadOpcode(unsigned Opcode) {
> + switch (Opcode) {
> + default:
> + return false;
> + case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDpci:
> + case ARM::t2PLDr: case ARM::t2PLDs:
> + case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWpci:
> + case ARM::t2PLDWr: case ARM::t2PLDWs:
> + case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIpci:
> + case ARM::t2PLIr: case ARM::t2PLIs:
> + return true;
> + }
> +}
> +
> +static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + // 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 TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID);
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> +
> + if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> + } else {
> + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate()
> + && !OpInfo[OpIdx].isOptionalDef());
> + int Offset = 0;
> + if (Opcode == ARM::t2PLDpci || Opcode == ARM::t2PLDWpci ||
> + Opcode == ARM::t2PLIpci) {
> + bool Negative = slice(insn, 23, 23) == 0;
> + unsigned Imm12 = getImm12(insn);
> + Offset = Negative ? -1 - Imm12 : 1 * Imm12;
> + } else 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.
> + 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;
> +}
> +
> +// 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 2 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == 0);
> +
> + // Build the register operand, followed by the (+/-)imm12 immediate.
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> +
> + MI.addOperand(MCOperand::CreateImm(decodeImm12(insn)));
> +
> + NumOpsAdded = 2;
> +
> + return true;
> +}
> +
> +// 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) {
> +
> + unsigned Rn = decodeRn(insn);
> +
> + if (Thumb2PreloadOpcode(Opcode))
> + return DisassembleThumb2PreLoad(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + // See, for example, A6.3.7 Load word: Table A6-18 Load word.
> + if (Load && Rn == 15)
> + return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded);
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + bool ThreeReg = (OpInfo[2].RegClass == ARM::GPRRegClassID);
> + bool TIED_TO = ThreeReg && TID.getOperandConstraint(2, TOI::TIED_TO) != -1;
> + bool Imm12 = !ThreeReg && slice(insn, 23, 23) == 1; // ARMInstrThumb2.td
> +
> + // Build the register operands, followed by the immediate.
> + unsigned R0, R1, 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(ARM::GPRRegClassID, R0)));
> + ++OpIdx;
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R1)));
> + ++OpIdx;
> +
> + if (ThreeReg) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,R2)));
> + ++OpIdx;
> + }
> +
> + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate()
> + && !OpInfo[OpIdx].isOptionalDef());
> +
> + 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) {
> +
> + const TargetInstrDesc &TID = ARMInsts[Opcode];
> + const TargetOperandInfo *OpInfo = TID.OpInfo;
> + unsigned &OpIdx = NumOpsAdded;
> +
> + OpIdx = 0;
> +
> + assert(NumOps >= 2 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID);
> +
> + // Build the register operands, followed by the optional rotation amount.
> +
> + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> + ++OpIdx;
> +
> + if (ThreeReg) {
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> + ++OpIdx;
> + }
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + 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(decodeRotate(insn)));
> + ++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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID &&
> + OpInfo[2].RegClass == ARM::GPRRegClassID);
> +
> + // Build the register operands.
> +
> + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID;
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRm(insn))));
> +
> + if (FourReg)
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + 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) {
> +
> + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
> +
> + assert(NumOps >= 3 &&
> + OpInfo[0].RegClass == ARM::GPRRegClassID &&
> + OpInfo[1].RegClass == ARM::GPRRegClassID &&
> + OpInfo[2].RegClass == ARM::GPRRegClassID);
> +
> + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID;
> +
> + // Build the register operands.
> +
> + if (FourReg)
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRd(insn))));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRs(insn))));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + decodeRn(insn))));
> +
> + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,
> + 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) {
> +
> + 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);
> + }
> +
> + // Load/store dual, load/store exclusive, table branch, otherwise.
> + assert(slice(op2, 2, 2) == 1);
> + if ((ARM::t2LDREX <= Opcode && Opcode <= ARM::t2LDREXH) ||
> + (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH)) {
> + // Load/store exclusive.
> + return DisassembleThumb2LdStEx(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + 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);
> + }
> + if (Opcode == ARM::t2TBBgen || Opcode == ARM::t2TBHgen) {
> + // Table branch.
> + return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + } else if (slice(op2, 6, 5) == 1) {
> + // Data-processing (shifted register).
> + return DisassembleThumb2DPSoReg(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> +
> + // 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);
> + } else {
> + // Data-processing (plain binary immediate)
> + return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + } else {
> + // Branches and miscellaneous control on page A6-20.
> + return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> +
> + break;
> + 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);
> + } 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);
> + }
> + break;
> + case 1:
> + if (slice(op2, 4, 4) == 0) {
> + // A6.3.12 Data-processing (register)
> + return DisassembleThumb2DPReg(MI, Opcode, insn, NumOps, NumOpsAdded);
> + } else if (slice(op2, 3, 3) == 0) {
> + // A6.3.16 Multiply, multiply accumulate, and absolute difference
> + return DisassembleThumb2Mul(MI, Opcode, insn, NumOps, NumOpsAdded);
> + } else {
> + // A6.3.17 Long multiply, long multiply accumulate, and divide
> + return DisassembleThumb2LongMul(MI, Opcode, insn, NumOps, NumOpsAdded);
> + }
> + break;
> + default:
> + // FIXME: A6.3.18 Coprocessor instructions
> + // But see ThumbDisassembler::getInstruction().
> + ;
> + break;
> + }
> +
> + break;
> + default:
> + assert(0 && "Encoding error for Thumb2 instruction!");
> + break;
> + }
> +
> + return false;
> +}
> +
> +static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
> + unsigned short NumOps, unsigned &NumOpsAdded) {
> +
> + 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);
> + }
> +
> + unsigned bits15_11 = slice(HalfWord, 15, 11);
> +
> + // A6.1 Thumb instruction set encoding
> + assert((bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) &&
> + "Bits [15:11] of first halfword of a Thumb2 instruction out of range");
> +
> + // 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);
> +}
>
> Modified: llvm/trunk/lib/Target/ARM/Makefile
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Makefile?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Makefile (original)
> +++ llvm/trunk/lib/Target/ARM/Makefile Tue Mar 16 11:36:54 2010
> @@ -16,8 +16,9 @@
> ARMGenRegisterInfo.inc ARMGenInstrNames.inc \
> ARMGenInstrInfo.inc ARMGenAsmWriter.inc \
> ARMGenDAGISel.inc ARMGenSubtarget.inc \
> - ARMGenCodeEmitter.inc ARMGenCallingConv.inc
> + ARMGenCodeEmitter.inc ARMGenCallingConv.inc \
> + ARMGenDisassemblerTables.inc
>
> -DIRS = AsmPrinter AsmParser TargetInfo
> +DIRS = AsmPrinter AsmParser Disassembler TargetInfo
>
> include $(LEVEL)/Makefile.common
>
> Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Tue Mar 16 11:36:54 2010
> @@ -78,14 +78,16 @@
> DebugLoc ndl = NMI->getDebugLoc();
> unsigned NPredReg = 0;
> ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg);
> - if (NCC == OCC) {
> - Mask |= (1 << Pos);
> - } else if (NCC != CC)
> + if (NCC == CC || NCC == OCC)
> + Mask |= (NCC & 1) << Pos;
> + else
> break;
> --Pos;
> ++MBBI;
> }
> Mask |= (1 << Pos);
> + // Tag along (firstcond[0] << 4) with the mask.
> + Mask |= (CC & 1) << 4;
> MIB.addImm(Mask);
> Modified = true;
> ++NumITs;
>
> Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Tue Mar 16 11:36:54 2010
> @@ -4,8 +4,8 @@
>
> define arm_aapcscc void @g() {
> entry:
> -;CHECK: [sp, #+8]
> -;CHECK: [sp, #+12]
> +;CHECK: [sp, #8]
> +;CHECK: [sp, #12]
> ;CHECK: [sp]
> tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00)
> ret void
>
> Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Tue Mar 16 11:36:54 2010
> @@ -6,7 +6,7 @@
> entry:
> ;CHECK: sub sp, sp, #4
> ;CHECK: add r{{[0-9]+}}, sp, #8
> -;CHECK: str r{{[0-9]+}}, [sp], #+4
> +;CHECK: str r{{[0-9]+}}, [sp], #4
> ;CHECK: bx lr
> %ap = alloca i8*, align 4
> %ap1 = bitcast i8** %ap to i8*
>
> Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Tue Mar 16 11:36:54 2010
> @@ -5,7 +5,7 @@
>
> define void @test(i32* %P, i32 %A, i32 %i) nounwind {
> entry:
> -; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2]
> +; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2]
> icmp eq i32 %i, 0 ; <i1>:0 [#uses=1]
> br i1 %0, label %return, label %bb
>
>
> Modified: llvm/trunk/test/CodeGen/ARM/globals.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/globals.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/globals.ll Tue Mar 16 11:36:54 2010
> @@ -41,7 +41,7 @@
> ; DarwinPIC: _test1:
> ; DarwinPIC: ldr r0, LCPI1_0
> ; DarwinPIC: LPC1_0:
> -; DarwinPIC: ldr r0, [pc, +r0]
> +; DarwinPIC: ldr r0, [pc, r0]
> ; DarwinPIC: ldr r0, [r0]
> ; DarwinPIC: bx lr
>
> @@ -63,7 +63,7 @@
>
> ; LinuxPIC: .LPC1_0:
> ; LinuxPIC: add r0, pc, r0
> -; LinuxPIC: ldr r0, [r1, +r0]
> +; LinuxPIC: ldr r0, [r1, r0]
> ; LinuxPIC: ldr r0, [r0]
> ; LinuxPIC: bx lr
>
>
> Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Tue Mar 16 11:36:54 2010
> @@ -10,10 +10,10 @@
> ;V6: ldrd r2, [r2]
>
> ;V5: ldr r3, [r2]
> -;V5: ldr r2, [r2, #+4]
> +;V5: ldr r2, [r2, #4]
>
> ;EABI: ldr r3, [r2]
> -;EABI: ldr r2, [r2, #+4]
> +;EABI: ldr r2, [r2, #4]
>
> %0 = load i64** @b, align 4
> %1 = load i64* %0, align 4
>
> Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Tue Mar 16 11:36:54 2010
> @@ -1,5 +1,5 @@
> ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!}
> -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4}
> +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4}
>
> @b = external global i64*
>
>
> Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original)
> +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Tue Mar 16 11:36:54 2010
> @@ -7,7 +7,7 @@
>
> define i32 @f() {
> ; CHECK-NONPIC: f:
> -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}]
> +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}]
> ; CHECK-NONPIC: i(gottpoff)
> ; CHECK-PIC: f:
> ; CHECK-PIC: __tls_get_addr
> @@ -18,7 +18,7 @@
>
> define i32* @g() {
> ; CHECK-NONPIC: g:
> -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}]
> +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}]
> ; CHECK-NONPIC: i(gottpoff)
> ; CHECK-PIC: g:
> ; CHECK-PIC: __tls_get_addr
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Tue Mar 16 11:36:54 2010
> @@ -22,7 +22,7 @@
>
> define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind {
> entry:
> -; CHECK: ldr.w r9, [r7, #+28]
> +; CHECK: ldr.w r9, [r7, #28]
> %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0]
> %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0]
> br i1 false, label %bb, label %bb20
> @@ -50,9 +50,9 @@
> bb420: ; preds = %bb20, %bb20
> ; CHECK: bb420
> ; CHECK: str r{{[0-7]}}, [sp]
> -; CHECK: str r{{[0-7]}}, [sp, #+4]
> -; CHECK: str r{{[0-7]}}, [sp, #+8]
> -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24]
> +; CHECK: str r{{[0-7]}}, [sp, #4]
> +; CHECK: str r{{[0-7]}}, [sp, #8]
> +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24]
> store %union.rec* null, %union.rec** @zz_hold, align 4
> store %union.rec* null, %union.rec** @zz_res, align 4
> store %union.rec* %x, %union.rec** @zz_hold, align 4
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Tue Mar 16 11:36:54 2010
> @@ -11,7 +11,7 @@
> define i32 @f2(i32* %v) {
> entry:
> ; CHECK: f2:
> -; CHECK: ldr.w r0, [r0, #+4092]
> +; CHECK: ldr.w r0, [r0, #4092]
> %tmp2 = getelementptr i32* %v, i32 1023
> %tmp = load i32* %tmp2
> ret i32 %tmp
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Tue Mar 16 11:36:54 2010
> @@ -11,7 +11,7 @@
> define i16 @f2(i16* %v) {
> entry:
> ; CHECK: f2:
> -; CHECK: ldrh.w r0, [r0, #+2046]
> +; CHECK: ldrh.w r0, [r0, #2046]
> %tmp2 = getelementptr i16* %v, i16 1023
> %tmp = load i16* %tmp2
> ret i16 %tmp
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Tue Mar 16 11:36:54 2010
> @@ -9,7 +9,7 @@
>
> define i32 @f2(i32 %a, i32* %v) {
> ; CHECK: f2:
> -; CHECK: str.w r0, [r1, #+4092]
> +; CHECK: str.w r0, [r1, #4092]
> %tmp2 = getelementptr i32* %v, i32 1023
> store i32 %a, i32* %tmp2
> ret i32 %a
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Tue Mar 16 11:36:54 2010
> @@ -2,7 +2,7 @@
>
> define void @test1(i32* %X, i32* %A, i32** %dest) {
> ; CHECK: test1
> -; CHECK: str r1, [r0, #+16]!
> +; CHECK: str r1, [r0, #16]!
> %B = load i32* %A ; <i32> [#uses=1]
> %Y = getelementptr i32* %X, i32 4 ; <i32*> [#uses=2]
> store i32 %B, i32* %Y
> @@ -12,7 +12,7 @@
>
> define i16* @test2(i16* %X, i32* %A) {
> ; CHECK: test2
> -; CHECK: strh r1, [r0, #+8]!
> +; CHECK: strh r1, [r0, #8]!
> %B = load i32* %A ; <i32> [#uses=1]
> %Y = getelementptr i16* %X, i32 4 ; <i16*> [#uses=2]
> %tmp = trunc i32 %B to i16 ; <i16> [#uses=1]
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Tue Mar 16 11:36:54 2010
> @@ -9,7 +9,7 @@
>
> define i8 @f2(i8 %a, i8* %v) {
> ; CHECK: f2:
> -; CHECK: strb.w r0, [r1, #+4092]
> +; CHECK: strb.w r0, [r1, #4092]
> %tmp2 = getelementptr i8* %v, i32 4092
> store i8 %a, i8* %tmp2
> ret i8 %a
>
> Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Tue Mar 16 11:36:54 2010
> @@ -9,7 +9,7 @@
>
> define i16 @f2(i16 %a, i16* %v) {
> ; CHECK: f2:
> -; CHECK: strh.w r0, [r1, #+4092]
> +; CHECK: strh.w r0, [r1, #4092]
> %tmp2 = getelementptr i16* %v, i32 2046
> store i16 %a, i16* %tmp2
> ret i16 %a
>
> Modified: llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp (original)
> +++ llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010
> @@ -12,6 +12,8 @@
> #include "Record.h"
> #include "X86DisassemblerTables.h"
> #include "X86RecognizableInstr.h"
> +#include "RISCDisassemblerEmitter.h"
> +
> using namespace llvm;
> using namespace llvm::X86Disassembler;
>
> @@ -124,6 +126,12 @@
> return;
> }
>
> + // Fixed-instruction-length targets use a common disassembler.
> + if (Target.getName() == "ARM") {
> + RISCDisassemblerEmitter(Records).run(OS);
> + return;
> + }
> +
> throw TGError(Target.getTargetRecord()->getLoc(),
> "Unable to generate disassembler for this target");
> }
>
> Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp (added)
> +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,1743 @@
> +//===- RISCDisassemblerEmitter.cpp - Disassembler Generator ---------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// FIXME: document
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#define DEBUG_TYPE "risc-disassembler-emitter"
> +
> +#include "RISCDisassemblerEmitter.h"
> +#include "CodeGenTarget.h"
> +#include "Record.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +#include <iomanip>
> +#include <vector>
> +#include <cstdio>
> +#include <map>
> +#include <string>
> +#include <sstream>
> +
> +using namespace llvm;
> +
> +////////////////////////////////////
> +// Utility classes / structures //
> +////////////////////////////////////
> +
> +// LLVM coding style
> +#define INDENT_LEVEL 2
> +
> +/// Indenter - A little helper class to keep track of the indentation depth,
> +/// while the instance object is being passed around.
> +class Indenter {
> +public:
> + Indenter() : depth(0) {}
> +
> + void push() {
> + depth += INDENT_LEVEL;
> + }
> +
> + void pop() {
> + if (depth >= INDENT_LEVEL)
> + depth -= INDENT_LEVEL;
> + }
> +
> + // Conversion operator.
> + operator int () {
> + return depth;
> + }
> +private:
> + uint8_t depth;
> +};
> +
> +/////////////////////////
> +// Utility functions //
> +/////////////////////////
> +
> +static uint8_t byteFromBitsInit(BitsInit &init) {
> + int width = init.getNumBits();
> +
> + assert(width <= 8 && "Field is too large for uint8_t!");
> +
> + int index;
> + uint8_t mask = 0x01;
> +
> + uint8_t ret = 0;
> +
> + for (index = 0; index < width; index++) {
> + if (static_cast<BitInit*>(init.getBit(index))->getValue())
> + ret |= mask;
> +
> + mask <<= 1;
> + }
> +
> + return ret;
> +}
> +
> +static uint8_t getByteField(const Record &def, const char *str) {
> + BitsInit *bits = def.getValueAsBitsInit(str);
> + return byteFromBitsInit(*bits);
> +}
> +
> +static BitsInit &getBitsField(const Record &def, const char *str) {
> + BitsInit *bits = def.getValueAsBitsInit(str);
> + return *bits;
> +}
> +
> +/// sameStringExceptEndingChar - Return true if the two strings differ only in
> +/// the ending char. ("VST4q8a", "VST4q8b", 'a', 'b') as input returns true.
> +static
> +bool sameStringExceptEndingChar(const std::string &LHS, const std::string &RHS,
> + char lhc, char rhc) {
> +
> + if (LHS.length() > 1 && RHS.length() > 1 && LHS.length() == RHS.length()) {
> + unsigned length = LHS.length();
> + return LHS.substr(0, length - 1) == RHS.substr(0, length - 1)
> + && LHS[length - 1] == lhc && RHS[length - 1] == rhc;
> + }
> +
> + return false;
> +}
> +
> +/// thumbInstruction - Determine whether we have a Thumb instruction.
> +/// See also ARMInstrFormats.td.
> +static bool thumbInstruction(uint8_t Form) {
> + return Form == 23;
> +}
> +
> +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system
> +// for a bit value.
> +//
> +// BIT_UNFILTERED is used as the init value for a filter position. It is used
> +// only for filter processings.
> +typedef enum {
> + BIT_TRUE, // '1'
> + BIT_FALSE, // '0'
> + BIT_UNSET, // '?'
> + BIT_UNFILTERED // unfiltered
> +} bit_value_t;
> +
> +static bit_value_t bitFromBits(BitsInit &bits, unsigned index) {
> + if (BitInit *bit = dynamic_cast<BitInit*>(bits.getBit(index)))
> + return bit->getValue() ? BIT_TRUE : BIT_FALSE;
> +
> + // The bit is uninitialized.
> + return BIT_UNSET;
> +}
> +
> +static void dumpBits(raw_ostream &o, BitsInit &bits) {
> + unsigned index;
> +
> + for (index = bits.getNumBits(); index > 0; index--) {
> + switch (bitFromBits(bits, index - 1)) {
> + case BIT_TRUE:
> + o << "1";
> + break;
> + case BIT_FALSE:
> + o << "0";
> + break;
> + case BIT_UNSET:
> + o << "_";
> + break;
> + default:
> + assert(0 && "unexpected return value from bitFromBits");
> + }
> + }
> +}
> +
> +/////////////
> +// Enums //
> +/////////////
> +
> +#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_DPSOREGFRM, 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_ARITHMISCFRM, 11) \
> + ENTRY(ARM_FORMAT_EXTFRM, 12) \
> + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \
> + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \
> + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \
> + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \
> + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \
> + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \
> + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \
> + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \
> + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \
> + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \
> + ENTRY(ARM_FORMAT_THUMBFRM, 23) \
> + ENTRY(ARM_FORMAT_NEONFRM, 24) \
> + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \
> + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \
> + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \
> + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \
> + ENTRY(ARM_FORMAT_MISCFRM, 29) \
> + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30)
> +
> +// 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 char *stringForARMFormat(ARMFormat form) {
> +#define ENTRY(n, v) case n: return #n;
> + switch(form) {
> + ARM_FORMATS
> + case ARM_FORMAT_NA:
> + default:
> + return "";
> + }
> +#undef ENTRY
> +}
> +
> +#define NS_FORMATS \
> + ENTRY(NS_FORMAT_NONE, 0) \
> + ENTRY(NS_FORMAT_VLDSTLane, 1) \
> + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \
> + ENTRY(NS_FORMAT_VLDSTRQ, 3) \
> + ENTRY(NS_FORMAT_NVdImm, 4) \
> + ENTRY(NS_FORMAT_NVdVmImm, 5) \
> + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \
> + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \
> + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \
> + ENTRY(NS_FORMAT_NVectorShuffle, 9) \
> + ENTRY(NS_FORMAT_NVectorShift, 10) \
> + ENTRY(NS_FORMAT_NVectorShift2, 11) \
> + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \
> + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \
> + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \
> + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \
> + ENTRY(NS_FORMAT_VTBL, 16)
> +
> +// NEON instruction sub-format further classify the NEONFrm instruction.
> +#define ENTRY(n, v) n = v,
> +typedef enum {
> + NS_FORMATS
> + NS_FORMAT_NA
> +} NSFormat;
> +#undef ENTRY
> +
> +// Converts enum to const char*.
> +static const char *stringForNSFormat(NSFormat form) {
> +#define ENTRY(n, v) case n: return #n;
> + switch(form) {
> + NS_FORMATS
> + case NS_FORMAT_NA:
> + default:
> + return "";
> + }
> +#undef ENTRY
> +}
> +
> +// Enums for the available target names.
> +typedef enum {
> + TARGET_ARM = 0,
> + TARGET_THUMB
> +} TARGET_NAME_t;
> +
> +class AbstractFilterChooser {
> +public:
> + static TARGET_NAME_t TargetName;
> + static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; }
> + virtual ~AbstractFilterChooser() {}
> + virtual void emitTop(raw_ostream &o, Indenter &i) = 0;
> + virtual void emitBot(raw_ostream &o, Indenter &i) = 0;
> +};
> +
> +// Define the symbol here.
> +TARGET_NAME_t AbstractFilterChooser::TargetName;
> +
> +template <unsigned tBitWidth>
> +class FilterChooser : public AbstractFilterChooser {
> +protected:
> + // Representation of the instruction to work on.
> + typedef bit_value_t insn_t[tBitWidth];
> +
> + class Filter {
> + protected:
> + FilterChooser *Owner; // pointer without ownership
> + unsigned StartBit; // the starting bit position
> + unsigned NumBits; // number of bits to filter
> + bool Mixed; // a mixed region contains both set and unset bits
> +
> + // Map of well-known segment value to the set of uid's with that value.
> + std::map<uint64_t, std::vector<unsigned> > FilteredInstructions;
> +
> + // Set of uid's with non-constant segment values.
> + std::vector<unsigned> VariableInstructions;
> +
> + // Map of well-known segment value to its delegate.
> + std::map<unsigned, FilterChooser> FilterChooserMap;
> +
> + // Number of instructions which fall under FilteredInstructions category.
> + unsigned NumFiltered;
> +
> + // Keeps track of the last opcode in the filtered bucket.
> + unsigned LastOpcFiltered;
> +
> + // Number of instructions which fall under VariableInstructions category.
> + unsigned NumVariable;
> +
> + public:
> + unsigned getNumFiltered() { return NumFiltered; }
> + unsigned getNumVariable() { return NumVariable; }
> + unsigned getSingletonOpc() {
> + assert(NumFiltered == 1);
> + return LastOpcFiltered;
> + }
> + FilterChooser &getVariableFC() {
> + assert(NumFiltered == 1);
> + assert(FilterChooserMap.size() == 1);
> + return FilterChooserMap.find(-1)->second;
> + }
> +
> + Filter(const Filter &f) :
> + Owner(f.Owner),
> + StartBit(f.StartBit),
> + NumBits(f.NumBits),
> + Mixed(f.Mixed),
> + FilteredInstructions(f.FilteredInstructions),
> + VariableInstructions(f.VariableInstructions),
> + FilterChooserMap(f.FilterChooserMap),
> + NumFiltered(f.NumFiltered),
> + LastOpcFiltered(f.LastOpcFiltered),
> + NumVariable(f.NumVariable) { }
> +
> + Filter(FilterChooser &owner, unsigned startBit, unsigned numBits,
> + bool mixed) :
> + Owner(&owner),
> + StartBit(startBit),
> + NumBits(numBits),
> + Mixed(mixed)
> + {
> + assert(StartBit + NumBits - 1 < tBitWidth);
> +
> + NumFiltered = 0;
> + LastOpcFiltered = 0;
> + NumVariable = 0;
> +
> + for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) {
> + insn_t Insn;
> +
> + // Populates the insn given the uid.
> + Owner->insnWithID(Insn, Owner->Opcodes[i]);
> +
> + uint64_t Field;
> + // Scans the segment for possibly well-specified encoding bits.
> + bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits);
> +
> + if (ok) {
> + // The encoding bits are well-known. Lets add the uid of the
> + // instruction into the bucket keyed off the constant field value.
> + LastOpcFiltered = Owner->Opcodes[i];
> + FilteredInstructions[Field].push_back(LastOpcFiltered);
> + ++NumFiltered;
> + } else {
> + // Some of the encoding bit(s) are unspecfied. This contributes to
> + // one additional member of "Variable" instructions.
> + VariableInstructions.push_back(Owner->Opcodes[i]);
> + ++NumVariable;
> + }
> + }
> +
> + assert((FilteredInstructions.size() + VariableInstructions.size() > 0)
> + && "Filter returns no instruction categories");
> + }
> +
> + // Divides the decoding task into sub tasks and delegates them to the
> + // inferior FilterChooser's.
> + //
> + // A special case arises when there's only one entry in the filtered
> + // instructions. In order to unambiguously decode the singleton, we need to
> + // match the remaining undecoded encoding bits against the singleton.
> + void recurse() {
> + std::map<uint64_t, std::vector<unsigned> >::const_iterator mapIterator;
> +
> + bit_value_t BitValueArray[tBitWidth];
> + // Starts by inheriting our parent filter chooser's filter bit values.
> + memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray));
> +
> + unsigned bitIndex;
> +
> + if (VariableInstructions.size()) {
> + // Conservatively marks each segment position as BIT_UNSET.
> + for (bitIndex = 0; bitIndex < NumBits; bitIndex++)
> + BitValueArray[StartBit + bitIndex] = BIT_UNSET;
> +
> + // Delegates to an inferior filter chooser for futher processing on this
> + // group of instructions whose segment values are variable.
> + FilterChooserMap.insert(std::pair<unsigned, FilterChooser>(
> + (unsigned)-1,
> + FilterChooser(Owner->AllInstructions,
> + VariableInstructions,
> + BitValueArray,
> + *Owner)
> + ));
> + }
> +
> + // No need to recurse for a singleton filtered instruction.
> + // See also Filter::emit().
> + if (getNumFiltered() == 1) {
> + //Owner->SingletonExists(LastOpcFiltered);
> + assert(FilterChooserMap.size() == 1);
> + return;
> + }
> +
> + // Otherwise, create sub choosers.
> + for (mapIterator = FilteredInstructions.begin();
> + mapIterator != FilteredInstructions.end();
> + mapIterator++) {
> +
> + // Marks all the segment positions with either BIT_TRUE or BIT_FALSE.
> + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) {
> + if (mapIterator->first & (1 << bitIndex))
> + BitValueArray[StartBit + bitIndex] = BIT_TRUE;
> + else
> + BitValueArray[StartBit + bitIndex] = BIT_FALSE;
> + }
> +
> + // Delegates to an inferior filter chooser for futher processing on this
> + // category of instructions.
> + FilterChooserMap.insert(std::pair<unsigned, FilterChooser>(
> + mapIterator->first,
> + FilterChooser(Owner->AllInstructions,
> + mapIterator->second,
> + BitValueArray,
> + *Owner)
> + ));
> + }
> + }
> +
> + // Emit code to decode instructions given a segment or segments of bits.
> + void emit(raw_ostream &o, Indenter &i) {
> + o.indent(i) << "// Check Inst{";
> +
> + if (NumBits > 1)
> + o << (StartBit + NumBits - 1) << '-';
> +
> + o << StartBit << "} ...\n";
> +
> + o.indent(i) << "switch (fieldFromInstruction(insn, "
> + << StartBit << ", " << NumBits << ")) {\n";
> +
> + typename std::map<unsigned, FilterChooser>::iterator filterIterator;
> +
> + bool DefaultCase = false;
> + for (filterIterator = FilterChooserMap.begin();
> + filterIterator != FilterChooserMap.end();
> + filterIterator++) {
> +
> + // Field value -1 implies a non-empty set of variable instructions.
> + // See also recurse().
> + if (filterIterator->first == (unsigned)-1) {
> + DefaultCase = true;
> +
> + o.indent(i) << "default:\n";
> + o.indent(i) << " break; // fallthrough\n";
> +
> + // Closing curly brace for the switch statement.
> + // This is unconventional because we want the default processing to be
> + // performed for the fallthrough cases as well, i.e., when the "cases"
> + // did not prove a decoded instruction.
> + o.indent(i) << "}\n";
> +
> + } else {
> + o.indent(i) << "case " << filterIterator->first << ":\n";
> + }
> +
> + // We arrive at a category of instructions with the same segment value.
> + // Now delegate to the sub filter chooser for further decodings.
> + // The case may fallthrough, which happens if the remaining well-known
> + // encoding bits do not match exactly.
> + if (!DefaultCase) i.push();
> + {
> + bool finished = filterIterator->second.emit(o, i);
> + // For top level default case, there's no need for a break statement.
> + if (Owner->isTopLevel() && DefaultCase)
> + break;
> + if (!finished)
> + o.indent(i) << "break;\n";
> + }
> + if (!DefaultCase) i.pop();
> + }
> +
> + // If there is no default case, we still need to supply a closing brace.
> + if (!DefaultCase) {
> + // Closing curly brace for the switch statement.
> + o.indent(i) << "}\n";
> + }
> + }
> +
> + // Returns the number of fanout produced by the filter. More fanout implies
> + // the filter distinguishes more categories of instructions.
> + unsigned usefulness() const {
> + if (VariableInstructions.size())
> + return FilteredInstructions.size();
> + else
> + return FilteredInstructions.size() + 1;
> + }
> + }; // End of inner class Filter
> +
> + friend class Filter;
> +
> + // Vector of codegen instructions to choose our filter.
> + const std::vector<const CodeGenInstruction*> &AllInstructions;
> +
> + // Vector of uid's for this filter chooser to work on.
> + const std::vector<unsigned> Opcodes;
> +
> + // Vector of candidate filters.
> + std::vector<Filter> Filters;
> +
> + // Array of bit values passed down from our parent.
> + // Set to all BIT_UNFILTERED's for Parent == NULL.
> + bit_value_t FilterBitValues[tBitWidth];
> +
> + // Links to the FilterChooser above us in the decoding tree.
> + FilterChooser *Parent;
> +
> + // Index of the best filter from Filters.
> + int BestIndex;
> +
> +public:
> + FilterChooser(const FilterChooser &FC) :
> + AbstractFilterChooser(),
> + AllInstructions(FC.AllInstructions),
> + Opcodes(FC.Opcodes),
> + Filters(FC.Filters),
> + Parent(FC.Parent),
> + BestIndex(FC.BestIndex)
> + {
> + memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues));
> + }
> +
> + FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
> + const std::vector<unsigned> &IDs) :
> + AllInstructions(Insts),
> + Opcodes(IDs),
> + Filters(),
> + Parent(NULL),
> + BestIndex(-1)
> + {
> + for (unsigned i = 0; i < tBitWidth; ++i)
> + FilterBitValues[i] = BIT_UNFILTERED;
> +
> + doFilter();
> + }
> +
> + FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
> + const std::vector<unsigned> &IDs,
> + bit_value_t (&ParentFilterBitValues)[tBitWidth],
> + FilterChooser &parent) :
> + AllInstructions(Insts),
> + Opcodes(IDs),
> + Filters(),
> + Parent(&parent),
> + BestIndex(-1)
> + {
> + for (unsigned i = 0; i < tBitWidth; ++i)
> + FilterBitValues[i] = ParentFilterBitValues[i];
> +
> + doFilter();
> + }
> +
> + // The top level filter chooser has NULL as its parent.
> + bool isTopLevel() { return Parent == NULL; }
> +
> + // This provides an opportunity for target specific code emission.
> + void emitTopHook(raw_ostream &o, Indenter &i) {
> + if (TargetName == TARGET_ARM) {
> + // Emit code that references the ARMFormat data type.
> + o << "static const ARMFormat ARMFormats[] = {\n";
> + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) {
> + const Record &Def = *(AllInstructions[i]->TheDef);
> + const std::string &Name = Def.getName();
> + if (Def.isSubClassOf("InstARM") || Def.isSubClassOf("InstThumb"))
> + o.indent(2) <<
> + stringForARMFormat((ARMFormat)getByteField(Def, "Form"));
> + else
> + o << " ARM_FORMAT_NA";
> +
> + o << ",\t// Inst #" << i << " = " << Name << '\n';
> + }
> + o << " ARM_FORMAT_NA\t// Unreachable.\n";
> + o << "};\n\n";
> +
> + // And emit code that references the NSFormat data type.
> + // This is meaningful only for NEONFrm instructions.
> + o << "static const NSFormat NSFormats[] = {\n";
> + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) {
> + const Record &Def = *(AllInstructions[i]->TheDef);
> + const std::string &Name = Def.getName();
> + if (Def.isSubClassOf("NeonI") || Def.isSubClassOf("NeonXI"))
> + o.indent(2) <<
> + stringForNSFormat((NSFormat)getByteField(Def, "NSForm"));
> + else
> + o << " NS_FORMAT_NA";
> +
> + o << ",\t// Inst #" << i << " = " << Name << '\n';
> + }
> + o << " NS_FORMAT_NA\t// Unreachable.\n";
> + o << "};\n\n";
> + }
> + }
> +
> + // Emit the top level typedef and decodeInstruction() function.
> + void emitTop(raw_ostream &o, Indenter &i) {
> +
> + // Run the target specific emit hook.
> + emitTopHook(o, i);
> +
> + switch(tBitWidth) {
> + case 8:
> + o.indent(i) << "typedef uint8_t field_t;\n";
> + break;
> + case 16:
> + o.indent(i) << "typedef uint16_t field_t;\n";
> + break;
> + case 32:
> + o.indent(i) << "typedef uint32_t field_t;\n";
> + break;
> + case 64:
> + o.indent(i) << "typedef uint64_t field_t;\n";
> + break;
> + default:
> + assert(0 && "Unexpected instruction size!");
> + }
> +
> + o << '\n';
> +
> + o.indent(i) << "static field_t " <<
> + "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n";
> +
> + o.indent(i) << "{\n";
> + i.push();
> + {
> + o.indent(i) << "assert(startBit + numBits <= " << tBitWidth
> + << " && \"Instruction field out of bounds!\");\n";
> + o << '\n';
> + o.indent(i) << "field_t fieldMask;\n";
> + o << '\n';
> + o.indent(i) << "if (numBits == " << tBitWidth << ")\n";
> +
> + i.push();
> + {
> + o.indent(i) << "fieldMask = (field_t)-1;\n";
> + }
> + i.pop();
> +
> + o.indent(i) << "else\n";
> +
> + i.push();
> + {
> + o.indent(i) << "fieldMask = ((1 << numBits) - 1) << startBit;\n";
> + }
> + i.pop();
> +
> + o << '\n';
> + o.indent(i) << "return (insn & fieldMask) >> startBit;\n";
> + }
> + i.pop();
> + o.indent(i) << "}\n";
> +
> + o << '\n';
> +
> + o.indent(i) << "static uint16_t decodeInstruction(field_t insn) {\n";
> +
> + i.push();
> + {
> + // Emits code to decode the instructions.
> + emit(o, i);
> +
> + o << '\n';
> + o.indent(i) << "return 0;\n";
> + }
> + i.pop();
> +
> + o.indent(i) << "}\n";
> +
> + o << '\n';
> +
> + }
> +
> + // This provides an opportunity for target specific code emission after
> + // emitTop().
> + void emitBot(raw_ostream &o, Indenter &i) {
> + if (TargetName == TARGET_THUMB) {
> + // Emit code that decodes the Thumb ISA.
> + o.indent(i)
> + << "static uint16_t decodeThumbInstruction(field_t insn) {\n";
> +
> + i.push();
> + {
> + // Emits code to decode the instructions.
> + emit(o, i);
> +
> + o << '\n';
> + o.indent(i) << "return 0;\n";
> + }
> + i.pop();
> +
> + o.indent(i) << "}\n";
> + }
> + }
> +
> +protected:
> + // Populates the insn given the uid.
> + void insnWithID(insn_t &Insn, unsigned Opcode) const {
> + assert(Opcode > 10);
> + BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst");
> +
> + for (unsigned i = 0; i < tBitWidth; ++i)
> + Insn[i] = bitFromBits(Bits, i);
> + }
> +
> + // Returns the record name.
> + const std::string &nameWithID(unsigned Opcode) const {
> + return AllInstructions[Opcode]->TheDef->getName();
> + }
> +
> + // Populates the field of the insn given the start position and the number of
> + // consecutive bits to scan for.
> + //
> + // Returns false if and on the first uninitialized bit value encountered.
> + // Returns true, otherwise.
> + const bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit,
> + unsigned NumBits) const {
> + Field = 0;
> +
> + for (unsigned i = 0; i < NumBits; ++i) {
> + if (Insn[StartBit + i] == BIT_UNSET)
> + return false;
> +
> + if (Insn[StartBit + i] == BIT_TRUE)
> + Field = Field | (1 << i);
> + }
> +
> + return true;
> + }
> +
> + void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[tBitWidth]) {
> + unsigned bitIndex;
> +
> + for (bitIndex = tBitWidth; bitIndex > 0; bitIndex--) {
> + switch (filter[bitIndex - 1]) {
> + case BIT_UNFILTERED:
> + o << ".";
> + break;
> + case BIT_UNSET:
> + o << "_";
> + break;
> + case BIT_TRUE:
> + o << "1";
> + break;
> + case BIT_FALSE:
> + o << "0";
> + break;
> + }
> + }
> + }
> +
> + void dumpStack(raw_ostream &o, const char *prefix) {
> + FilterChooser *current = this;
> +
> + while (current) {
> + o << prefix;
> +
> + dumpFilterArray(o, current->FilterBitValues);
> +
> + o << '\n';
> +
> + current = current->Parent;
> + }
> + }
> +
> + Filter &bestFilter() {
> + assert(BestIndex != -1 && "BestIndex not set");
> + return Filters[BestIndex];
> + }
> +
> + // States of our finite state machines.
> + typedef enum {
> + ATTR_NONE,
> + ATTR_FILTERED,
> + ATTR_ALL_SET,
> + ATTR_ALL_UNSET,
> + ATTR_MIXED
> + } bitAttr_t;
> +
> + // Called from Filter::recurse() when singleton exists. For debug purpose.
> + void SingletonExists(unsigned Opc) {
> +
> + insn_t Insn0;
> + insnWithID(Insn0, Opc);
> +
> + errs() << "Singleton exists: " << nameWithID(Opc)
> + << " with its decoding dominating ";
> + for (unsigned i = 0; i < Opcodes.size(); ++i) {
> + if (Opcodes[i] == Opc) continue;
> + errs() << nameWithID(Opcodes[i]) << ' ';
> + }
> + errs() << '\n';
> +
> + dumpStack(errs(), "\t\t");
> + for (unsigned i = 0; i < Opcodes.size(); i++) {
> + const std::string &Name = nameWithID(Opcodes[i]);
> +
> + errs() << '\t' << Name << " ";
> + dumpBits(errs(),
> + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
> + errs() << '\n';
> + }
> + }
> +
> + bool ValueSet(bit_value_t V) {
> + return (V == BIT_TRUE || V == BIT_FALSE);
> + }
> + bool ValueNotSet(bit_value_t V) {
> + return (V == BIT_UNSET);
> + }
> + int Value(bit_value_t V) {
> + return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1);
> + }
> + bool PositionFiltered(unsigned i) {
> + return ValueSet(FilterBitValues[i]);
> + }
> +
> + // Calculates the island(s) needed to decode the instruction.
> + unsigned getIslands(std::vector<unsigned> &StartBits,
> + std::vector<unsigned> &EndBits,
> + std::vector<uint64_t> &FieldVals, insn_t &Insn)
> + {
> + unsigned Num, BitNo;
> + Num = BitNo = 0;
> +
> + uint64_t FieldVal = 0;
> +
> + // 0: Init
> + // 1: Water
> + // 2: Island
> + int State = 0;
> + int Val = -1;
> +
> + for (unsigned i = 0; i < tBitWidth; ++i) {
> + Val = Value(Insn[i]);
> + bool Filtered = PositionFiltered(i);
> + switch (State) {
> + default:
> + assert(0 && "Unreachable code!");
> + break;
> + case 0:
> + case 1:
> + if (Filtered || Val == -1)
> + State = 1; // Still in Water
> + else {
> + State = 2; // Into the Island
> + BitNo = 0;
> + StartBits.push_back(i);
> + FieldVal = Val;
> + }
> + break;
> + case 2:
> + if (Filtered || Val == -1) {
> + State = 1; // Into the Water
> + EndBits.push_back(i - 1);
> + FieldVals.push_back(FieldVal);
> + ++Num;
> + } else {
> + State = 2; // Still in Island
> + ++BitNo;
> + FieldVal = FieldVal | Val << BitNo;
> + }
> + break;
> + }
> + }
> + // If we are still in Island after the loop, do some housekeeping.
> + if (State == 2) {
> + EndBits.push_back(tBitWidth - 1);
> + FieldVals.push_back(FieldVal);
> + ++Num;
> + }
> +
> + /*
> + printf("StartBits.size()=%u,EndBits.size()=%u,FieldVals.size()=%u,Num=%u\n",
> + (unsigned)StartBits.size(), (unsigned)EndBits.size(),
> + (unsigned)FieldVals.size(), Num);
> + */
> +
> + assert(StartBits.size() == Num && EndBits.size() == Num &&
> + FieldVals.size() == Num);
> +
> + return Num;
> + }
> +
> + bool LdStCopEncoding1(unsigned Opc) {
> + const std::string &Name = nameWithID(Opc);
> + if (Name == "LDC_OFFSET" || Name == "LDC_OPTION" ||
> + Name == "LDC_POST" || Name == "LDC_PRE" ||
> + Name == "LDCL_OFFSET" || Name == "LDCL_OPTION" ||
> + Name == "LDCL_POST" || Name == "LDCL_PRE" ||
> + Name == "STC_OFFSET" || Name == "STC_OPTION" ||
> + Name == "STC_POST" || Name == "STC_PRE" ||
> + Name == "STCL_OFFSET" || Name == "STCL_OPTION" ||
> + Name == "STCL_POST" || Name == "STCL_PRE")
> + return true;
> + else
> + return false;
> + }
> +
> + // Emits code to decode the singleton. Return true if we have matched all the
> + // well-known bits.
> + bool emitSingletonDecoder(raw_ostream &o, Indenter &i, unsigned Opc) {
> +
> + std::vector<unsigned> StartBits;
> + std::vector<unsigned> EndBits;
> + std::vector<uint64_t> FieldVals;
> + insn_t Insn;
> + insnWithID(Insn, Opc);
> +
> + if (TargetName == TARGET_ARM && LdStCopEncoding1(Opc)) {
> + o.indent(i);
> + // A8.6.51 & A8.6.188
> + // If coproc = 0b101?, i.e, slice(insn, 11, 8) = 10 or 11, escape.
> + o << "if (fieldFromInstruction(insn, 9, 3) == 5) break; // fallthrough\n";
> + }
> +
> + // Look for islands of undecoded bits of the singleton.
> + getIslands(StartBits, EndBits, FieldVals, Insn);
> +
> + unsigned Size = StartBits.size();
> + unsigned I, NumBits;
> +
> + // If we have matched all the well-known bits, just issue a return.
> + if (Size == 0) {
> + o.indent(i) << "return " << Opc << "; // " << nameWithID(Opc) << '\n';
> + return true;
> + }
> +
> + // Otherwise, there are more decodings to be done!
> +
> + // Emit code to match the island(s) for the singleton.
> + o.indent(i) << "// Check ";
> +
> + for (I = Size; I != 0; --I) {
> + o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} ";
> + if (I > 1)
> + o << "&& ";
> + else
> + o << "for singleton decoding...\n";
> + }
> +
> + o.indent(i) << "if (";
> +
> + for (I = Size; I != 0; --I) {
> + NumBits = EndBits[I-1] - StartBits[I-1] + 1;
> + o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits
> + << ") == " << FieldVals[I-1];
> + if (I > 1)
> + o << " && ";
> + else
> + o << ")\n";
> + }
> +
> + o.indent(i) << " return " << Opc << "; // " << nameWithID(Opc) << '\n';
> +
> + return false;
> + }
> +
> + // Emits code to decode the singleton, and then to decode the rest.
> + void emitSingletonDecoder(raw_ostream &o, Indenter &i, Filter & Best) {
> +
> + unsigned Opc = Best.getSingletonOpc();
> +
> + emitSingletonDecoder(o, i, Opc);
> +
> + // Emit code for the rest.
> + o.indent(i) << "else\n";
> + i.push();
> + {
> + Best.getVariableFC().emit(o, i);
> + }
> + i.pop();
> + }
> +
> + // Assign a single filter and run with it.
> + void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit,
> + bool mixed) {
> + Filters.clear();
> + Filter F(*this, startBit, numBit, true);
> + Filters.push_back(F);
> + BestIndex = 0; // Sole Filter instance to choose from.
> + bestFilter().recurse();
> + }
> +
> + bool filterProcessor(bool AllowMixed, bool Greedy = true) {
> + Filters.clear();
> + BestIndex = -1;
> + unsigned numInstructions = Opcodes.size();
> +
> + assert(numInstructions && "Filter created with no instructions");
> +
> + // No further filtering is necessary.
> + if (numInstructions == 1)
> + return true;
> +
> + // Heuristics. See also doFilter()'s "Heuristics" comment when num of
> + // instructions is 3.
> + if (AllowMixed && !Greedy) {
> + assert(numInstructions == 3);
> +
> + for (unsigned i = 0; i < Opcodes.size(); ++i) {
> + std::vector<unsigned> StartBits;
> + std::vector<unsigned> EndBits;
> + std::vector<uint64_t> FieldVals;
> + insn_t Insn;
> +
> + insnWithID(Insn, Opcodes[i]);
> +
> + // Look for islands of undecoded bits of any instruction.
> + if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) {
> + // Found an instruction with island(s). Now just assign a filter.
> + runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1,
> + true);
> + return true;
> + }
> + }
> + }
> +
> + unsigned bitIndex, insnIndex;
> +
> + // We maintain tBitWidth copies of the bitAttrs automaton.
> + // The automaton consumes the corresponding bit from each
> + // instruction.
> + //
> + // Input symbols: 0, 1, and _ (unset).
> + // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED.
> + // Initial state: NONE.
> + //
> + // (NONE) ------- [01] -> (ALL_SET)
> + // (NONE) ------- _ ----> (ALL_UNSET)
> + // (ALL_SET) ---- [01] -> (ALL_SET)
> + // (ALL_SET) ---- _ ----> (MIXED)
> + // (ALL_UNSET) -- [01] -> (MIXED)
> + // (ALL_UNSET) -- _ ----> (ALL_UNSET)
> + // (MIXED) ------ . ----> (MIXED)
> + // (FILTERED)---- . ----> (FILTERED)
> +
> + bitAttr_t bitAttrs[tBitWidth];
> +
> + // FILTERED bit positions provide no entropy and are not worthy of pursuing.
> + // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position.
> + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex)
> + if (FilterBitValues[bitIndex] == BIT_TRUE ||
> + FilterBitValues[bitIndex] == BIT_FALSE)
> + bitAttrs[bitIndex] = ATTR_FILTERED;
> + else
> + bitAttrs[bitIndex] = ATTR_NONE;
> +
> + for (insnIndex = 0; insnIndex < numInstructions; ++insnIndex) {
> + insn_t insn;
> +
> + insnWithID(insn, Opcodes[insnIndex]);
> +
> + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) {
> + switch (bitAttrs[bitIndex]) {
> + case ATTR_NONE:
> + if (insn[bitIndex] == BIT_UNSET)
> + bitAttrs[bitIndex] = ATTR_ALL_UNSET;
> + else
> + bitAttrs[bitIndex] = ATTR_ALL_SET;
> + break;
> + case ATTR_ALL_SET:
> + if (insn[bitIndex] == BIT_UNSET)
> + bitAttrs[bitIndex] = ATTR_MIXED;
> + break;
> + case ATTR_ALL_UNSET:
> + if (insn[bitIndex] != BIT_UNSET)
> + bitAttrs[bitIndex] = ATTR_MIXED;
> + break;
> + case ATTR_MIXED:
> + case ATTR_FILTERED:
> + break;
> + }
> + }
> + }
> +
> + // The regionAttr automaton consumes the bitAttrs automatons' state,
> + // lowest-to-highest.
> + //
> + // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed)
> + // States: NONE, ALL_SET, MIXED
> + // Initial state: NONE
> + //
> + // (NONE) ----- F --> (NONE)
> + // (NONE) ----- S --> (ALL_SET) ; and set region start
> + // (NONE) ----- U --> (NONE)
> + // (NONE) ----- M --> (MIXED) ; and set region start
> + // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region
> + // (ALL_SET) -- S --> (ALL_SET)
> + // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region
> + // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region
> + // (MIXED) ---- F --> (NONE) ; and report a MIXED region
> + // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region
> + // (MIXED) ---- U --> (NONE) ; and report a MIXED region
> + // (MIXED) ---- M --> (MIXED)
> +
> + bitAttr_t regionAttr = ATTR_NONE;
> + unsigned startBit = 0;
> +
> + for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++) {
> + bitAttr_t bitAttr = bitAttrs[bitIndex];
> +
> + assert(bitAttr != ATTR_NONE && "Bit without attributes");
> +
> +#define SET_START \
> + startBit = bitIndex;
> +
> +#define REPORT_REGION \
> + if (regionAttr == ATTR_MIXED && AllowMixed) \
> + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, true)); \
> + else if (regionAttr == ATTR_ALL_SET && !AllowMixed) \
> + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, false));
> +
> + switch (regionAttr) {
> + case ATTR_NONE:
> + switch (bitAttr) {
> + case ATTR_FILTERED:
> + break;
> + case ATTR_ALL_SET:
> + SET_START
> + regionAttr = ATTR_ALL_SET;
> + break;
> + case ATTR_ALL_UNSET:
> + break;
> + case ATTR_MIXED:
> + SET_START
> + regionAttr = ATTR_MIXED;
> + break;
> + default:
> + assert(0 && "Unexpected bitAttr!");
> + }
> + break;
> + case ATTR_ALL_SET:
> + switch (bitAttr) {
> + case ATTR_FILTERED:
> + REPORT_REGION
> + regionAttr = ATTR_NONE;
> + break;
> + case ATTR_ALL_SET:
> + break;
> + case ATTR_ALL_UNSET:
> + REPORT_REGION
> + regionAttr = ATTR_NONE;
> + break;
> + case ATTR_MIXED:
> + REPORT_REGION
> + SET_START
> + regionAttr = ATTR_MIXED;
> + break;
> + default:
> + assert(0 && "Unexpected bitAttr!");
> + }
> + break;
> + case ATTR_MIXED:
> + switch (bitAttr) {
> + case ATTR_FILTERED:
> + REPORT_REGION
> + SET_START
> + regionAttr = ATTR_NONE;
> + break;
> + case ATTR_ALL_SET:
> + REPORT_REGION
> + SET_START
> + regionAttr = ATTR_ALL_SET;
> + break;
> + case ATTR_ALL_UNSET:
> + REPORT_REGION
> + regionAttr = ATTR_NONE;
> + break;
> + case ATTR_MIXED:
> + break;
> + default:
> + assert(0 && "Unexpected bitAttr!");
> + }
> + break;
> + case ATTR_ALL_UNSET:
> + assert(0 && "regionAttr state machine has no ATTR_UNSET state");
> + case ATTR_FILTERED:
> + assert(0 && "regionAttr state machine has no ATTR_FILTERED state");
> + }
> + }
> +
> + // At the end, if we're still in ALL_SET or MIXED states, report a region
> +
> + switch (regionAttr) {
> + case ATTR_NONE:
> + break;
> + case ATTR_FILTERED:
> + break;
> + case ATTR_ALL_SET:
> + REPORT_REGION
> + break;
> + case ATTR_ALL_UNSET:
> + break;
> + case ATTR_MIXED:
> + REPORT_REGION
> + break;
> + }
> +
> +#undef SET_START
> +#undef REPORT_REGION
> +
> + // We have finished with the filter processings. Now it's time to choose
> + // the best performing filter.
> +
> + BestIndex = 0;
> + bool AllUseless = true;
> + unsigned BestScore = 0;
> +
> + for (unsigned i = 0, e = Filters.size(); i != e; ++i) {
> + unsigned Usefulness = Filters[i].usefulness();
> +
> + if (Usefulness)
> + AllUseless = false;
> +
> + if (Usefulness > BestScore) {
> + BestIndex = i;
> + BestScore = Usefulness;
> + }
> + }
> +
> + if (!AllUseless) {
> + bestFilter().recurse();
> + }
> +
> + return !AllUseless;
> + } // end of filterProcessor(bool)
> +
> + // Decides on the best configuration of filter(s) to use in order to decode
> + // the instructions. A conflict of instructions may occur, in which case we
> + // dump the conflict set to the standard error.
> + void doFilter() {
> + unsigned Num = Opcodes.size();
> + assert(Num && "FilterChooser created with no instructions");
> +
> + // Heuristics: Use Inst{31-28} as the top level filter for ARM ISA.
> + if (TargetName == TARGET_ARM && Parent == NULL) {
> + runSingleFilter(*this, 28, 4, false);
> + return;
> + }
> +
> + if (filterProcessor(false))
> + return;
> +
> + if (filterProcessor(true))
> + return;
> +
> + // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where
> + // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a
> + // well-known encoding pattern. In such case, we backtrack and scan for the
> + // the very first consecutive ATTR_ALL_SET region and assign a filter to it.
> + if (Num == 3 && filterProcessor(true, false))
> + return;
> +
> + // If we come to here, the instruction decoding has failed.
> + // Print out the instructions in the conflict set...
> +
> + BestIndex = -1;
> +
> + DEBUG({
> + errs() << "Conflict:\n";
> +
> + dumpStack(errs(), "\t\t");
> +
> + for (unsigned i = 0; i < Num; i++) {
> + const std::string &Name = nameWithID(Opcodes[i]);
> +
> + errs() << '\t' << Name << " ";
> + dumpBits(errs(),
> + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
> + errs() << '\n';
> + }
> + });
> + }
> +
> + // Emits code to decode our share of instructions. Returns true if the
> + // emitted code causes a return, which occurs if we know how to decode
> + // the instruction at this level or the instruction is not decodeable.
> + bool emit(raw_ostream &o, Indenter &i) {
> + if (Opcodes.size() == 1) {
> + // There is only one instruction in the set, which is great!
> + // Call emitSingletonDecoder() to see whether there are any remaining
> + // encodings bits.
> + return emitSingletonDecoder(o, i, Opcodes[0]);
> +
> + } else if (BestIndex == -1) {
> + if (TargetName == TARGET_ARM && Opcodes.size() == 2) {
> + // Resolve the known conflict sets:
> + //
> + // 1. source registers are identical => VMOVDneon; otherwise => VORRd
> + // 2. source registers are identical => VMOVQ; otherwise => VORRq
> + // 3. LDR, LDRcp => return LDR for now.
> + // FIXME: How can we distinguish between LDR and LDRcp? Do we need to?
> + // 4. VLD[234]LN*a/VST[234]LN*a vs. VLD[234]LN*b/VST[234]LN*b conflicts
> + // are resolved returning the 'a' versions of the instructions. Note
> + // that the difference between a/b is that the former is for double-
> + // spaced even registers while the latter is for double-spaced odd
> + // registers. This is for codegen instruction selection purpose.
> + // For disassembly, it does not matter.
> + const std::string &name1 = nameWithID(Opcodes[0]);
> + const std::string &name2 = nameWithID(Opcodes[1]);
> + if ((name1 == "VMOVDneon" && name2 == "VORRd") ||
> + (name1 == "VMOVQ" && name2 == "VORRq")) {
> + // Inserting the opening curly brace for this case block.
> + i.pop();
> + o.indent(i) << "{\n";
> + i.push();
> +
> + o.indent(i) << "field_t N = fieldFromInstruction(insn, 7, 1), "
> + << "M = fieldFromInstruction(insn, 5, 1);\n";
> + o.indent(i) << "field_t Vn = fieldFromInstruction(insn, 16, 4), "
> + << "Vm = fieldFromInstruction(insn, 0, 4);\n";
> + o.indent(i) << "return (N == M && Vn == Vm) ? "
> + << Opcodes[0] << " /* " << name1 << " */ : "
> + << Opcodes[1] << " /* " << name2 << " */ ;\n";
> +
> + // Inserting the closing curly brace for this case block.
> + i.pop();
> + o.indent(i) << "}\n";
> + i.push();
> +
> + return true;
> + }
> + if (name1 == "LDR" && name2 == "LDRcp") {
> + o.indent(i) << "return " << Opcodes[0]
> + << "; // Returning LDR for {LDR, LDRcp}\n";
> + return true;
> + }
> + if (sameStringExceptEndingChar(name1, name2, 'a', 'b')) {
> + o.indent(i) << "return " << Opcodes[0] << "; // Returning " << name1
> + << " for {" << name1 << ", " << name2 << "}\n";
> + return true;
> + }
> +
> + // Otherwise, it does not belong to the known conflict sets.
> + }
> + // We don't know how to decode these instructions! Dump the conflict set!
> + o.indent(i) << "return 0;" << " // Conflict set: ";
> + for (int i = 0, N = Opcodes.size(); i < N; ++i) {
> + o << nameWithID(Opcodes[i]);
> + if (i < (N - 1))
> + o << ", ";
> + else
> + o << '\n';
> + }
> + return true;
> + } else {
> + // Choose the best filter to do the decodings!
> + Filter &Best = bestFilter();
> + if (Best.getNumFiltered() == 1)
> + emitSingletonDecoder(o, i, Best);
> + else
> + bestFilter().emit(o, i);
> + return false;
> + }
> + }
> +};
> +
> +///////////////
> +// Backend //
> +///////////////
> +
> +class RISCDisassemblerEmitter::RISCDEBackend {
> +public:
> + RISCDEBackend(RISCDisassemblerEmitter &frontend) :
> + NumberedInstructions(),
> + Opcodes(),
> + Frontend(frontend),
> + Target(),
> + AFC(NULL)
> + {
> + populateInstructions();
> +
> + if (Target.getName() == "ARM") {
> + TargetName = TARGET_ARM;
> + } else {
> + errs() << "Target name " << Target.getName() << " not recognized\n";
> + assert(0 && "Unknown target");
> + }
> + }
> +
> + ~RISCDEBackend() {
> + if (AFC) {
> + delete AFC;
> + AFC = NULL;
> + }
> + }
> +
> + void getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
> + &NumberedInstructions) {
> + // Dig down to the proper namespace. Code shamelessly stolen from
> + // InstrEnumEmitter.cpp
> + std::string Namespace;
> + CodeGenTarget::inst_iterator II, E;
> +
> + for (II = Target.inst_begin(), E = Target.inst_end(); II != E; ++II)
> + if (II->second.Namespace != "TargetInstrInfo") {
> + Namespace = II->second.Namespace;
> + break;
> + }
> +
> + assert(!Namespace.empty() && "No instructions defined.");
> +
> + Target.getInstructionsByEnumValue(NumberedInstructions);
> + }
> +
> + bool populateInstruction(const CodeGenInstruction &CGI, TARGET_NAME_t TN) {
> + const Record &Def = *CGI.TheDef;
> + const std::string &Name = Def.getName();
> + uint8_t Form = getByteField(Def, "Form");
> + BitsInit &Bits = getBitsField(Def, "Inst");
> +
> + if (TN == TARGET_ARM) {
> + // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6?
> + if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") &&
> + Form == ARM_FORMAT_PSEUDO)
> + return false;
> + if (thumbInstruction(Form))
> + return false;
> + if (Name.find("CMPz") != std::string::npos /* ||
> + Name.find("CMNz") != std::string::npos */)
> + return false;
> +
> + // Ignore pseudo instructions.
> + if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9")
> + return false;
> +
> + // VLDRQ/VSTRQ can be hanlded with the more generic VLDMD/VSTMD.
> + if (Name == "VLDRQ" || Name == "VSTRQ")
> + return false;
> +
> + //
> + // The following special cases are for conflict resolutions.
> + //
> +
> + // RSCSri and RSCSrs set the 's' bit, but are not predicated. We are
> + // better off using the generic RSCri and RSCrs instructions.
> + if (Name == "RSCSri" || Name == "RSCSrs") return false;
> +
> + // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used
> + // in the compiler to implement conditional moves. We can ignore them in
> + // favor of their more generic versions of instructions.
> + // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op).
> + if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" ||
> + Name == "FCPYScc" || Name == "FCPYDcc" ||
> + Name == "FNEGScc" || Name == "FNEGDcc")
> + return false;
> +
> + // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc.
> + if (Name == "VMOVDcc" || Name == "VMOVScc" || Name == "VNEGDcc" ||
> + Name == "VNEGScc")
> + return false;
> +
> + // Ignore the *_sfp instructions when decoding. They are used by the
> + // compiler to implement scalar floating point operations using vector
> + // operations in order to work around some performance issues.
> + if (Name.find("_sfp") != std::string::npos) return false;
> +
> + // LLVM added LDM/STM_UPD which conflicts with LDM/STM.
> + // Ditto for VLDMS_UPD, VLDMD_UPD, VSTMS_UPD, VSTMD_UPD.
> + if (Name == "LDM_UPD" || Name == "STM_UPD" || Name == "VLDMS_UPD" ||
> + Name == "VLDMD_UPD" || Name == "VSTMS_UPD" || Name == "VSTMD_UPD")
> + return false;
> +
> + // LDM_RET is a special case of LDM (Load Multiple) where the registers
> + // loaded include the PC, causing a branch to a loaded address. Ignore
> + // the LDM_RET instruction when decoding.
> + if (Name == "LDM_RET") return false;
> +
> + // Bcc is in a more generic form than B. Ignore B when decoding.
> + if (Name == "B") return false;
> +
> + // Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction.
> + if (Name == "BL" || Name == "BL_pred" || Name == "BLX" || Name == "BX" ||
> + Name == "TPsoft")
> + return false;
> +
> + // Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for
> + // decoding. The instruction duplicates an element from an ARM core
> + // register into every element of the destination vector. There is no
> + // distinction between data types.
> + if (Name == "VDUPfd" || Name == "VDUPfq") return false;
> +
> + // A8-598: VEXT
> + // Vector Extract extracts elements from the bottom end of the second
> + // operand vector and the top end of the first, concatenates them and
> + // places the result in the destination vector. The elements of the
> + // vectors are treated as being 8-bit bitfields. There is no distinction
> + // between data types. The size of the operation can be specified in
> + // assembler as vext.size. If the value is 16, 32, or 64, the syntax is
> + // a pseudo-instruction for a VEXT instruction specifying the equivalent
> + // number of bytes.
> + //
> + // Variants VEXTd16, VEXTd32, VEXTd8, and VEXTdf are reduced to VEXTd8;
> + // variants VEXTq16, VEXTq32, VEXTq8, and VEXTqf are reduced to VEXTq8.
> + if (Name == "VEXTd16" || Name == "VEXTd32" || Name == "VEXTdf" ||
> + Name == "VEXTq16" || Name == "VEXTq32" || Name == "VEXTqf")
> + return false;
> +
> + // Vector Reverse is similar to Vector Extract. There is no distinction
> + // between data types, other than size.
> + //
> + // VREV64df is equivalent to VREV64d32.
> + // VREV64qf is equivalent to VREV64q32.
> + if (Name == "VREV64df" || Name == "VREV64qf") return false;
> +
> + // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d.
> + // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q.
> + // VLD1df is equivalent to VLD1d32.
> + // VLD1qf is equivalent to VLD1q32.
> + // VLD2d64 is equivalent to VLD1q64.
> + // VST1df is equivalent to VST1d32.
> + // VST1qf is equivalent to VST1q32.
> + // VST2d64 is equivalent to VST1q64.
> + if (Name == "VDUPLNfd" || Name == "VDUPfdf" ||
> + Name == "VDUPLNfq" || Name == "VDUPfqf" ||
> + Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" ||
> + Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64")
> + return false;
> + } else if (TN == TARGET_THUMB) {
> + if (!thumbInstruction(Form))
> + return false;
> +
> + // Ignore pseudo instructions.
> + if (Name == "tInt_eh_sjlj_setjmp" || Name == "t2Int_eh_sjlj_setjmp" ||
> + Name == "t2MOVi32imm" || Name == "tBX" || Name == "tBXr9")
> + return false;
> +
> + // LLVM added tLDM_UPD which conflicts with tLDM.
> + if (Name == "tLDM_UPD")
> + return false;
> +
> + // On Darwin R9 is call-clobbered. Ignore the non-Darwin counterparts.
> + if (Name == "tBL" || Name == "tBLXi" || Name == "tBLXr")
> + return false;
> +
> + // Ignore the TPsoft (TLS) instructions, which conflict with tBLr9.
> + if (Name == "tTPsoft" || Name == "t2TPsoft")
> + return false;
> +
> + // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi.
> + if (Name == "tLEApcrel" || Name == "tLEApcrelJT")
> + return false;
> +
> + // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing.
> + if (Name == "t2LEApcrel")
> + return false;
> +
> + // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr.
> + // Ignore t2SUBrSPs, prefer the t2SUB[S]r[r|s].
> + // Ignore t2ADDrSPs, prefer the t2ADD[S]r[r|s].
> + if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" ||
> + Name == "t2SUBrSPs" || Name == "t2ADDrSPs")
> + return false;
> +
> + // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST.
> + if (Name == "t2LDRDpci")
> + return false;
> +
> + // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen.
> + if (Name == "t2TBB" || Name == "t2TBH")
> + return false;
> +
> + // Resolve conflicts:
> + //
> + // tBfar conflicts with tBLr9
> + // tCMNz conflicts with tCMN (with assembly format strings being equal)
> + // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto)
> + // tMOVCCi conflicts with tMOVi8
> + // tMOVCCr conflicts with tMOVgpr2gpr
> + // tBR_JTr conflicts with tBRIND
> + // tSpill conflicts with tSTRspi
> + // tLDRcp conflicts with tLDRspi
> + // tRestore conflicts with tLDRspi
> + // t2LEApcrelJT conflicts with t2LEApcrel
> + // t2ADDrSPi/t2SUBrSPi have more generic couterparts
> + if (Name == "tBfar" ||
> + /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" ||
> + Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" ||
> + Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" ||
> + Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" ||
> + Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" ||
> + Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" ||
> + Name == "t2LEApcrelJT" || Name == "t2ADDrSPi" || Name == "t2SUBrSPi")
> + return false;
> + }
> +
> + // Dumps the instruction encoding format.
> + switch (TargetName) {
> + case TARGET_ARM:
> + case TARGET_THUMB:
> + DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form));
> + break;
> + }
> +
> + DEBUG({
> + errs() << " ";
> +
> + // Dumps the instruction encoding bits.
> + dumpBits(errs(), Bits);
> +
> + errs() << '\n';
> +
> + // Dumps the list of operand info.
> + for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
> + CodeGenInstruction::OperandInfo Info = CGI.OperandList[i];
> + const std::string &OperandName = Info.Name;
> + const Record &OperandDef = *Info.Rec;
> +
> + errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n";
> + }
> + });
> +
> + return true;
> + }
> +
> + void populateInstructions() {
> + getInstructionsByEnumValue(NumberedInstructions);
> +
> + uint16_t numUIDs = NumberedInstructions.size();
> + uint16_t uid;
> +
> + const char *instClass = NULL;
> +
> + switch (TargetName) {
> + case TARGET_ARM:
> + instClass = "InstARM";
> + break;
> + default:
> + assert(0 && "Unreachable code!");
> + }
> +
> + for (uid = 0; uid < numUIDs; uid++) {
> + // filter out intrinsics
> + if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass))
> + continue;
> +
> + if (populateInstruction(*NumberedInstructions[uid], TargetName))
> + Opcodes.push_back(uid);
> + }
> +
> + // Special handling for the ARM chip, which supports two modes of execution.
> + // This branch handles the Thumb opcodes.
> + if (TargetName == TARGET_ARM) {
> + for (uid = 0; uid < numUIDs; uid++) {
> + // filter out intrinsics
> + if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM")
> + && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb"))
> + continue;
> +
> + if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB))
> + Opcodes2.push_back(uid);
> + }
> + }
> + }
> +
> + // Emits disassembler code for instruction decoding. This delegates to the
> + // FilterChooser instance to do the heavy lifting.
> + void emit(raw_ostream &o) {
> + Indenter i;
> + std::string s;
> + raw_string_ostream ro(s);
> +
> + switch (TargetName) {
> + case TARGET_ARM:
> + Frontend.EmitSourceFileHeader("ARM Disassembler", ro);
> + break;
> + default:
> + assert(0 && "Unreachable code!");
> + }
> +
> + ro.flush();
> + o << s;
> +
> + o.indent(i) << "#include <inttypes.h>\n";
> + o.indent(i) << "#include <assert.h>\n";
> + o << '\n';
> + o << "namespace llvm {\n\n";
> +
> + AbstractFilterChooser::setTargetName(TargetName);
> +
> + switch (TargetName) {
> + case TARGET_ARM: {
> + // Emit common utility and ARM ISA decoder.
> + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes);
> + AFC->emitTop(o, i);
> + delete AFC;
> +
> + // Emit Thumb ISA decoder as well.
> + AbstractFilterChooser::setTargetName(TARGET_THUMB);
> + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes2);
> + AFC->emitBot(o, i);
> + break;
> + }
> + default:
> + assert(0 && "Unreachable code!");
> + }
> +
> + o << "\n} // End llvm namespace \n";
> + }
> +
> +protected:
> + std::vector<const CodeGenInstruction*> NumberedInstructions;
> + std::vector<unsigned> Opcodes;
> + // Special case for the ARM chip, which supports ARM and Thumb ISAs.
> + // Opcodes2 will be populated with the Thumb opcodes.
> + std::vector<unsigned> Opcodes2;
> + RISCDisassemblerEmitter &Frontend;
> + CodeGenTarget Target;
> + AbstractFilterChooser *AFC;
> +
> + TARGET_NAME_t TargetName;
> +};
> +
> +/////////////////////////
> +// Backend interface //
> +/////////////////////////
> +
> +void RISCDisassemblerEmitter::initBackend()
> +{
> + Backend = new RISCDEBackend(*this);
> +}
> +
> +void RISCDisassemblerEmitter::run(raw_ostream &o)
> +{
> + Backend->emit(o);
> +}
> +
> +void RISCDisassemblerEmitter::shutdownBackend()
> +{
> + delete Backend;
> + Backend = NULL;
> +}
>
> Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h?rev=98637&view=auto
> ==============================================================================
> --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h (added)
> +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h Tue Mar 16 11:36:54 2010
> @@ -0,0 +1,48 @@
> +//===- RISCDisassemblerEmitter.h - Disassembler Generator -------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// FIXME: document
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef RISCDISASSEMBLEREMITTER_H
> +#define RISCDISASSEMBLEREMITTER_H
> +
> +#include "TableGenBackend.h"
> +
> +#include <inttypes.h>
> +
> +namespace llvm {
> +
> +class RISCDisassemblerEmitter : public TableGenBackend {
> + RecordKeeper &Records;
> +public:
> + RISCDisassemblerEmitter(RecordKeeper &R) : Records(R) {
> + initBackend();
> + }
> +
> + ~RISCDisassemblerEmitter() {
> + shutdownBackend();
> + }
> +
> + // run - Output the code emitter
> + void run(raw_ostream &o);
> +
> +private:
> + class RISCDEBackend;
> +
> + RISCDEBackend *Backend;
> +
> + void initBackend();
> + void shutdownBackend();
> +};
> +
> +} // end llvm namespace
> +
> +#endif
>
> Modified: llvm/trunk/utils/TableGen/TableGen.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGen.cpp?rev=98637&r1=98636&r2=98637&view=diff
> ==============================================================================
> --- llvm/trunk/utils/TableGen/TableGen.cpp (original)
> +++ llvm/trunk/utils/TableGen/TableGen.cpp Tue Mar 16 11:36:54 2010
> @@ -31,6 +31,7 @@
> #include "OptParserEmitter.h"
> #include "Record.h"
> #include "RegisterInfoEmitter.h"
> +#include "RISCDisassemblerEmitter.h"
> #include "SubtargetEmitter.h"
> #include "TGParser.h"
> #include "llvm/Support/CommandLine.h"
> @@ -48,6 +49,7 @@
> GenEmitter,
> GenRegisterEnums, GenRegister, GenRegisterHeader,
> GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher,
> + GenRISCDisassembler,
> GenDisassembler,
> GenCallingConv,
> GenClangDiagsDefs,
> @@ -84,6 +86,9 @@
> "Generate calling convention descriptions"),
> clEnumValN(GenAsmWriter, "gen-asm-writer",
> "Generate assembly writer"),
> + clEnumValN(GenRISCDisassembler, "gen-risc-disassembler",
> + "Generate disassembler for fixed instruction"
> + " length"),
> clEnumValN(GenDisassembler, "gen-disassembler",
> "Generate disassembler"),
> clEnumValN(GenAsmMatcher, "gen-asm-matcher",
> @@ -229,6 +234,9 @@
> case GenAsmWriter:
> AsmWriterEmitter(Records).run(*Out);
> break;
> + case GenRISCDisassembler:
> + RISCDisassemblerEmitter(Records).run(*Out);
> + break;
> case GenAsmMatcher:
> AsmMatcherEmitter(Records).run(*Out);
> break;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list