From 49d9dc4dd205b615beb7af160ef974eaabe4d1cf Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Tue, 16 Mar 2010 16:59:47 +0000 Subject: [PATCH] --- Reverse-merging r98637 into '.': U test/CodeGen/ARM/tls2.ll U test/CodeGen/ARM/arm-negative-stride.ll U test/CodeGen/ARM/2009-10-30.ll U test/CodeGen/ARM/globals.ll U test/CodeGen/ARM/str_pre-2.ll U test/CodeGen/ARM/ldrd.ll U test/CodeGen/ARM/2009-10-27-double-align.ll U test/CodeGen/Thumb2/thumb2-strb.ll U test/CodeGen/Thumb2/ldr-str-imm12.ll U test/CodeGen/Thumb2/thumb2-strh.ll U test/CodeGen/Thumb2/thumb2-ldr.ll U test/CodeGen/Thumb2/thumb2-str_pre.ll U test/CodeGen/Thumb2/thumb2-str.ll U test/CodeGen/Thumb2/thumb2-ldrh.ll U utils/TableGen/TableGen.cpp U utils/TableGen/DisassemblerEmitter.cpp D utils/TableGen/RISCDisassemblerEmitter.h D utils/TableGen/RISCDisassemblerEmitter.cpp U Makefile.rules U lib/Target/ARM/ARMInstrNEON.td U lib/Target/ARM/Makefile U lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp U lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp U lib/Target/ARM/AsmPrinter/ARMInstPrinter.h D lib/Target/ARM/Disassembler U lib/Target/ARM/ARMInstrFormats.td U lib/Target/ARM/ARMAddressingModes.h U lib/Target/ARM/Thumb2ITBlockPass.cpp git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98640 91177308-0d34-0410-b5e6-96231b3b80d8 --- Makefile.rules | 5 - lib/Target/ARM/ARMAddressingModes.h | 20 +- lib/Target/ARM/ARMInstrFormats.td | 43 - lib/Target/ARM/ARMInstrNEON.td | 493 +-- lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp | 46 +- lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp | 433 +-- lib/Target/ARM/AsmPrinter/ARMInstPrinter.h | 40 +- .../ARM/Disassembler/ARMDisassembler.cpp | 513 --- lib/Target/ARM/Disassembler/ARMDisassembler.h | 71 - .../ARM/Disassembler/ARMDisassemblerCore.cpp | 3351 ----------------- .../ARM/Disassembler/ARMDisassemblerCore.h | 301 -- lib/Target/ARM/Disassembler/Makefile | 17 - .../ThumbDisassemblerCore.cpp.inc | 2158 ----------- lib/Target/ARM/Makefile | 5 +- lib/Target/ARM/Thumb2ITBlockPass.cpp | 8 +- test/CodeGen/ARM/2009-10-27-double-align.ll | 4 +- test/CodeGen/ARM/2009-10-30.ll | 2 +- test/CodeGen/ARM/arm-negative-stride.ll | 2 +- test/CodeGen/ARM/globals.ll | 4 +- test/CodeGen/ARM/ldrd.ll | 4 +- test/CodeGen/ARM/str_pre-2.ll | 2 +- test/CodeGen/ARM/tls2.ll | 4 +- test/CodeGen/Thumb2/ldr-str-imm12.ll | 8 +- test/CodeGen/Thumb2/thumb2-ldr.ll | 2 +- test/CodeGen/Thumb2/thumb2-ldrh.ll | 2 +- test/CodeGen/Thumb2/thumb2-str.ll | 2 +- test/CodeGen/Thumb2/thumb2-str_pre.ll | 4 +- test/CodeGen/Thumb2/thumb2-strb.ll | 2 +- test/CodeGen/Thumb2/thumb2-strh.ll | 2 +- utils/TableGen/DisassemblerEmitter.cpp | 8 - utils/TableGen/RISCDisassemblerEmitter.cpp | 1743 --------- utils/TableGen/RISCDisassemblerEmitter.h | 48 - utils/TableGen/TableGen.cpp | 8 - 33 files changed, 167 insertions(+), 9188 deletions(-) delete mode 100644 lib/Target/ARM/Disassembler/ARMDisassembler.cpp delete mode 100644 lib/Target/ARM/Disassembler/ARMDisassembler.h delete mode 100644 lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp delete mode 100644 lib/Target/ARM/Disassembler/ARMDisassemblerCore.h delete mode 100644 lib/Target/ARM/Disassembler/Makefile delete mode 100644 lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc delete mode 100644 utils/TableGen/RISCDisassemblerEmitter.cpp delete mode 100644 utils/TableGen/RISCDisassemblerEmitter.h diff --git a/Makefile.rules b/Makefile.rules index 1e3194f78e5..20e642a4505 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -1614,11 +1614,6 @@ $(ObjDir)/%GenIntrinsics.inc.tmp : %.td $(ObjDir)/.dir $(Echo) "Building $(> 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 @@ -197,7 +179,7 @@ namespace ARM_AM { // of zero. if ((Arg & ~255U) == 0) return Arg; - unsigned RotAmt = getSOImmValOneRotate(Arg); + unsigned RotAmt = getSOImmValRotate(Arg); // If this cannot be handled with a single shifter_op, bail out. if (rotr32(~255U, RotAmt) & Arg) diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 52553f5477d..258a96b9216 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1464,29 +1464,6 @@ class AVConv5I opcod1, bits<4> opcod2, dag oops, dag iops, // 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 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 pattern> : InstARM { @@ -1497,8 +1474,6 @@ class NeonI 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. @@ -1510,8 +1485,6 @@ class NeonXI Predicates = [HasNEON]; - NSFormat NSF = NSFormatNone; // For disassembly. - bits<5> NSForm = NSFormatNone.Value; // For disassembly. } class NI pattern> : NeonXI { - let NSF = VLDSTRQFrm; // For disassembly. - let NSForm = VLDSTRQFrm.Value; // For disassembly. } class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, @@ -1538,8 +1509,6 @@ class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, 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 op21_19, bits<4> op11_8, bit op7, bit op6, 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. @@ -1586,8 +1553,6 @@ class N2V op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, 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. @@ -1603,8 +1568,6 @@ class N2VX op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, 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. @@ -1618,8 +1581,6 @@ class N2VImm op11_8, bit op7, bit op6, bit op4, 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. @@ -1633,8 +1594,6 @@ class N3V op21_20, bits<4> op11_8, bit op6, bit op4, 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. @@ -1648,8 +1607,6 @@ class N3VX op21_20, bits<4> op11_8, bit op6, bit op4 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. diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index da2babf05da..8fee6fa9527 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -213,10 +213,7 @@ def VLD2q32 : VLD2Q<0b1000, "vld2", "32">; class VLD2Ddbl 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", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; @@ -231,10 +228,7 @@ class VLD3WB op7_4, string OpcodeStr, string Dt> : 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", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD3d8 : VLD3D<0b0000, "vld3", "8">; def VLD3d16 : VLD3D<0b0100, "vld3", "16">; @@ -266,10 +260,7 @@ class VLD4WB op7_4, string OpcodeStr, string Dt> (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", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD4d8 : VLD4D<0b0000, "vld4", "8">; def VLD4d16 : VLD4D<0b0100, "vld4", "16">; @@ -306,28 +297,12 @@ def VLD2LNd16 : VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 0; } 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; - 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. -} +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // vld2 to double-spaced odd registers. -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. -} +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, string OpcodeStr, string Dt> @@ -343,11 +318,7 @@ def VLD3LNd16 : VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b00; } 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; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } // vld3 to double-spaced odd registers. @@ -369,28 +340,12 @@ def VLD4LNd16 : VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 0; } 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; - 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. -} +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // vld4 to double-spaced odd registers. -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. -} +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // VLD1DUP : Vector Load (single element to all lanes) // VLD2DUP : Vector Load (single 2-element structure to all lanes) @@ -478,10 +433,7 @@ def VST2q32 : VST2Q<0b1000, "vst2", "32">; class VST2Ddbl 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", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; @@ -496,10 +448,7 @@ class VST3WB op7_4, string OpcodeStr, string Dt> : 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", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST3d8 : VST3D<0b0000, "vst3", "8">; def VST3d16 : VST3D<0b0100, "vst3", "16">; @@ -529,10 +478,7 @@ class VST4WB op7_4, string OpcodeStr, string Dt> : 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", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST4d8 : VST4D<0b0000, "vst4", "8">; def VST4d16 : VST4D<0b0100, "vst4", "16">; @@ -569,28 +515,12 @@ def VST2LNd16 : VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 0; } 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; - 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. -} +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // vst2 to double-spaced odd registers. -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. -} +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, string OpcodeStr, string Dt> @@ -605,28 +535,12 @@ def VST3LNd16 : VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b00; } 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; - 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. -} +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // vst3 to double-spaced odd registers. -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. -} +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, string OpcodeStr, string Dt> @@ -642,28 +556,12 @@ def VST4LNd16 : VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 0; } 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; - 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. -} +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } // vst4 to double-spaced odd registers. -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. -} +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } } // mayStore = 1, hasExtraSrcRegAllocReq = 1 @@ -770,18 +668,12 @@ class N2VDShuffle op19_18, bits<5> op11_7, string OpcodeStr, string Dt> : 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", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; class N2VQShuffle 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", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; // Basic 3-register operations: single-, double- and quad-register. class N3VS op21_20, bits<4> op11_8, bit op4, @@ -823,8 +715,6 @@ class N3VDSL op21_20, bits<4> op11_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 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> @@ -835,8 +725,6 @@ class N3VDSL16 op21_20, bits<4> op11_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 op21_20, bits<4> op11_8, bit op4, @@ -868,8 +756,6 @@ class N3VQSL op21_20, bits<4> op11_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 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> @@ -881,8 +767,6 @@ class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, (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. @@ -905,8 +789,6 @@ class N3VDIntSL op21_20, bits<4> op11_8, InstrItinClass itin, (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> @@ -918,8 +800,6 @@ class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQInt op21_20, bits<4> op11_8, bit op4, @@ -942,8 +822,6 @@ class N3VQIntSL op21_20, bits<4> op11_8, InstrItinClass itin, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, @@ -956,8 +834,6 @@ class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, (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. @@ -988,10 +864,7 @@ class N3VDMulOpSL op21_20, bits<4> op11_8, InstrItinClass itin, (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> @@ -1003,10 +876,7 @@ class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, @@ -1027,10 +897,7 @@ class N3VQMulOpSL op21_20, bits<4> op11_8, InstrItinClass itin, (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, @@ -1043,10 +910,7 @@ class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -1132,10 +996,7 @@ class N3VLIntSL op21_20, bits<4> op11_8, InstrItinClass itin, [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1145,10 +1006,7 @@ class N3VLIntSL16 op21_20, bits<4> op11_8, [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_8:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; // Wide 3-register intrinsics. class N3VWInt op21_20, bits<4> op11_8, bit op4, @@ -1197,10 +1055,6 @@ class N2VQPLInt2 op24_23, bits<2> op21_20, bits<2> op19_18, 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 op11_8, bit op7, bit op4, @@ -1218,6 +1072,16 @@ class N2VQSh op11_8, bit op7, bit op4, OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; +// Long shift by immediate. +class N2VLSh op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm; + // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1260,26 +1124,8 @@ class N2VQShIns op11_8, bit op7, bit op4, 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 op11_8, bit op7, bit op6, bit op4, - string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm { - // 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 op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1294,7 +1140,6 @@ class N2VCvtQ op11_8, bit op7, bit op4, (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 @@ -1505,60 +1350,6 @@ multiclass N3VInt_QHSD op11_8, bit op4, 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 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; - def v2i32 : N3VDInt; - - // 128-bit vector types. - def v8i16 : N3VQInt; - def v4i32 : N3VQInt; -} -multiclass N3VInt_QHS2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_HS2 { - def v8i8 : N3VDInt; - def v16i8 : N3VQInt; -} -multiclass N3VInt_QHSD2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_QHS2 { - def v1i64 : N3VDInt; - def v2i64 : N3VQInt; -} -} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1828,47 +1619,6 @@ multiclass N2VSh_QHSD op11_8, bit op4, // 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 op11_8, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - SDNode OpNode> { - // 64-bit vector types. - def v8i8 : N2VDSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDSh; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQSh; - // imm6 = xxxxxx -} -} // Neon Shift-Accumulate vector operations, // element sizes of 8, 16, 32 and 64 bits: @@ -1949,47 +1699,6 @@ multiclass N2VShIns_QHSD op11_8, bit op4, // 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 op11_8, bit op4, - string OpcodeStr, SDNode ShOp> { - // 64-bit vector types. - def v8i8 : N2VDShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDShIns; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQShIns; - // imm6 = xxxxxx -} -} - // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, @@ -2620,21 +2329,18 @@ def VRSQRTSfq : N3VQInt<0, 0, 0b10, 0b1111, 1, // Vector Shifts. // VSHL : Vector Shift -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>; +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>; // VSHL : Vector Shift Left (Immediate) -// (disassembly note: this has a different interpretation of the shift amont) -defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; +defm VSHLi : N2VSh_QHSD<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) @@ -2644,8 +2350,6 @@ class N2VLShMax op21_16, bits<4> op11_8, bit op7, : N2VLSh { 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>; @@ -2659,10 +2363,10 @@ defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn", "i", NEONvshrn>; // VRSHL : Vector Rounding Shift -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>; +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>; // 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>; @@ -2672,18 +2376,15 @@ defm VRSHRN : N2VNSh_HSD<0, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vrshrn", "i", NEONvrshrn>; // VQSHL : Vector Saturating Shift -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>; +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>; // VQSHL : Vector Saturating Shift Left (Immediate) -// (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>; +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>; // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; +defm VQSHLsu : N2VSh_QHSD<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", @@ -2696,12 +2397,12 @@ defm VQSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 0, 1, IIC_VSHLi4D, "vqshrun", "s", NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -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>; +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>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -2721,8 +2422,7 @@ defm VRSRAs : N2VShAdd_QHSD<0, 1, 0b0011, 1, "vrsra", "s", NEONvrshrs>; defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; // VSLI : Vector Shift Left and Insert -// (disassembly note: this has a different interpretation of the shift amont) -defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; +defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; // VSRI : Vector Shift Right and Insert defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; @@ -2818,13 +2518,10 @@ def VSWPq : N2VX<0b11, 0b11, 0b00, 0b10, 0b00000, 1, 0, // 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) @@ -3065,7 +2762,6 @@ def VDUPfq : NVDup<0b11101010, 0b1011, 0b00, (outs QPR:$dst), (ins GPR:$src), // VDUP : Vector Duplicate Lane (from scalar to all elements) -let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { class VDUPLND op19_18, bits<2> op17_16, string OpcodeStr, string Dt, ValueType Ty> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, @@ -3079,7 +2775,6 @@ class VDUPLNQ op19_18, bits<2> op17_16, string OpcodeStr, string Dt, (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. @@ -3148,37 +2843,24 @@ defm VMOVLu : N2VLInt_QHS<0b11,0b10100,0,1, "vmovl", "u", // Vector Conversions. -let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { -class N2VDX 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; -class N2VQX 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; -} - // VCVT : Vector Convert Between Floating-Point and Integers -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 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 : 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>; +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>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", @@ -3263,8 +2945,6 @@ def VREV16q8 : VREV16Q<0b00, "vrev16", "8", v16i8>; // VEXT : Vector Extract -let NSF = NVdVnVmImmVectorExtractFrm, - NSForm = NVdVnVmImmVectorExtractFrm.Value in { class VEXTd : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, @@ -3278,7 +2958,6 @@ class VEXTq 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>; @@ -3322,8 +3001,6 @@ def VZIPq32 : N2VQShuffle<0b10, 0b00011, IIC_VPERMQ3, "vzip", "32">; // 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), @@ -3380,8 +3057,6 @@ def VTBX4 DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; } // hasExtraSrcRegAllocReq = 1 -} // End of "let NSF = VTBLFrm, ..." - //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index ea299a06a90..4a4437ed213 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -120,7 +120,7 @@ namespace { 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 @@ void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) { 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 << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << (char)ARM_AM::getAM2Op(MO3.getImm()) << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << (char)ARM_AM::getAM2Op(MO3.getImm()) << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) @@ -458,12 +458,12 @@ void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op){ unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; return; } - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) @@ -490,7 +490,7 @@ void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op) { if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) + << (char)ARM_AM::getAM3Op(MO3.getImm()) << ImmOffs; O << "]"; } @@ -508,7 +508,7 @@ void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op){ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) + << (char)ARM_AM::getAM3Op(MO2.getImm()) << ImmOffs; } @@ -558,7 +558,7 @@ void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) + << (char)ARM_AM::getAM5Op(MO2.getImm()) << ImmOffs*4; } O << "]"; @@ -594,7 +594,7 @@ void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, const MachineOperand &MO1 = MI->getOperand(Op); assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; + O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; } void @@ -617,11 +617,10 @@ void 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 >> Pos) & 1) == CondBit0; + bool T = (Mask & (1 << Pos)) == 0; if (T) O << 't'; else @@ -653,7 +652,7 @@ ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, if (MO3.getReg()) O << ", " << getRegisterName(MO3.getReg()); else if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs * Scale; + O << ", #+" << ImmOffs * Scale; O << "]"; } @@ -675,7 +674,7 @@ void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op) { const MachineOperand &MO2 = MI->getOperand(Op+1); O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs*4; + O << ", #+" << ImmOffs*4; O << "]"; } @@ -711,7 +710,7 @@ void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI, unsigned OffImm = MO2.getImm(); if (OffImm) // Don't print +0. - O << ", #" << OffImm; + O << ", #+" << OffImm; O << "]"; } @@ -727,7 +726,7 @@ void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI, if (OffImm < 0) O << ", #-" << -OffImm; else if (OffImm > 0) - O << ", #" << OffImm; + O << ", #+" << OffImm; O << "]"; } @@ -743,7 +742,7 @@ void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI, if (OffImm < 0) O << ", #-" << -OffImm * 4; else if (OffImm > 0) - O << ", #" << OffImm * 4; + O << ", #+" << OffImm * 4; O << "]"; } @@ -755,18 +754,7 @@ void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, if (OffImm < 0) O << "#-" << -OffImm; else if (OffImm > 0) - 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; + O << "#+" << OffImm; } void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp index f8235c95b83..d4b213a21d1 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp @@ -28,165 +28,7 @@ using namespace llvm; #undef MachineInstr #undef ARMAsmPrinter -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::printInst(const MCInst *MI) { printInstruction(MI); } void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, const char *Modifier) { @@ -194,9 +36,6 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 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); /* @@ -205,7 +44,6 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, O << '{' << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) << '}';*/ -#endif } else if (Modifier && strcmp(Modifier, "lane") == 0) { assert(0); /* @@ -218,9 +56,7 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, O << getRegisterName(Reg); } } else if (Op.isImm()) { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); - assert(isCallOp || - ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); O << '#' << Op.getImm(); } else { assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); @@ -306,17 +142,17 @@ void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op) { 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 << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << ARM_AM::getAM2Offset(MO3.getImm()); + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << getRegisterName(MO2.getReg()); + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) O << ", " @@ -333,14 +169,11 @@ void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI, if (!MO1.getReg()) { unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << ImmOffs; + O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; return; } - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << getRegisterName(MO1.getReg()); + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) O << ", " @@ -363,8 +196,8 @@ void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum) { if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) - << ImmOffs; + << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ImmOffs; O << ']'; } @@ -381,9 +214,9 @@ void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI, unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) - << ImmOffs; + O << "#" + << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ImmOffs; } @@ -431,7 +264,7 @@ void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum, if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) + << (char)ARM_AM::getAM5Op(MO2.getImm()) << ImmOffs*4; } O << "]"; @@ -470,56 +303,14 @@ void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { O << "{"; - for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { - if (i != 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 << ", "; 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) @@ -561,191 +352,3 @@ void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum) { 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(); -} - diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h index ceb641d95bb..9a3cbc3f5d0 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -54,26 +54,26 @@ public: 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 @@ public: 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, unsigned OpNum); - void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); + void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} + void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} void printHex8ImmOperand(const MCInst *MI, int OpNum) {} void printHex16ImmOperand(const MCInst *MI, int OpNum) {} void printHex32ImmOperand(const MCInst *MI, int OpNum) {} diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp deleted file mode 100644 index 52010cd057f..00000000000 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ /dev/null @@ -1,513 +0,0 @@ -//===- 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 diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.h b/lib/Target/ARM/Disassembler/ARMDisassembler.h deleted file mode 100644 index 85bc8b3d2c0..00000000000 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.h +++ /dev/null @@ -1,71 +0,0 @@ -//===- 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 diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp deleted file mode 100644 index c38a606c0a9..00000000000 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ /dev/null @@ -1,3351 +0,0 @@ -//===- ARMDisassemblerCore.cpp - ARM disassembler helpers ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is part of the ARM Disassembler. -// It contains code to represent the core concepts of Builder, Builder Factory, -// as well as the Algorithm to solve the problem of disassembling an ARM instr. -// -//===----------------------------------------------------------------------===// - -#include "ARMAddressingModes.h" -#include "ARMDisassemblerCore.h" -#include - -/// 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<> 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(x); -template 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(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 . - // 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 - ) 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(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 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 Algorithms; - /// NSAlgorithms - NSAlgorithms stores a map from NSFormat to ARMAlgorithm*. - static std::vector 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::Algorithms; - -// Define the symbol here. -std::vector 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); -} diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h deleted file mode 100644 index 23b309cd4f4..00000000000 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h +++ /dev/null @@ -1,301 +0,0 @@ -//===- ARMDisassemblerCore.h - ARM disassembler helpers ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is part of the ARM Disassembler. -// -// The first part defines the enumeration type of ARM instruction format, which -// specifies the encoding used by the instruction, as well as a helper function -// to convert the enums to printable char strings. -// -// It also contains code to represent the concepts of Builder, 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 diff --git a/lib/Target/ARM/Disassembler/Makefile b/lib/Target/ARM/Disassembler/Makefile deleted file mode 100644 index 3eab8325a44..00000000000 --- a/lib/Target/ARM/Disassembler/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- 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 diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc deleted file mode 100644 index 928c403b7ef..00000000000 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc +++ /dev/null @@ -1,2158 +0,0 @@ -//===- 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 # and # -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(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(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(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(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(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(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 , 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 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: 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); -} diff --git a/lib/Target/ARM/Makefile b/lib/Target/ARM/Makefile index 2aac1161201..a8dd38cb362 100644 --- a/lib/Target/ARM/Makefile +++ b/lib/Target/ARM/Makefile @@ -16,9 +16,8 @@ BUILT_SOURCES = ARMGenRegisterInfo.h.inc ARMGenRegisterNames.inc \ ARMGenRegisterInfo.inc ARMGenInstrNames.inc \ ARMGenInstrInfo.inc ARMGenAsmWriter.inc \ ARMGenDAGISel.inc ARMGenSubtarget.inc \ - ARMGenCodeEmitter.inc ARMGenCallingConv.inc \ - ARMGenDisassemblerTables.inc + ARMGenCodeEmitter.inc ARMGenCallingConv.inc -DIRS = AsmPrinter AsmParser Disassembler TargetInfo +DIRS = AsmPrinter AsmParser TargetInfo include $(LEVEL)/Makefile.common diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp index f36d4ef7567..f5ba155f402 100644 --- a/lib/Target/ARM/Thumb2ITBlockPass.cpp +++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp @@ -78,16 +78,14 @@ bool Thumb2ITBlockPass::InsertITBlocks(MachineBasicBlock &MBB) { DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); - if (NCC == CC || NCC == OCC) - Mask |= (NCC & 1) << Pos; - else + if (NCC == OCC) { + Mask |= (1 << Pos); + } else if (NCC != CC) break; --Pos; ++MBBI; } Mask |= (1 << Pos); - // Tag along (firstcond[0] << 4) with the mask. - Mask |= (CC & 1) << 4; MIB.addImm(Mask); Modified = true; ++NumITs; diff --git a/test/CodeGen/ARM/2009-10-27-double-align.ll b/test/CodeGen/ARM/2009-10-27-double-align.ll index f17d059ed08..a4e76859d16 100644 --- a/test/CodeGen/ARM/2009-10-27-double-align.ll +++ b/test/CodeGen/ARM/2009-10-27-double-align.ll @@ -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 diff --git a/test/CodeGen/ARM/2009-10-30.ll b/test/CodeGen/ARM/2009-10-30.ll index 87d1a8b9e9a..90a5bd2a757 100644 --- a/test/CodeGen/ARM/2009-10-30.ll +++ b/test/CodeGen/ARM/2009-10-30.ll @@ -6,7 +6,7 @@ define void @f(i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, ...) { 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* diff --git a/test/CodeGen/ARM/arm-negative-stride.ll b/test/CodeGen/ARM/arm-negative-stride.ll index fb0f8ff8790..52ab8717c15 100644 --- a/test/CodeGen/ARM/arm-negative-stride.ll +++ b/test/CodeGen/ARM/arm-negative-stride.ll @@ -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 ; :0 [#uses=1] br i1 %0, label %return, label %bb diff --git a/test/CodeGen/ARM/globals.ll b/test/CodeGen/ARM/globals.ll index adb44973974..886c0d55cfa 100644 --- a/test/CodeGen/ARM/globals.ll +++ b/test/CodeGen/ARM/globals.ll @@ -41,7 +41,7 @@ define i32 @test1() { ; 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 @@ define i32 @test1() { ; 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 diff --git a/test/CodeGen/ARM/ldrd.ll b/test/CodeGen/ARM/ldrd.ll index 895562a1d31..c366e2dca5f 100644 --- a/test/CodeGen/ARM/ldrd.ll +++ b/test/CodeGen/ARM/ldrd.ll @@ -10,10 +10,10 @@ entry: ;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 diff --git a/test/CodeGen/ARM/str_pre-2.ll b/test/CodeGen/ARM/str_pre-2.ll index 553cd64fce9..f8d3df29c40 100644 --- a/test/CodeGen/ARM/str_pre-2.ll +++ b/test/CodeGen/ARM/str_pre-2.ll @@ -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* diff --git a/test/CodeGen/ARM/tls2.ll b/test/CodeGen/ARM/tls2.ll index 57370c4de1c..d932f90e4c1 100644 --- a/test/CodeGen/ARM/tls2.ll +++ b/test/CodeGen/ARM/tls2.ll @@ -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 @@ entry: 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 diff --git a/test/CodeGen/Thumb2/ldr-str-imm12.ll b/test/CodeGen/Thumb2/ldr-str-imm12.ll index 55cdac983b3..f007b5c6972 100644 --- a/test/CodeGen/Thumb2/ldr-str-imm12.ll +++ b/test/CodeGen/Thumb2/ldr-str-imm12.ll @@ -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 @@ bb119: ; preds = %bb20, %bb20 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 diff --git a/test/CodeGen/Thumb2/thumb2-ldr.ll b/test/CodeGen/Thumb2/thumb2-ldr.ll index 88434f1c7d8..94888fd9405 100644 --- a/test/CodeGen/Thumb2/thumb2-ldr.ll +++ b/test/CodeGen/Thumb2/thumb2-ldr.ll @@ -11,7 +11,7 @@ entry: 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 diff --git a/test/CodeGen/Thumb2/thumb2-ldrh.ll b/test/CodeGen/Thumb2/thumb2-ldrh.ll index fee97bf6891..f1fb79c35ed 100644 --- a/test/CodeGen/Thumb2/thumb2-ldrh.ll +++ b/test/CodeGen/Thumb2/thumb2-ldrh.ll @@ -11,7 +11,7 @@ entry: 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 diff --git a/test/CodeGen/Thumb2/thumb2-str.ll b/test/CodeGen/Thumb2/thumb2-str.ll index 11bb936d1e6..3eeec8c3850 100644 --- a/test/CodeGen/Thumb2/thumb2-str.ll +++ b/test/CodeGen/Thumb2/thumb2-str.ll @@ -9,7 +9,7 @@ define i32 @f1(i32 %a, i32* %v) { 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 diff --git a/test/CodeGen/Thumb2/thumb2-str_pre.ll b/test/CodeGen/Thumb2/thumb2-str_pre.ll index 1e6616a91cc..9af960bbebd 100644 --- a/test/CodeGen/Thumb2/thumb2-str_pre.ll +++ b/test/CodeGen/Thumb2/thumb2-str_pre.ll @@ -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 ; [#uses=1] %Y = getelementptr i32* %X, i32 4 ; [#uses=2] store i32 %B, i32* %Y @@ -12,7 +12,7 @@ define void @test1(i32* %X, i32* %A, i32** %dest) { define i16* @test2(i16* %X, i32* %A) { ; CHECK: test2 -; CHECK: strh r1, [r0, #8]! +; CHECK: strh r1, [r0, #+8]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i16* %X, i32 4 ; [#uses=2] %tmp = trunc i32 %B to i16 ; [#uses=1] diff --git a/test/CodeGen/Thumb2/thumb2-strb.ll b/test/CodeGen/Thumb2/thumb2-strb.ll index 7978e7fa918..1ebb938b1a8 100644 --- a/test/CodeGen/Thumb2/thumb2-strb.ll +++ b/test/CodeGen/Thumb2/thumb2-strb.ll @@ -9,7 +9,7 @@ define i8 @f1(i8 %a, i8* %v) { 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 diff --git a/test/CodeGen/Thumb2/thumb2-strh.ll b/test/CodeGen/Thumb2/thumb2-strh.ll index 97110a726f4..b0eb8c12f59 100644 --- a/test/CodeGen/Thumb2/thumb2-strh.ll +++ b/test/CodeGen/Thumb2/thumb2-strh.ll @@ -9,7 +9,7 @@ define i16 @f1(i16 %a, i16* %v) { 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 diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index e68592d0079..61b9b1583b2 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -12,8 +12,6 @@ #include "Record.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" -#include "RISCDisassemblerEmitter.h" - using namespace llvm; using namespace llvm::X86Disassembler; @@ -126,12 +124,6 @@ void DisassemblerEmitter::run(raw_ostream &OS) { 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"); } diff --git a/utils/TableGen/RISCDisassemblerEmitter.cpp b/utils/TableGen/RISCDisassemblerEmitter.cpp deleted file mode 100644 index 35ad22a9dc6..00000000000 --- a/utils/TableGen/RISCDisassemblerEmitter.cpp +++ /dev/null @@ -1,1743 +0,0 @@ -//===- 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 -#include -#include -#include -#include -#include - -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(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(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 -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 > FilteredInstructions; - - // Set of uid's with non-constant segment values. - std::vector VariableInstructions; - - // Map of well-known segment value to its delegate. - std::map 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 >::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)-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( - 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::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 &AllInstructions; - - // Vector of uid's for this filter chooser to work on. - const std::vector Opcodes; - - // Vector of candidate filters. - std::vector 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 &Insts, - const std::vector &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 &Insts, - const std::vector &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 &StartBits, - std::vector &EndBits, - std::vector &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 StartBits; - std::vector EndBits; - std::vector 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 StartBits; - std::vector EndBits; - std::vector 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 - &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 \n"; - o.indent(i) << "#include \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 NumberedInstructions; - std::vector Opcodes; - // Special case for the ARM chip, which supports ARM and Thumb ISAs. - // Opcodes2 will be populated with the Thumb opcodes. - std::vector 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; -} diff --git a/utils/TableGen/RISCDisassemblerEmitter.h b/utils/TableGen/RISCDisassemblerEmitter.h deleted file mode 100644 index f0e5eced02e..00000000000 --- a/utils/TableGen/RISCDisassemblerEmitter.h +++ /dev/null @@ -1,48 +0,0 @@ -//===- 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 - -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 diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index aaeef4d1fc2..f20ec00aa0e 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -31,7 +31,6 @@ #include "OptParserEmitter.h" #include "Record.h" #include "RegisterInfoEmitter.h" -#include "RISCDisassemblerEmitter.h" #include "SubtargetEmitter.h" #include "TGParser.h" #include "llvm/Support/CommandLine.h" @@ -49,7 +48,6 @@ enum ActionType { GenEmitter, GenRegisterEnums, GenRegister, GenRegisterHeader, GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher, - GenRISCDisassembler, GenDisassembler, GenCallingConv, GenClangDiagsDefs, @@ -86,9 +84,6 @@ namespace { "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", @@ -234,9 +229,6 @@ int main(int argc, char **argv) { case GenAsmWriter: AsmWriterEmitter(Records).run(*Out); break; - case GenRISCDisassembler: - RISCDisassemblerEmitter(Records).run(*Out); - break; case GenAsmMatcher: AsmMatcherEmitter(Records).run(*Out); break;