mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-15 00:38:42 +00:00
Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend
(RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, and the disassembler core which invokes the decoder function and builds up the MCInst based on the decoded Opcode. Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm instructions to help disassembly. We also changed the output of the addressing modes to omit the '+' from the assembler syntax #+/-<imm> or +/-<Rm>. See, for example, A8.6.57/58/60. And modified test cases to not expect '+' in +reg or #+num. For example, ; CHECK: ldr.w r9, [r7, #28] git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98637 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ea7f22c31d
commit
d30a98e43a
@ -1614,6 +1614,11 @@ $(ObjDir)/%GenIntrinsics.inc.tmp : %.td $(ObjDir)/.dir
|
||||
$(Echo) "Building $(<F) intrinsics information with tblgen"
|
||||
$(Verb) $(TableGen) -gen-tgt-intrinsic -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/ARMDisassemblerTables.inc.tmp : ARM.td $(ObjDir)/.dir
|
||||
$(Echo) "Building ARM disassembly tables with tblgen"
|
||||
$(Verb) $(TableGen) -gen-risc-disassembler -o $(call SYSPATH, $@) $<
|
||||
|
||||
|
||||
clean-local::
|
||||
-$(Verb) $(RM) -f $(INCFiles)
|
||||
|
||||
|
@ -35,6 +35,10 @@ namespace ARM_AM {
|
||||
add = '+', sub = '-'
|
||||
};
|
||||
|
||||
static inline const char *getAddrOpcStr(AddrOpc Op) {
|
||||
return Op == sub ? "-" : "";
|
||||
}
|
||||
|
||||
static inline const char *getShiftOpcStr(ShiftOpc Op) {
|
||||
switch (Op) {
|
||||
default: assert(0 && "Unknown shift opc!");
|
||||
@ -127,6 +131,20 @@ namespace ARM_AM {
|
||||
return (Imm >> 8) * 2;
|
||||
}
|
||||
|
||||
/// getSOImmValOneRotate - Try to handle Imm with an immediate shifter
|
||||
/// operand, computing the rotate amount to use. If this immediate value
|
||||
/// cannot be handled with a single shifter-op, return 0.
|
||||
static inline unsigned getSOImmValOneRotate(unsigned Imm) {
|
||||
// A5.2.4 Constants with multiple encodings
|
||||
// The lowest unsigned value of rotation wins!
|
||||
for (unsigned R = 1; R <= 15; ++R)
|
||||
if ((Imm & rotr32(~255U, 2*R)) == 0)
|
||||
return 2*R;
|
||||
|
||||
// Failed to find a suitable rotate amount.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getSOImmValRotate - Try to handle Imm with an immediate shifter operand,
|
||||
/// computing the rotate amount to use. If this immediate value cannot be
|
||||
/// handled with a single shifter-op, determine a good rotate amount that will
|
||||
@ -179,7 +197,7 @@ namespace ARM_AM {
|
||||
// of zero.
|
||||
if ((Arg & ~255U) == 0) return Arg;
|
||||
|
||||
unsigned RotAmt = getSOImmValRotate(Arg);
|
||||
unsigned RotAmt = getSOImmValOneRotate(Arg);
|
||||
|
||||
// If this cannot be handled with a single shifter_op, bail out.
|
||||
if (rotr32(~255U, RotAmt) & Arg)
|
||||
|
@ -1464,6 +1464,29 @@ class AVConv5I<bits<8> 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<bits<5> val> {
|
||||
bits<5> Value = val;
|
||||
}
|
||||
def NSFormatNone : NSFormat<0>;
|
||||
def VLDSTLaneFrm : NSFormat<1>;
|
||||
def VLDSTLaneDblFrm : NSFormat<2>;
|
||||
def VLDSTRQFrm : NSFormat<3>;
|
||||
def NVdImmFrm : NSFormat<4>;
|
||||
def NVdVmImmFrm : NSFormat<5>;
|
||||
def NVdVmImmVCVTFrm : NSFormat<6>;
|
||||
def NVdVmImmVDupLaneFrm : NSFormat<7>;
|
||||
def NVdVmImmVSHLLFrm : NSFormat<8>;
|
||||
def NVectorShuffleFrm : NSFormat<9>;
|
||||
def NVectorShiftFrm : NSFormat<10>;
|
||||
def NVectorShift2Frm : NSFormat<11>;
|
||||
def NVdVnVmImmFrm : NSFormat<12>;
|
||||
def NVdVnVmImmVectorShiftFrm : NSFormat<13>;
|
||||
def NVdVnVmImmVectorExtractFrm : NSFormat<14>;
|
||||
def NVdVnVmImmMulScalarFrm : NSFormat<15>;
|
||||
def VTBLFrm : NSFormat<16>;
|
||||
|
||||
class NeonI<dag oops, dag iops, AddrMode am, IndexMode im, InstrItinClass itin,
|
||||
string opc, string dt, string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, Size4Bytes, im, NEONFrm, NeonDomain, cstr, itin> {
|
||||
@ -1474,6 +1497,8 @@ class NeonI<dag oops, dag iops, AddrMode am, IndexMode im, InstrItinClass itin,
|
||||
!strconcat("\t", asm));
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [HasNEON];
|
||||
NSFormat NSF = NSFormatNone; // For disassembly.
|
||||
bits<5> NSForm = NSFormatNone.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// Same as NeonI except it does not have a "data type" specifier.
|
||||
@ -1485,6 +1510,8 @@ class NeonXI<dag oops, dag iops, AddrMode am, IndexMode im, InstrItinClass itin,
|
||||
let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm));
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [HasNEON];
|
||||
NSFormat NSF = NSFormatNone; // For disassembly.
|
||||
bits<5> NSForm = NSFormatNone.Value; // For disassembly.
|
||||
}
|
||||
|
||||
class NI<dag oops, dag iops, InstrItinClass itin, string opc, string asm,
|
||||
@ -1497,6 +1524,8 @@ class NI4<dag oops, dag iops, InstrItinClass itin, string opc,
|
||||
string asm, list<dag> pattern>
|
||||
: NeonXI<oops, iops, AddrMode4, IndexModeNone, itin, opc, asm, "",
|
||||
pattern> {
|
||||
let NSF = VLDSTRQFrm; // For disassembly.
|
||||
let NSForm = VLDSTRQFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
class NLdSt<bit op23, bits<2> op21_20, bits<4> op11_8, bits<4> op7_4,
|
||||
@ -1509,6 +1538,8 @@ class NLdSt<bit op23, bits<2> 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<dag oops, dag iops, InstrItinClass itin,
|
||||
@ -1538,6 +1569,8 @@ class N1ModImm<bit op23, bits<3> 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.
|
||||
@ -1553,6 +1586,8 @@ class N2V<bits<2> 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.
|
||||
@ -1568,6 +1603,8 @@ class N2VX<bits<2> 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.
|
||||
@ -1581,6 +1618,8 @@ class N2VImm<bit op24, bit op23, bits<4> 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.
|
||||
@ -1594,6 +1633,8 @@ class N3V<bit op24, bit op23, bits<2> 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.
|
||||
@ -1607,6 +1648,8 @@ class N3VX<bit op24, bit op23, bits<2> 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.
|
||||
|
@ -213,7 +213,10 @@ def VLD2q32 : VLD2Q<0b1000, "vld2", "32">;
|
||||
class VLD2Ddbl<bits<4> op7_4, string OpcodeStr, string Dt>
|
||||
: NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2),
|
||||
(ins addrmode6:$addr), IIC_VLD2,
|
||||
OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>;
|
||||
OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">;
|
||||
def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">;
|
||||
@ -228,7 +231,10 @@ class VLD3WB<bits<4> 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", []>;
|
||||
"$addr.addr = $wb", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VLD3d8 : VLD3D<0b0000, "vld3", "8">;
|
||||
def VLD3d16 : VLD3D<0b0100, "vld3", "16">;
|
||||
@ -260,7 +266,10 @@ class VLD4WB<bits<4> 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", []>;
|
||||
"$addr.addr = $wb", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VLD4d8 : VLD4D<0b0000, "vld4", "8">;
|
||||
def VLD4d16 : VLD4D<0b0100, "vld4", "16">;
|
||||
@ -297,12 +306,28 @@ def 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; }
|
||||
def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; }
|
||||
def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// vld2 to double-spaced odd registers.
|
||||
def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; }
|
||||
def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; }
|
||||
def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// VLD3LN : Vector Load (single 3-element structure to one lane)
|
||||
class VLD3LN<bits<4> op11_8, string OpcodeStr, string Dt>
|
||||
@ -318,7 +343,11 @@ def 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; }
|
||||
def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> {
|
||||
let Inst{5-4} = 0b10;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; }
|
||||
|
||||
// vld3 to double-spaced odd registers.
|
||||
@ -340,12 +369,28 @@ def 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; }
|
||||
def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; }
|
||||
def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// vld4 to double-spaced odd registers.
|
||||
def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; }
|
||||
def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; }
|
||||
def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// VLD1DUP : Vector Load (single element to all lanes)
|
||||
// VLD2DUP : Vector Load (single 2-element structure to all lanes)
|
||||
@ -433,7 +478,10 @@ def VST2q32 : VST2Q<0b1000, "vst2", "32">;
|
||||
class VST2Ddbl<bits<4> op7_4, string OpcodeStr, string Dt>
|
||||
: NLdSt<0, 0b00, 0b1001, op7_4, (outs),
|
||||
(ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST,
|
||||
OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>;
|
||||
OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">;
|
||||
def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">;
|
||||
@ -448,7 +496,10 @@ class VST3WB<bits<4> 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", []>;
|
||||
"$addr.addr = $wb", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VST3d8 : VST3D<0b0000, "vst3", "8">;
|
||||
def VST3d16 : VST3D<0b0100, "vst3", "16">;
|
||||
@ -478,7 +529,10 @@ class VST4WB<bits<4> 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", []>;
|
||||
"$addr.addr = $wb", []> {
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
def VST4d8 : VST4D<0b0000, "vst4", "8">;
|
||||
def VST4d16 : VST4D<0b0100, "vst4", "16">;
|
||||
@ -515,12 +569,28 @@ def 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; }
|
||||
def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; }
|
||||
def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// vst2 to double-spaced odd registers.
|
||||
def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; }
|
||||
def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; }
|
||||
def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// VST3LN : Vector Store (single 3-element structure from one lane)
|
||||
class VST3LN<bits<4> op11_8, string OpcodeStr, string Dt>
|
||||
@ -535,12 +605,28 @@ def 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; }
|
||||
def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; }
|
||||
def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> {
|
||||
let Inst{5-4} = 0b10;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> {
|
||||
let Inst{6-4} = 0b100;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// vst3 to double-spaced odd registers.
|
||||
def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; }
|
||||
def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; }
|
||||
def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> {
|
||||
let Inst{5-4} = 0b10;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> {
|
||||
let Inst{6-4} = 0b100;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// VST4LN : Vector Store (single 4-element structure from one lane)
|
||||
class VST4LN<bits<4> op11_8, string OpcodeStr, string Dt>
|
||||
@ -556,12 +642,28 @@ def 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; }
|
||||
def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; }
|
||||
def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// vst4 to double-spaced odd registers.
|
||||
def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; }
|
||||
def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; }
|
||||
def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> {
|
||||
let Inst{5} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> {
|
||||
let Inst{6} = 1;
|
||||
let NSF = VLDSTLaneDblFrm; // For disassembly.
|
||||
let NSForm = VLDSTLaneDblFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
} // mayStore = 1, hasExtraSrcRegAllocReq = 1
|
||||
|
||||
@ -668,12 +770,18 @@ class N2VDShuffle<bits<2> 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", []>;
|
||||
"$src1 = $dst1, $src2 = $dst2", []> {
|
||||
let NSF = NVectorShuffleFrm; // For disassembly.
|
||||
let NSForm = NVectorShuffleFrm.Value; // For disassembly.
|
||||
}
|
||||
class N2VQShuffle<bits<2> op19_18, bits<5> op11_7,
|
||||
InstrItinClass itin, string OpcodeStr, string Dt>
|
||||
: N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2),
|
||||
(ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2",
|
||||
"$src1 = $dst1, $src2 = $dst2", []>;
|
||||
"$src1 = $dst1, $src2 = $dst2", []> {
|
||||
let NSF = NVectorShuffleFrm; // For disassembly.
|
||||
let NSForm = NVectorShuffleFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// Basic 3-register operations: single-, double- and quad-register.
|
||||
class N3VS<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
|
||||
@ -715,6 +823,8 @@ class N3VDSL<bits<2> 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<bits<2> op21_20, bits<4> op11_8,
|
||||
string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp>
|
||||
@ -725,6 +835,8 @@ class N3VDSL16<bits<2> 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<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
|
||||
@ -756,6 +868,8 @@ class N3VQSL<bits<2> 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<bits<2> op21_20, bits<4> op11_8, string OpcodeStr, string Dt,
|
||||
ValueType ResTy, ValueType OpTy, SDNode ShOp>
|
||||
@ -767,6 +881,8 @@ class N3VQSL16<bits<2> 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.
|
||||
@ -789,6 +905,8 @@ class N3VDIntSL<bits<2> 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<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
|
||||
string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp>
|
||||
@ -800,6 +918,8 @@ class N3VDIntSL16<bits<2> 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<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
|
||||
@ -822,6 +942,8 @@ class N3VQIntSL<bits<2> 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<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
|
||||
string OpcodeStr, string Dt,
|
||||
@ -834,6 +956,8 @@ class N3VQIntSL16<bits<2> 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.
|
||||
@ -864,7 +988,10 @@ class N3VDMulOpSL<bits<2> 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)))))))]>;
|
||||
imm:$lane)))))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
class N3VDMulOpSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
|
||||
string OpcodeStr, string Dt,
|
||||
ValueType Ty, SDNode MulOp, SDNode ShOp>
|
||||
@ -876,7 +1003,10 @@ class N3VDMulOpSL16<bits<2> 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)))))))]>;
|
||||
imm:$lane)))))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
class N3VQMulOp<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
|
||||
InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty,
|
||||
@ -897,7 +1027,10 @@ class N3VQMulOpSL<bits<2> 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)))))))]>;
|
||||
imm:$lane)))))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
class N3VQMulOpSL16<bits<2> op21_20, bits<4> op11_8, InstrItinClass itin,
|
||||
string OpcodeStr, string Dt,
|
||||
ValueType ResTy, ValueType OpTy,
|
||||
@ -910,7 +1043,10 @@ class N3VQMulOpSL16<bits<2> 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)))))))]>;
|
||||
imm:$lane)))))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// Neon 3-argument intrinsics, both double- and quad-register.
|
||||
// The destination register is also used as the first source operand register.
|
||||
@ -996,7 +1132,10 @@ class N3VLIntSL<bit op24, bits<2> 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)))))]>;
|
||||
imm:$lane)))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
class N3VLIntSL16<bit op24, bits<2> op21_20, bits<4> op11_8,
|
||||
InstrItinClass itin, string OpcodeStr, string Dt,
|
||||
ValueType ResTy, ValueType OpTy, Intrinsic IntOp>
|
||||
@ -1006,7 +1145,10 @@ class N3VLIntSL16<bit op24, bits<2> op21_20, bits<4> op11_8,
|
||||
[(set (ResTy QPR:$dst),
|
||||
(ResTy (IntOp (OpTy DPR:$src1),
|
||||
(OpTy (NEONvduplane (OpTy DPR_8:$src2),
|
||||
imm:$lane)))))]>;
|
||||
imm:$lane)))))]> {
|
||||
let NSF = NVdVnVmImmMulScalarFrm; // For disassembly.
|
||||
let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// Wide 3-register intrinsics.
|
||||
class N3VWInt<bit op24, bit op23, bits<2> op21_20, bits<4> op11_8, bit op4,
|
||||
@ -1055,6 +1197,10 @@ class N2VQPLInt2<bits<2> 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<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4,
|
||||
@ -1072,16 +1218,6 @@ class N2VQSh<bit op24, bit op23, bits<4> 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<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
|
||||
string OpcodeStr, string Dt,
|
||||
ValueType ResTy, ValueType OpTy, SDNode OpNode>
|
||||
: N2VImm<op24, op23, op11_8, op7, op6, op4,
|
||||
(outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD,
|
||||
OpcodeStr, Dt, "$dst, $src, $SIMM", "",
|
||||
[(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src),
|
||||
(i32 imm:$SIMM))))]>;
|
||||
|
||||
// Narrow shift by immediate.
|
||||
class N2VNSh<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
|
||||
InstrItinClass itin, string OpcodeStr, string Dt,
|
||||
@ -1124,8 +1260,26 @@ class N2VQShIns<bit op24, bit op23, bits<4> 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<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6, bit op4,
|
||||
string OpcodeStr, string Dt,
|
||||
ValueType ResTy, ValueType OpTy, SDNode OpNode>
|
||||
: N2VImm<op24, op23, op11_8, op7, op6, op4,
|
||||
(outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD,
|
||||
OpcodeStr, Dt, "$dst, $src, $SIMM", "",
|
||||
[(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src),
|
||||
(i32 imm:$SIMM))))]> {
|
||||
// This has a different interpretation of the shift amount encoding than
|
||||
// NVectorShiftFrm.
|
||||
let NSF = NVectorShift2Frm; // For disassembly.
|
||||
let NSForm = NVectorShift2Frm.Value; // For disassembly.
|
||||
}
|
||||
|
||||
// Convert, with fractional bits immediate,
|
||||
// both double- and quad-register.
|
||||
let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in {
|
||||
class N2VCvtD<bit op24, bit op23, bits<4> op11_8, bit op7, bit op4,
|
||||
string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy,
|
||||
Intrinsic IntOp>
|
||||
@ -1140,6 +1294,7 @@ class N2VCvtQ<bit op24, bit op23, bits<4> 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
|
||||
@ -1350,6 +1505,60 @@ multiclass N3VInt_QHSD<bit op24, bit op23, bits<4> 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<bit op24, bit op23, bits<4> op11_8, bit op4,
|
||||
InstrItinClass itinD16, InstrItinClass itinD32,
|
||||
InstrItinClass itinQ16, InstrItinClass itinQ32,
|
||||
string OpcodeStr, string Dt,
|
||||
Intrinsic IntOp, bit Commutable = 0> {
|
||||
// 64-bit vector types.
|
||||
def v4i16 : N3VDInt<op24, op23, 0b01, op11_8, op4, itinD16,
|
||||
OpcodeStr, !strconcat(Dt, "16"),
|
||||
v4i16, v4i16, IntOp, Commutable>;
|
||||
def v2i32 : N3VDInt<op24, op23, 0b10, op11_8, op4, itinD32,
|
||||
OpcodeStr, !strconcat(Dt, "32"),
|
||||
v2i32, v2i32, IntOp, Commutable>;
|
||||
|
||||
// 128-bit vector types.
|
||||
def v8i16 : N3VQInt<op24, op23, 0b01, op11_8, op4, itinQ16,
|
||||
OpcodeStr, !strconcat(Dt, "16"),
|
||||
v8i16, v8i16, IntOp, Commutable>;
|
||||
def v4i32 : N3VQInt<op24, op23, 0b10, op11_8, op4, itinQ32,
|
||||
OpcodeStr, !strconcat(Dt, "32"),
|
||||
v4i32, v4i32, IntOp, Commutable>;
|
||||
}
|
||||
multiclass N3VInt_QHS2<bit op24, bit op23, bits<4> op11_8, bit op4,
|
||||
InstrItinClass itinD16, InstrItinClass itinD32,
|
||||
InstrItinClass itinQ16, InstrItinClass itinQ32,
|
||||
string OpcodeStr, string Dt,
|
||||
Intrinsic IntOp, bit Commutable = 0>
|
||||
: N3VInt_HS2<op24, op23, op11_8, op4, itinD16, itinD32, itinQ16, itinQ32,
|
||||
OpcodeStr, Dt, IntOp, Commutable> {
|
||||
def v8i8 : N3VDInt<op24, op23, 0b00, op11_8, op4, itinD16,
|
||||
OpcodeStr, !strconcat(Dt, "8"),
|
||||
v8i8, v8i8, IntOp, Commutable>;
|
||||
def v16i8 : N3VQInt<op24, op23, 0b00, op11_8, op4, itinQ16,
|
||||
OpcodeStr, !strconcat(Dt, "8"),
|
||||
v16i8, v16i8, IntOp, Commutable>;
|
||||
}
|
||||
multiclass N3VInt_QHSD2<bit op24, bit op23, bits<4> op11_8, bit op4,
|
||||
InstrItinClass itinD16, InstrItinClass itinD32,
|
||||
InstrItinClass itinQ16, InstrItinClass itinQ32,
|
||||
string OpcodeStr, string Dt,
|
||||
Intrinsic IntOp, bit Commutable = 0>
|
||||
: N3VInt_QHS2<op24, op23, op11_8, op4, itinD16, itinD32, itinQ16, itinQ32,
|
||||
OpcodeStr, Dt, IntOp, Commutable> {
|
||||
def v1i64 : N3VDInt<op24, op23, 0b11, op11_8, op4, itinD32,
|
||||
OpcodeStr, !strconcat(Dt, "64"),
|
||||
v1i64, v1i64, IntOp, Commutable>;
|
||||
def v2i64 : N3VQInt<op24, op23, 0b11, op11_8, op4, itinQ32,
|
||||
OpcodeStr, !strconcat(Dt, "64"),
|
||||
v2i64, v2i64, IntOp, Commutable>;
|
||||
}
|
||||
}
|
||||
|
||||
// Neon Narrowing 3-register vector intrinsics,
|
||||
// source operand element sizes of 16, 32 and 64 bits:
|
||||
@ -1619,6 +1828,47 @@ multiclass N2VSh_QHSD<bit op24, bit op23, bits<4> 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<bit op24, bit op23, bits<4> op11_8, bit op4,
|
||||
InstrItinClass itin, string OpcodeStr, string Dt,
|
||||
SDNode OpNode> {
|
||||
// 64-bit vector types.
|
||||
def v8i8 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "8"), v8i8, OpNode> {
|
||||
let Inst{21-19} = 0b001; // imm6 = 001xxx
|
||||
}
|
||||
def v4i16 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "16"), v4i16, OpNode> {
|
||||
let Inst{21-20} = 0b01; // imm6 = 01xxxx
|
||||
}
|
||||
def v2i32 : N2VDSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "32"), v2i32, OpNode> {
|
||||
let Inst{21} = 0b1; // imm6 = 1xxxxx
|
||||
}
|
||||
def v1i64 : N2VDSh<op24, op23, op11_8, 1, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "64"), v1i64, OpNode>;
|
||||
// imm6 = xxxxxx
|
||||
|
||||
// 128-bit vector types.
|
||||
def v16i8 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "8"), v16i8, OpNode> {
|
||||
let Inst{21-19} = 0b001; // imm6 = 001xxx
|
||||
}
|
||||
def v8i16 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "16"), v8i16, OpNode> {
|
||||
let Inst{21-20} = 0b01; // imm6 = 01xxxx
|
||||
}
|
||||
def v4i32 : N2VQSh<op24, op23, op11_8, 0, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "32"), v4i32, OpNode> {
|
||||
let Inst{21} = 0b1; // imm6 = 1xxxxx
|
||||
}
|
||||
def v2i64 : N2VQSh<op24, op23, op11_8, 1, op4, itin,
|
||||
OpcodeStr, !strconcat(Dt, "64"), v2i64, OpNode>;
|
||||
// imm6 = xxxxxx
|
||||
}
|
||||
}
|
||||
|
||||
// Neon Shift-Accumulate vector operations,
|
||||
// element sizes of 8, 16, 32 and 64 bits:
|
||||
@ -1699,6 +1949,47 @@ multiclass N2VShIns_QHSD<bit op24, bit op23, bits<4> 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<bit op24, bit op23, bits<4> op11_8, bit op4,
|
||||
string OpcodeStr, SDNode ShOp> {
|
||||
// 64-bit vector types.
|
||||
def v8i8 : N2VDShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "8", v8i8, ShOp> {
|
||||
let Inst{21-19} = 0b001; // imm6 = 001xxx
|
||||
}
|
||||
def v4i16 : N2VDShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "16", v4i16, ShOp> {
|
||||
let Inst{21-20} = 0b01; // imm6 = 01xxxx
|
||||
}
|
||||
def v2i32 : N2VDShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "32", v2i32, ShOp> {
|
||||
let Inst{21} = 0b1; // imm6 = 1xxxxx
|
||||
}
|
||||
def v1i64 : N2VDShIns<op24, op23, op11_8, 1, op4,
|
||||
OpcodeStr, "64", v1i64, ShOp>;
|
||||
// imm6 = xxxxxx
|
||||
|
||||
// 128-bit vector types.
|
||||
def v16i8 : N2VQShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "8", v16i8, ShOp> {
|
||||
let Inst{21-19} = 0b001; // imm6 = 001xxx
|
||||
}
|
||||
def v8i16 : N2VQShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "16", v8i16, ShOp> {
|
||||
let Inst{21-20} = 0b01; // imm6 = 01xxxx
|
||||
}
|
||||
def v4i32 : N2VQShIns<op24, op23, op11_8, 0, op4,
|
||||
OpcodeStr, "32", v4i32, ShOp> {
|
||||
let Inst{21} = 0b1; // imm6 = 1xxxxx
|
||||
}
|
||||
def v2i64 : N2VQShIns<op24, op23, op11_8, 1, op4,
|
||||
OpcodeStr, "64", v2i64, ShOp>;
|
||||
// imm6 = xxxxxx
|
||||
}
|
||||
}
|
||||
|
||||
// Neon Shift Long operations,
|
||||
// element sizes of 8, 16, 32 bits:
|
||||
multiclass N2VLSh_QHS<bit op24, bit op23, bits<4> op11_8, bit op7, bit op6,
|
||||
@ -2329,18 +2620,21 @@ def VRSQRTSfq : N3VQInt<0, 0, 0b10, 0b1111, 1,
|
||||
// Vector Shifts.
|
||||
|
||||
// VSHL : Vector Shift
|
||||
defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>;
|
||||
defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>;
|
||||
defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>;
|
||||
defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ,
|
||||
IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>;
|
||||
// VSHL : Vector Shift Left (Immediate)
|
||||
defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>;
|
||||
// VSHR : Vector Shift Right (Immediate)
|
||||
defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>;
|
||||
defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>;
|
||||
|
||||
// VSHLL : Vector Shift Left Long
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>;
|
||||
|
||||
// VSHLL : Vector Shift Left Long (with maximum shift count)
|
||||
@ -2350,6 +2644,8 @@ class N2VLShMax<bit op24, bit op23, bits<6> op21_16, bits<4> op11_8, bit op7,
|
||||
: N2VLSh<op24, op23, op11_8, op7, op6, op4, OpcodeStr, Dt,
|
||||
ResTy, OpTy, OpNode> {
|
||||
let Inst{21-16} = op21_16;
|
||||
let NSF = NVdVmImmVSHLLFrm; // For disassembly.
|
||||
let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly.
|
||||
}
|
||||
def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8",
|
||||
v8i16, v8i8, NEONvshlli>;
|
||||
@ -2363,10 +2659,10 @@ defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn", "i",
|
||||
NEONvshrn>;
|
||||
|
||||
// VRSHL : Vector Rounding Shift
|
||||
defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>;
|
||||
defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>;
|
||||
defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>;
|
||||
defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>;
|
||||
// VRSHR : Vector Rounding Shift Right
|
||||
defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>;
|
||||
defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>;
|
||||
@ -2376,15 +2672,18 @@ defm VRSHRN : N2VNSh_HSD<0, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vrshrn", "i",
|
||||
NEONvrshrn>;
|
||||
|
||||
// VQSHL : Vector Saturating Shift
|
||||
defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>;
|
||||
defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>;
|
||||
defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>;
|
||||
defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>;
|
||||
// VQSHL : Vector Saturating Shift Left (Immediate)
|
||||
defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>;
|
||||
defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>;
|
||||
// VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned)
|
||||
defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>;
|
||||
|
||||
// VQSHRN : Vector Saturating Shift Right and Narrow
|
||||
defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s",
|
||||
@ -2397,12 +2696,12 @@ defm VQSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 0, 1, IIC_VSHLi4D, "vqshrun", "s",
|
||||
NEONvqshrnsu>;
|
||||
|
||||
// VQRSHL : Vector Saturating Rounding Shift
|
||||
defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqrshl", "s",
|
||||
int_arm_neon_vqrshifts, 0>;
|
||||
defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqrshl", "u",
|
||||
int_arm_neon_vqrshiftu, 0>;
|
||||
defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqrshl", "s",
|
||||
int_arm_neon_vqrshifts, 0>;
|
||||
defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q,
|
||||
IIC_VSHLi4Q, "vqrshl", "u",
|
||||
int_arm_neon_vqrshiftu, 0>;
|
||||
|
||||
// VQRSHRN : Vector Saturating Rounding Shift Right and Narrow
|
||||
defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s",
|
||||
@ -2422,7 +2721,8 @@ defm 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
|
||||
defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>;
|
||||
// (disassembly note: this has a different interpretation of the shift amont)
|
||||
defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>;
|
||||
// VSRI : Vector Shift Right and Insert
|
||||
defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>;
|
||||
|
||||
@ -2518,10 +2818,13 @@ 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)
|
||||
|
||||
@ -2762,6 +3065,7 @@ 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<bits<2> op19_18, bits<2> op17_16,
|
||||
string OpcodeStr, string Dt, ValueType Ty>
|
||||
: N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0,
|
||||
@ -2775,6 +3079,7 @@ class VDUPLNQ<bits<2> 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.
|
||||
|
||||
@ -2843,24 +3148,37 @@ defm VMOVLu : N2VLInt_QHS<0b11,0b10100,0,1, "vmovl", "u",
|
||||
|
||||
// Vector Conversions.
|
||||
|
||||
// VCVT : Vector Convert Between Floating-Point and Integers
|
||||
def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
|
||||
v2i32, v2f32, fp_to_sint>;
|
||||
def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
|
||||
v2i32, v2f32, fp_to_uint>;
|
||||
def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
|
||||
v2f32, v2i32, sint_to_fp>;
|
||||
def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
|
||||
v2f32, v2i32, uint_to_fp>;
|
||||
let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in {
|
||||
class N2VDX<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18,
|
||||
bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr,
|
||||
string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode>
|
||||
: N2VD<op24_23, op21_20, op19_18, op17_16, op11_7, op4, OpcodeStr, Dt,
|
||||
ResTy, OpTy, OpNode>;
|
||||
class N2VQX<bits<2> op24_23, bits<2> op21_20, bits<2> op19_18,
|
||||
bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr,
|
||||
string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode>
|
||||
: N2VQ<op24_23, op21_20, op19_18, op17_16, op11_7, op4, OpcodeStr, Dt,
|
||||
ResTy, OpTy, OpNode>;
|
||||
}
|
||||
|
||||
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 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 VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32",
|
||||
v4i32, v4f32, fp_to_sint>;
|
||||
def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32",
|
||||
v4i32, v4f32, fp_to_uint>;
|
||||
def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32",
|
||||
v4f32, v4i32, sint_to_fp>;
|
||||
def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32",
|
||||
v4f32, v4i32, uint_to_fp>;
|
||||
|
||||
// VCVT : Vector Convert Between Floating-Point and Fixed-Point.
|
||||
def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32",
|
||||
@ -2945,6 +3263,8 @@ def VREV16q8 : VREV16Q<0b00, "vrev16", "8", v16i8>;
|
||||
|
||||
// VEXT : Vector Extract
|
||||
|
||||
let NSF = NVdVnVmImmVectorExtractFrm,
|
||||
NSForm = NVdVnVmImmVectorExtractFrm.Value in {
|
||||
class VEXTd<string OpcodeStr, string Dt, ValueType Ty>
|
||||
: N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst),
|
||||
(ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD,
|
||||
@ -2958,6 +3278,7 @@ class VEXTq<string OpcodeStr, string Dt, ValueType Ty>
|
||||
OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "",
|
||||
[(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs),
|
||||
(Ty QPR:$rhs), imm:$index)))]>;
|
||||
}
|
||||
|
||||
def VEXTd8 : VEXTd<"vext", "8", v8i8>;
|
||||
def VEXTd16 : VEXTd<"vext", "16", v4i16>;
|
||||
@ -3001,6 +3322,8 @@ 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),
|
||||
@ -3057,6 +3380,8 @@ def VTBX4
|
||||
DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>;
|
||||
} // hasExtraSrcRegAllocReq = 1
|
||||
|
||||
} // End of "let NSF = VTBLFrm, ..."
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// NEON instructions for single-precision FP math
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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 << ", #"
|
||||
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||
<< ARM_AM::getAM2Offset(MO3.getImm());
|
||||
O << "]";
|
||||
return;
|
||||
}
|
||||
|
||||
O << ", "
|
||||
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||
<< getRegisterName(MO2.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
|
||||
@ -458,12 +458,12 @@ void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op){
|
||||
unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
|
||||
assert(ImmOffs && "Malformed indexed load / store!");
|
||||
O << "#"
|
||||
<< (char)ARM_AM::getAM2Op(MO2.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
|
||||
<< ImmOffs;
|
||||
return;
|
||||
}
|
||||
|
||||
O << (char)ARM_AM::getAM2Op(MO2.getImm())
|
||||
O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
|
||||
<< getRegisterName(MO1.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
|
||||
@ -490,7 +490,7 @@ void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op) {
|
||||
|
||||
if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
|
||||
O << ", #"
|
||||
<< (char)ARM_AM::getAM3Op(MO3.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
|
||||
<< ImmOffs;
|
||||
O << "]";
|
||||
}
|
||||
@ -508,7 +508,7 @@ void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op){
|
||||
unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
|
||||
assert(ImmOffs && "Malformed indexed load / store!");
|
||||
O << "#"
|
||||
<< (char)ARM_AM::getAM3Op(MO2.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm()))
|
||||
<< ImmOffs;
|
||||
}
|
||||
|
||||
@ -558,7 +558,7 @@ void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op,
|
||||
|
||||
if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
|
||||
O << ", #"
|
||||
<< (char)ARM_AM::getAM5Op(MO2.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
|
||||
<< ImmOffs*4;
|
||||
}
|
||||
O << "]";
|
||||
@ -594,7 +594,7 @@ 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,10 +617,11 @@ 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 & (1 << Pos)) == 0;
|
||||
bool T = ((Mask >> Pos) & 1) == CondBit0;
|
||||
if (T)
|
||||
O << 't';
|
||||
else
|
||||
@ -652,7 +653,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 << "]";
|
||||
}
|
||||
|
||||
@ -674,7 +675,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 << "]";
|
||||
}
|
||||
|
||||
@ -710,7 +711,7 @@ void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI,
|
||||
|
||||
unsigned OffImm = MO2.getImm();
|
||||
if (OffImm) // Don't print +0.
|
||||
O << ", #+" << OffImm;
|
||||
O << ", #" << OffImm;
|
||||
O << "]";
|
||||
}
|
||||
|
||||
@ -726,7 +727,7 @@ void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI,
|
||||
if (OffImm < 0)
|
||||
O << ", #-" << -OffImm;
|
||||
else if (OffImm > 0)
|
||||
O << ", #+" << OffImm;
|
||||
O << ", #" << OffImm;
|
||||
O << "]";
|
||||
}
|
||||
|
||||
@ -742,7 +743,7 @@ void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI,
|
||||
if (OffImm < 0)
|
||||
O << ", #-" << -OffImm * 4;
|
||||
else if (OffImm > 0)
|
||||
O << ", #+" << OffImm * 4;
|
||||
O << ", #" << OffImm * 4;
|
||||
O << "]";
|
||||
}
|
||||
|
||||
@ -754,7 +755,18 @@ void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI,
|
||||
if (OffImm < 0)
|
||||
O << "#-" << -OffImm;
|
||||
else if (OffImm > 0)
|
||||
O << "#+" << OffImm;
|
||||
O << "#" << OffImm;
|
||||
}
|
||||
|
||||
void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI,
|
||||
int OpNum) {
|
||||
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
||||
int32_t OffImm = (int32_t)MO1.getImm() / 4;
|
||||
// Don't print +0.
|
||||
if (OffImm < 0)
|
||||
O << "#-" << -OffImm * 4;
|
||||
else if (OffImm > 0)
|
||||
O << "#" << OffImm * 4;
|
||||
}
|
||||
|
||||
void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
|
||||
|
@ -28,7 +28,165 @@ using namespace llvm;
|
||||
#undef MachineInstr
|
||||
#undef ARMAsmPrinter
|
||||
|
||||
void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); }
|
||||
static unsigned NextReg(unsigned Reg) {
|
||||
switch (Reg) {
|
||||
case ARM::D0:
|
||||
return ARM::D1;
|
||||
case ARM::D1:
|
||||
return ARM::D2;
|
||||
case ARM::D2:
|
||||
return ARM::D3;
|
||||
case ARM::D3:
|
||||
return ARM::D4;
|
||||
case ARM::D4:
|
||||
return ARM::D5;
|
||||
case ARM::D5:
|
||||
return ARM::D6;
|
||||
case ARM::D6:
|
||||
return ARM::D7;
|
||||
case ARM::D7:
|
||||
return ARM::D8;
|
||||
case ARM::D8:
|
||||
return ARM::D9;
|
||||
case ARM::D9:
|
||||
return ARM::D10;
|
||||
case ARM::D10:
|
||||
return ARM::D11;
|
||||
case ARM::D11:
|
||||
return ARM::D12;
|
||||
case ARM::D12:
|
||||
return ARM::D13;
|
||||
case ARM::D13:
|
||||
return ARM::D14;
|
||||
case ARM::D14:
|
||||
return ARM::D15;
|
||||
case ARM::D15:
|
||||
return ARM::D16;
|
||||
case ARM::D16:
|
||||
return ARM::D17;
|
||||
case ARM::D17:
|
||||
return ARM::D18;
|
||||
case ARM::D18:
|
||||
return ARM::D19;
|
||||
case ARM::D19:
|
||||
return ARM::D20;
|
||||
case ARM::D20:
|
||||
return ARM::D21;
|
||||
case ARM::D21:
|
||||
return ARM::D22;
|
||||
case ARM::D22:
|
||||
return ARM::D23;
|
||||
case ARM::D23:
|
||||
return ARM::D24;
|
||||
case ARM::D24:
|
||||
return ARM::D25;
|
||||
case ARM::D25:
|
||||
return ARM::D26;
|
||||
case ARM::D26:
|
||||
return ARM::D27;
|
||||
case ARM::D27:
|
||||
return ARM::D28;
|
||||
case ARM::D28:
|
||||
return ARM::D29;
|
||||
case ARM::D29:
|
||||
return ARM::D30;
|
||||
case ARM::D30:
|
||||
return ARM::D31;
|
||||
|
||||
default:
|
||||
assert(0 && "Unexpected register enum");
|
||||
}
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printInst(const MCInst *MI) {
|
||||
// Check for MOVs and print canonical forms, instead.
|
||||
if (MI->getOpcode() == ARM::MOVs) {
|
||||
const MCOperand &Dst = MI->getOperand(0);
|
||||
const MCOperand &MO1 = MI->getOperand(1);
|
||||
const MCOperand &MO2 = MI->getOperand(2);
|
||||
const MCOperand &MO3 = MI->getOperand(3);
|
||||
|
||||
O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm()));
|
||||
printSBitModifierOperand(MI, 6);
|
||||
printPredicateOperand(MI, 4);
|
||||
|
||||
O << '\t' << getRegisterName(Dst.getReg())
|
||||
<< ", " << getRegisterName(MO1.getReg());
|
||||
|
||||
if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx)
|
||||
return;
|
||||
|
||||
O << ", ";
|
||||
|
||||
if (MO2.getReg()) {
|
||||
O << getRegisterName(MO2.getReg());
|
||||
assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
|
||||
} else {
|
||||
O << "#" << ARM_AM::getSORegOffset(MO3.getImm());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// A8.6.123 PUSH
|
||||
if ((MI->getOpcode() == ARM::STM || MI->getOpcode() == ARM::t2STM_UPD) &&
|
||||
MI->getOperand(0).getReg() == ARM::SP) {
|
||||
const unsigned IdxOffset = MI->getOpcode() == ARM::STM ? 0 : 1;
|
||||
const MCOperand &MO1 = MI->getOperand(IdxOffset + 1);
|
||||
if (ARM_AM::getAM4WBFlag(MO1.getImm()) &&
|
||||
ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) {
|
||||
O << '\t' << "push";
|
||||
printPredicateOperand(MI, IdxOffset + 2);
|
||||
O << '\t';
|
||||
printRegisterList(MI, IdxOffset + 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// A8.6.122 POP
|
||||
if ((MI->getOpcode() == ARM::LDM || MI->getOpcode() == ARM::t2LDM_UPD) &&
|
||||
MI->getOperand(0).getReg() == ARM::SP) {
|
||||
const unsigned IdxOffset = MI->getOpcode() == ARM::LDM ? 0 : 1;
|
||||
const MCOperand &MO1 = MI->getOperand(IdxOffset + 1);
|
||||
if (ARM_AM::getAM4WBFlag(MO1.getImm()) &&
|
||||
ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) {
|
||||
O << '\t' << "pop";
|
||||
printPredicateOperand(MI, IdxOffset + 2);
|
||||
O << '\t';
|
||||
printRegisterList(MI, IdxOffset + 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// A8.6.355 VPUSH
|
||||
if ((MI->getOpcode() == ARM::VSTMS || MI->getOpcode() == ARM::VSTMD) &&
|
||||
MI->getOperand(0).getReg() == ARM::SP) {
|
||||
const MCOperand &MO1 = MI->getOperand(1);
|
||||
if (ARM_AM::getAM5WBFlag(MO1.getImm()) &&
|
||||
ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) {
|
||||
O << '\t' << "vpush";
|
||||
printPredicateOperand(MI, 2);
|
||||
O << '\t';
|
||||
printRegisterList(MI, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// A8.6.354 VPOP
|
||||
if ((MI->getOpcode() == ARM::VLDMS || MI->getOpcode() == ARM::VLDMD) &&
|
||||
MI->getOperand(0).getReg() == ARM::SP) {
|
||||
const MCOperand &MO1 = MI->getOperand(1);
|
||||
if (ARM_AM::getAM5WBFlag(MO1.getImm()) &&
|
||||
ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) {
|
||||
O << '\t' << "vpop";
|
||||
printPredicateOperand(MI, 2);
|
||||
O << '\t';
|
||||
printRegisterList(MI, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printInstruction(MI);
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||||
const char *Modifier) {
|
||||
@ -36,6 +194,9 @@ 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);
|
||||
/*
|
||||
@ -44,6 +205,7 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||||
O << '{'
|
||||
<< getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi)
|
||||
<< '}';*/
|
||||
#endif
|
||||
} else if (Modifier && strcmp(Modifier, "lane") == 0) {
|
||||
assert(0);
|
||||
/*
|
||||
@ -56,7 +218,9 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
||||
O << getRegisterName(Reg);
|
||||
}
|
||||
} else if (Op.isImm()) {
|
||||
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
|
||||
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
||||
assert(isCallOp ||
|
||||
((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"));
|
||||
O << '#' << Op.getImm();
|
||||
} else {
|
||||
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
|
||||
@ -142,17 +306,17 @@ 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 << ", #"
|
||||
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
||||
<< ARM_AM::getAM2Offset(MO3.getImm());
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||
<< ARM_AM::getAM2Offset(MO3.getImm());
|
||||
O << "]";
|
||||
return;
|
||||
}
|
||||
|
||||
O << ", "
|
||||
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
||||
<< getRegisterName(MO2.getReg());
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||
<< getRegisterName(MO2.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
|
||||
O << ", "
|
||||
@ -169,11 +333,14 @@ void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
|
||||
if (!MO1.getReg()) {
|
||||
unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
|
||||
assert(ImmOffs && "Malformed indexed load / store!");
|
||||
O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs;
|
||||
O << '#'
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
|
||||
<< ImmOffs;
|
||||
return;
|
||||
}
|
||||
|
||||
O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg());
|
||||
O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
|
||||
<< getRegisterName(MO1.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
|
||||
O << ", "
|
||||
@ -196,8 +363,8 @@ void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum) {
|
||||
|
||||
if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
|
||||
O << ", #"
|
||||
<< (char)ARM_AM::getAM3Op(MO3.getImm())
|
||||
<< ImmOffs;
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
|
||||
<< ImmOffs;
|
||||
O << ']';
|
||||
}
|
||||
|
||||
@ -214,9 +381,9 @@ void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI,
|
||||
|
||||
unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
|
||||
assert(ImmOffs && "Malformed indexed load / store!");
|
||||
O << "#"
|
||||
<< (char)ARM_AM::getAM3Op(MO2.getImm())
|
||||
<< ImmOffs;
|
||||
O << '#'
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm()))
|
||||
<< ImmOffs;
|
||||
}
|
||||
|
||||
|
||||
@ -264,7 +431,7 @@ void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum,
|
||||
|
||||
if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
|
||||
O << ", #"
|
||||
<< (char)ARM_AM::getAM5Op(MO2.getImm())
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
|
||||
<< ImmOffs*4;
|
||||
}
|
||||
O << "]";
|
||||
@ -303,14 +470,56 @@ void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI,
|
||||
|
||||
void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) {
|
||||
O << "{";
|
||||
// Always skip the first operand, it's the optional (and implicit writeback).
|
||||
for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) {
|
||||
if (i != OpNum+1) O << ", ";
|
||||
for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) {
|
||||
if (i != OpNum) O << ", ";
|
||||
O << getRegisterName(MI->getOperand(i).getReg());
|
||||
}
|
||||
O << "}";
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
unsigned option = Op.getImm();
|
||||
unsigned mode = option & 31;
|
||||
bool changemode = option >> 5 & 1;
|
||||
unsigned AIF = option >> 6 & 7;
|
||||
unsigned imod = option >> 9 & 3;
|
||||
if (imod == 2)
|
||||
O << "ie";
|
||||
else if (imod == 3)
|
||||
O << "id";
|
||||
O << '\t';
|
||||
if (imod > 1) {
|
||||
if (AIF & 4) O << 'a';
|
||||
if (AIF & 2) O << 'i';
|
||||
if (AIF & 1) O << 'f';
|
||||
if (AIF > 0 && changemode) O << ", ";
|
||||
}
|
||||
if (changemode)
|
||||
O << '#' << mode;
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
unsigned Mask = Op.getImm();
|
||||
if (Mask) {
|
||||
O << '_';
|
||||
if (Mask & 8) O << 'f';
|
||||
if (Mask & 4) O << 's';
|
||||
if (Mask & 2) O << 'x';
|
||||
if (Mask & 1) O << 'c';
|
||||
}
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
O << '#';
|
||||
if (Op.getImm() < 0)
|
||||
O << '-' << (-Op.getImm() - 1);
|
||||
else
|
||||
O << Op.getImm();
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) {
|
||||
ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
|
||||
if (CC != ARMCC::AL)
|
||||
@ -352,3 +561,191 @@ void ARMInstPrinter::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();
|
||||
}
|
||||
|
||||
|
@ -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, int OpNum) {}
|
||||
void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {}
|
||||
void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum);
|
||||
void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum);
|
||||
void printHex8ImmOperand(const MCInst *MI, int OpNum) {}
|
||||
void printHex16ImmOperand(const MCInst *MI, int OpNum) {}
|
||||
void printHex32ImmOperand(const MCInst *MI, int OpNum) {}
|
||||
|
513
lib/Target/ARM/Disassembler/ARMDisassembler.cpp
Normal file
513
lib/Target/ARM/Disassembler/ARMDisassembler.cpp
Normal file
@ -0,0 +1,513 @@
|
||||
//===- ARMDisassembler.cpp - Disassembler for ARM/Thumb ISA ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is part of the ARM Disassembler.
|
||||
// It contains code to translate the data produced by the decoder into MCInsts.
|
||||
// Documentation for the disassembler can be found in ARMDisassembler.h.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "arm-disassembler"
|
||||
|
||||
#include "ARMDisassembler.h"
|
||||
#include "ARMDisassemblerCore.h"
|
||||
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/Target/TargetRegistry.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
/// ARMDisassemblerTables.inc - ARMDisassemblerTables.inc is tblgen'ed from
|
||||
/// RISCDisassemblerEmitter.cpp TableGen backend. It contains:
|
||||
///
|
||||
/// o Mappings from opcode to ARM/Thumb instruction format
|
||||
///
|
||||
/// o static uint16_t decodeInstruction(uint32_t insn) - the decoding function
|
||||
/// for an ARM instruction.
|
||||
///
|
||||
/// o static uint16_t decodeThumbInstruction(field_t insn) - the decoding
|
||||
/// function for a Thumb instruction.
|
||||
///
|
||||
#include "../ARMGenDisassemblerTables.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace ARMDisassembler {
|
||||
|
||||
/// showBitVector - Use the raw_ostream to log a diagnostic message describing
|
||||
/// the inidividual bits of the instruction. This is a sample output:
|
||||
///
|
||||
/// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
/// -------------------------------------------------------------------------------------------------
|
||||
/// | 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0|
|
||||
/// -------------------------------------------------------------------------------------------------
|
||||
///
|
||||
static inline void showBitVector(raw_ostream &os, const uint32_t &insn) {
|
||||
os << " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 \n";
|
||||
os << "-------------------------------------------------------------------------------------------------\n";
|
||||
os << '|';
|
||||
for (unsigned i = 32; i != 0; --i) {
|
||||
if (insn >> (i - 1) & 0x01)
|
||||
os << " 1";
|
||||
else
|
||||
os << " 0";
|
||||
os << (i%4 == 1 ? '|' : ':');
|
||||
}
|
||||
os << '\n';
|
||||
os << "-------------------------------------------------------------------------------------------------\n";
|
||||
os << '\n';
|
||||
}
|
||||
|
||||
/// decodeARMInstruction is a decorator function which tries special cases of
|
||||
/// instruction matching before calling the auto-generated decoder function.
|
||||
static unsigned decodeARMInstruction(uint32_t &insn) {
|
||||
if (slice(insn, 31, 28) == 15)
|
||||
goto AutoGenedDecoder;
|
||||
|
||||
// Special case processing, if any, goes here....
|
||||
|
||||
// LLVM combines the offset mode of A8.6.197 & A8.6.198 into STRB.
|
||||
// The insufficient encoding information of the combined instruction confuses
|
||||
// the decoder wrt BFC/BFI. Therefore, we try to recover here.
|
||||
// For BFC, Inst{27-21} = 0b0111110 & Inst{6-0} = 0b0011111.
|
||||
// For BFI, Inst{27-21} = 0b0111110 & Inst{6-4} = 0b001 & Inst{3-0} =! 0b1111.
|
||||
if (slice(insn, 27, 21) == 0x3e && slice(insn, 6, 4) == 1) {
|
||||
if (slice(insn, 3, 0) == 15)
|
||||
return ARM::BFC;
|
||||
else
|
||||
return ARM::BFI;
|
||||
}
|
||||
|
||||
// Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8.
|
||||
// As a result, the decoder fails to decode UMULL properly.
|
||||
if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) {
|
||||
return ARM::UMULL;
|
||||
}
|
||||
|
||||
// Ditto for STR_PRE, which is a super-instruction for A8.6.194 & A8.6.195.
|
||||
// As a result, the decoder fails to decode SBFX properly.
|
||||
if (slice(insn, 27, 21) == 0x3d && slice(insn, 6, 4) == 5)
|
||||
return ARM::SBFX;
|
||||
|
||||
// And STRB_PRE, which is a super-instruction for A8.6.197 & A8.6.198.
|
||||
// As a result, the decoder fails to decode UBFX properly.
|
||||
if (slice(insn, 27, 21) == 0x3f && slice(insn, 6, 4) == 5)
|
||||
return ARM::UBFX;
|
||||
|
||||
// Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2.
|
||||
// As a result, the decoder fails to deocode SSAT properly.
|
||||
if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1)
|
||||
return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr;
|
||||
|
||||
// Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147.
|
||||
// As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT.
|
||||
if (slice(insn, 27, 24) == 0) {
|
||||
switch (slice(insn, 21, 20)) {
|
||||
case 2:
|
||||
switch (slice(insn, 7, 4)) {
|
||||
case 11:
|
||||
return ARM::STRHT;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (slice(insn, 7, 4)) {
|
||||
case 11:
|
||||
return ARM::LDRHT;
|
||||
case 13:
|
||||
return ARM::LDRSBT;
|
||||
case 15:
|
||||
return ARM::LDRSHT;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
}
|
||||
|
||||
// Ditto for SBCrs, which is a super-instruction for A8.6.152 & A8.6.153.
|
||||
// As a result, the decoder fails to decode STRH_Post/LDRD_POST/STRD_POST
|
||||
// properly.
|
||||
if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 0) {
|
||||
unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21);
|
||||
switch (slice(insn, 7, 4)) {
|
||||
case 11:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::STRH;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::STRH_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::STRH_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::LDRD;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::LDRD_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::LDRD_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::STRD;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::STRD_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::STRD_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
}
|
||||
|
||||
// Ditto for SBCSSrs, which is a super-instruction for A8.6.152 & A8.6.153.
|
||||
// As a result, the decoder fails to decode LDRH_POST/LDRSB_POST/LDRSH_POST
|
||||
// properly.
|
||||
if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 1) {
|
||||
unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21);
|
||||
switch (slice(insn, 7, 4)) {
|
||||
case 11:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::LDRH;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::LDRH_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::LDRH_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::LDRSB;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::LDRSB_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::LDRSB_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
switch (PW) {
|
||||
case 2: // Offset
|
||||
return ARM::LDRSH;
|
||||
case 3: // Pre-indexed
|
||||
return ARM::LDRSH_PRE;
|
||||
case 0: // Post-indexed
|
||||
return ARM::LDRSH_POST;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // fallthrough
|
||||
}
|
||||
}
|
||||
|
||||
AutoGenedDecoder:
|
||||
// Calling the auto-generated decoder function.
|
||||
return decodeInstruction(insn);
|
||||
}
|
||||
|
||||
// Helper function for special case handling of LDR (literal) and friends.
|
||||
// See, for example, A6.3.7 Load word: Table A6-18 Load word.
|
||||
// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode
|
||||
// before passing it on.
|
||||
static unsigned T2Morph2LoadLiteral(unsigned Opcode) {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
return Opcode; // Return unmorphed opcode.
|
||||
|
||||
case ARM::t2LDRDi8:
|
||||
return ARM::t2LDRDpci;
|
||||
|
||||
case ARM::t2LDR_POST: case ARM::t2LDR_PRE:
|
||||
case ARM::t2LDRi12: case ARM::t2LDRi8:
|
||||
case ARM::t2LDRs:
|
||||
return ARM::t2LDRpci;
|
||||
|
||||
case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE:
|
||||
case ARM::t2LDRBi12: case ARM::t2LDRBi8:
|
||||
case ARM::t2LDRBs:
|
||||
return ARM::t2LDRBpci;
|
||||
|
||||
case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE:
|
||||
case ARM::t2LDRHi12: case ARM::t2LDRHi8:
|
||||
case ARM::t2LDRHs:
|
||||
return ARM::t2LDRHpci;
|
||||
|
||||
case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE:
|
||||
case ARM::t2LDRSBi12: case ARM::t2LDRSBi8:
|
||||
case ARM::t2LDRSBs:
|
||||
return ARM::t2LDRSBpci;
|
||||
|
||||
case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE:
|
||||
case ARM::t2LDRSHi12: case ARM::t2LDRSHi8:
|
||||
case ARM::t2LDRSHs:
|
||||
return ARM::t2LDRSHpci;
|
||||
}
|
||||
}
|
||||
|
||||
/// decodeThumbSideEffect is a decorator function which can potentially twiddle
|
||||
/// the instruction or morph the returned opcode under Thumb2.
|
||||
///
|
||||
/// First it checks whether the insn is a NEON or VFP instr; if true, bit
|
||||
/// twiddling could be performed on insn to turn it into an ARM NEON/VFP
|
||||
/// equivalent instruction and decodeInstruction is called with the transformed
|
||||
/// insn.
|
||||
///
|
||||
/// Next, there is special handling for Load byte/halfword/word instruction by
|
||||
/// checking whether Rn=0b1111 and call T2Morph2LoadLiteral() on the decoded
|
||||
/// Thumb2 instruction. See comments below for further details.
|
||||
///
|
||||
/// Finally, one last check is made to see whether the insn is a NEON/VFP and
|
||||
/// decodeInstruction(insn) is invoked on the original insn.
|
||||
///
|
||||
/// Otherwise, decodeThumbInstruction is called with the original insn.
|
||||
static unsigned decodeThumbSideEffect(bool IsThumb2, uint32_t &insn) {
|
||||
if (IsThumb2) {
|
||||
uint16_t op1 = slice(insn, 28, 27);
|
||||
uint16_t op2 = slice(insn, 26, 20);
|
||||
|
||||
// A6.3 32-bit Thumb instruction encoding
|
||||
// Table A6-9 32-bit Thumb instruction encoding
|
||||
|
||||
// The coprocessor instructions of interest are transformed to their ARM
|
||||
// equivalents.
|
||||
|
||||
// --------- Transform Begin Marker ---------
|
||||
if ((op1 == 1 || op1 == 3) && slice(op2, 6, 4) == 7) {
|
||||
// A7.4 Advanced SIMD data-processing instructions
|
||||
// U bit of Thumb corresponds to Inst{24} of ARM.
|
||||
uint16_t U = slice(op1, 1, 1);
|
||||
|
||||
// Inst{28-24} of ARM = {1,0,0,1,U};
|
||||
uint16_t bits28_24 = 9 << 1 | U;
|
||||
DEBUG(showBitVector(errs(), insn));
|
||||
setSlice(insn, 28, 24, bits28_24);
|
||||
return decodeInstruction(insn);
|
||||
}
|
||||
|
||||
if (op1 == 3 && slice(op2, 6, 4) == 1 && slice(op2, 0, 0) == 0) {
|
||||
// A7.7 Advanced SIMD element or structure load/store instructions
|
||||
// Inst{27-24} of Thumb = 0b1001
|
||||
// Inst{27-24} of ARM = 0b0100
|
||||
DEBUG(showBitVector(errs(), insn));
|
||||
setSlice(insn, 27, 24, 4);
|
||||
return decodeInstruction(insn);
|
||||
}
|
||||
// --------- Transform End Marker ---------
|
||||
|
||||
// See, for example, A6.3.7 Load word: Table A6-18 Load word.
|
||||
// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode
|
||||
// before passing it on to our delegate.
|
||||
if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1
|
||||
&& slice(insn, 19, 16) == 15)
|
||||
return T2Morph2LoadLiteral(decodeThumbInstruction(insn));
|
||||
|
||||
// One last check for NEON/VFP instructions.
|
||||
if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1)
|
||||
return decodeInstruction(insn);
|
||||
|
||||
// Fall through.
|
||||
}
|
||||
|
||||
return decodeThumbInstruction(insn);
|
||||
}
|
||||
|
||||
static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
return false;
|
||||
case ARM::t2PLDi12: case ARM::t2PLDi8:
|
||||
case ARM::t2PLDr: case ARM::t2PLDs:
|
||||
case ARM::t2PLDWi12: case ARM::t2PLDWi8:
|
||||
case ARM::t2PLDWr: case ARM::t2PLDWs:
|
||||
case ARM::t2PLIi12: case ARM::t2PLIi8:
|
||||
case ARM::t2PLIr: case ARM::t2PLIs:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
return 0;
|
||||
case ARM::t2PLDi12: case ARM::t2PLDi8:
|
||||
case ARM::t2PLDr: case ARM::t2PLDs:
|
||||
return ARM::t2PLDpci;
|
||||
case ARM::t2PLDWi12: case ARM::t2PLDWi8:
|
||||
case ARM::t2PLDWr: case ARM::t2PLDWs:
|
||||
return ARM::t2PLDWpci;
|
||||
case ARM::t2PLIi12: case ARM::t2PLIi8:
|
||||
case ARM::t2PLIr: case ARM::t2PLIs:
|
||||
return ARM::t2PLIpci;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Public interface for the disassembler
|
||||
//
|
||||
|
||||
bool ARMDisassembler::getInstruction(MCInst &MI,
|
||||
uint64_t &Size,
|
||||
const MemoryObject &Region,
|
||||
uint64_t Address,
|
||||
raw_ostream &os) const {
|
||||
// The machine instruction.
|
||||
uint32_t insn;
|
||||
|
||||
// We want to read exactly 4 bytes of data.
|
||||
if (Region.readBytes(Address, 4, (uint8_t*)&insn, NULL) == -1)
|
||||
return false;
|
||||
|
||||
unsigned Opcode = decodeARMInstruction(insn);
|
||||
ARMFormat Format = ARMFormats[Opcode];
|
||||
NSFormat NSF = NSFormats[Opcode];
|
||||
Size = 4;
|
||||
|
||||
DEBUG({
|
||||
errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode)
|
||||
<< " Format=" << stringForARMFormat(Format) << " NSFormat="
|
||||
<< stringForNSFormat(NSF) << '\n';
|
||||
showBitVector(errs(), insn);
|
||||
});
|
||||
|
||||
AbstractARMMCBuilder *Builder =
|
||||
ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF);
|
||||
|
||||
if (!Builder)
|
||||
return false;
|
||||
|
||||
if (!Builder->Build(MI, insn))
|
||||
return false;
|
||||
|
||||
delete Builder;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbDisassembler::getInstruction(MCInst &MI,
|
||||
uint64_t &Size,
|
||||
const MemoryObject &Region,
|
||||
uint64_t Address,
|
||||
raw_ostream &os) const {
|
||||
// The machine instruction.
|
||||
uint32_t insn = 0;
|
||||
uint32_t insn1 = 0;
|
||||
|
||||
// A6.1 Thumb instruction set encoding
|
||||
//
|
||||
// If bits [15:11] of the halfword being decoded take any of the following
|
||||
// values, the halfword is the first halfword of a 32-bit instruction:
|
||||
// o 0b11101
|
||||
// o 0b11110
|
||||
// o 0b11111.
|
||||
//
|
||||
// Otherwise, the halfword is a 16-bit instruction.
|
||||
|
||||
// Read 2 bytes of data first.
|
||||
if (Region.readBytes(Address, 2, (uint8_t*)&insn, NULL) == -1)
|
||||
return false;
|
||||
|
||||
unsigned bits15_11 = slice(insn, 15, 11);
|
||||
bool IsThumb2 = false;
|
||||
|
||||
// 32-bit instructions if the bits [15:11] of the halfword matches
|
||||
// { 0b11101 /* 0x1D */, 0b11110 /* 0x1E */, ob11111 /* 0x1F */ }.
|
||||
if (bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) {
|
||||
IsThumb2 = true;
|
||||
if (Region.readBytes(Address + 2, 2, (uint8_t*)&insn1, NULL) == -1)
|
||||
return false;
|
||||
insn = (insn << 16 | insn1);
|
||||
}
|
||||
|
||||
// The insn could potentially be bit-twiddled in order to be decoded as an ARM
|
||||
// NEON/VFP opcode. In such case, the modified insn is later disassembled as
|
||||
// an ARM NEON/VFP instruction.
|
||||
//
|
||||
// This is a short term solution for lack of encoding bits specified for the
|
||||
// Thumb2 NEON/VFP instructions. The long term solution could be adding some
|
||||
// infrastructure to have each instruction support more than one encodings.
|
||||
// Which encoding is used would be based on which subtarget the compiler/
|
||||
// disassembler is working with at the time. This would allow the sharing of
|
||||
// the NEON patterns between ARM and Thumb2, as well as potential greater
|
||||
// sharing between the regular ARM instructions and the 32-bit wide Thumb2
|
||||
// instructions as well.
|
||||
unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn);
|
||||
|
||||
// A8.6.117/119/120/121.
|
||||
// PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant.
|
||||
if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15)
|
||||
Opcode = T2Morph2Preload2PCI(Opcode);
|
||||
|
||||
ARMFormat Format = ARMFormats[Opcode];
|
||||
NSFormat NSF = NSFormats[Opcode];
|
||||
Size = IsThumb2 ? 4 : 2;
|
||||
|
||||
DEBUG({
|
||||
errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode)
|
||||
<< " Format=" << stringForARMFormat(Format) << " NSFormat="
|
||||
<< stringForNSFormat(NSF) << '\n';
|
||||
showBitVector(errs(), insn);
|
||||
});
|
||||
|
||||
AbstractARMMCBuilder *Builder =
|
||||
ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF);
|
||||
|
||||
if (!Builder)
|
||||
return false;
|
||||
|
||||
if (!Builder->Build(MI, insn))
|
||||
return false;
|
||||
|
||||
delete Builder;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ARM Disassembler
|
||||
|
||||
static const MCDisassembler *createARMDisassembler(const Target &T) {
|
||||
return new ARMDisassembler::ARMDisassembler;
|
||||
}
|
||||
|
||||
static const MCDisassembler *createThumbDisassembler(const Target &T) {
|
||||
return new ARMDisassembler::ThumbDisassembler;
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeARMDisassembler() {
|
||||
// Register the disassembler.
|
||||
TargetRegistry::RegisterMCDisassembler(TheARMTarget,
|
||||
createARMDisassembler);
|
||||
TargetRegistry::RegisterMCDisassembler(TheThumbTarget,
|
||||
createThumbDisassembler);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
71
lib/Target/ARM/Disassembler/ARMDisassembler.h
Normal file
71
lib/Target/ARM/Disassembler/ARMDisassembler.h
Normal file
@ -0,0 +1,71 @@
|
||||
//===- X86Disassembler.h - Disassembler for x86 and x86_64 ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMDISASSEMBLER_H
|
||||
#define ARMDISASSEMBLER_H
|
||||
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCInst;
|
||||
class MemoryObject;
|
||||
class raw_ostream;
|
||||
|
||||
namespace ARMDisassembler {
|
||||
|
||||
/// ARMDisassembler - ARM disassembler for all ARM platforms.
|
||||
class ARMDisassembler : public MCDisassembler {
|
||||
public:
|
||||
/// Constructor - Initializes the disassembler.
|
||||
///
|
||||
ARMDisassembler() :
|
||||
MCDisassembler() {
|
||||
}
|
||||
|
||||
~ARMDisassembler() {
|
||||
}
|
||||
|
||||
/// getInstruction - See MCDisassembler.
|
||||
bool getInstruction(MCInst &instr,
|
||||
uint64_t &size,
|
||||
const MemoryObject ®ion,
|
||||
uint64_t address,
|
||||
raw_ostream &vStream) const;
|
||||
private:
|
||||
};
|
||||
|
||||
/// ThumbDisassembler - Thumb disassembler for all ARM platforms.
|
||||
class ThumbDisassembler : public MCDisassembler {
|
||||
public:
|
||||
/// Constructor - Initializes the disassembler.
|
||||
///
|
||||
ThumbDisassembler() :
|
||||
MCDisassembler() {
|
||||
}
|
||||
|
||||
~ThumbDisassembler() {
|
||||
}
|
||||
|
||||
/// getInstruction - See MCDisassembler.
|
||||
bool getInstruction(MCInst &instr,
|
||||
uint64_t &size,
|
||||
const MemoryObject ®ion,
|
||||
uint64_t address,
|
||||
raw_ostream &vStream) const;
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace ARMDisassembler
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
3351
lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
Normal file
3351
lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
Normal file
File diff suppressed because it is too large
Load Diff
301
lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
Normal file
301
lib/Target/ARM/Disassembler/ARMDisassemblerCore.h
Normal file
@ -0,0 +1,301 @@
|
||||
//===- ARMDisassemblerCore.h - ARM disassembler helpers ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is part of the ARM Disassembler.
|
||||
//
|
||||
// The first part defines the enumeration type of ARM instruction format, which
|
||||
// specifies the encoding used by the instruction, as well as a helper function
|
||||
// to convert the enums to printable char strings.
|
||||
//
|
||||
// It also contains code to represent the concepts of Builder, Builder Factory,
|
||||
// as well as the Algorithm to solve the problem of disassembling an ARM instr.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMDISASSEMBLERCORE_H
|
||||
#define ARMDISASSEMBLERCORE_H
|
||||
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "ARMInstrInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ARMUtils {
|
||||
public:
|
||||
static const char *OpcodeName(unsigned Opcode);
|
||||
};
|
||||
|
||||
#define ARM_FORMATS \
|
||||
ENTRY(ARM_FORMAT_PSEUDO, 0) \
|
||||
ENTRY(ARM_FORMAT_MULFRM, 1) \
|
||||
ENTRY(ARM_FORMAT_BRFRM, 2) \
|
||||
ENTRY(ARM_FORMAT_BRMISCFRM, 3) \
|
||||
ENTRY(ARM_FORMAT_DPFRM, 4) \
|
||||
ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \
|
||||
ENTRY(ARM_FORMAT_LDFRM, 6) \
|
||||
ENTRY(ARM_FORMAT_STFRM, 7) \
|
||||
ENTRY(ARM_FORMAT_LDMISCFRM, 8) \
|
||||
ENTRY(ARM_FORMAT_STMISCFRM, 9) \
|
||||
ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \
|
||||
ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \
|
||||
ENTRY(ARM_FORMAT_EXTFRM, 12) \
|
||||
ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \
|
||||
ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \
|
||||
ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \
|
||||
ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \
|
||||
ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \
|
||||
ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \
|
||||
ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \
|
||||
ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \
|
||||
ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \
|
||||
ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \
|
||||
ENTRY(ARM_FORMAT_THUMBFRM, 23) \
|
||||
ENTRY(ARM_FORMAT_NEONFRM, 24) \
|
||||
ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \
|
||||
ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \
|
||||
ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \
|
||||
ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \
|
||||
ENTRY(ARM_FORMAT_MISCFRM, 29) \
|
||||
ENTRY(ARM_FORMAT_THUMBMISCFRM, 30)
|
||||
|
||||
// ARM instruction format specifies the encoding used by the instruction.
|
||||
#define ENTRY(n, v) n = v,
|
||||
typedef enum {
|
||||
ARM_FORMATS
|
||||
ARM_FORMAT_NA
|
||||
} ARMFormat;
|
||||
#undef ENTRY
|
||||
|
||||
// Converts enum to const char*.
|
||||
static const inline char *stringForARMFormat(ARMFormat form) {
|
||||
#define ENTRY(n, v) case n: return #n;
|
||||
switch(form) {
|
||||
ARM_FORMATS
|
||||
case ARM_FORMAT_NA:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef ENTRY
|
||||
}
|
||||
|
||||
#define NS_FORMATS \
|
||||
ENTRY(NS_FORMAT_NONE, 0) \
|
||||
ENTRY(NS_FORMAT_VLDSTLane, 1) \
|
||||
ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \
|
||||
ENTRY(NS_FORMAT_VLDSTRQ, 3) \
|
||||
ENTRY(NS_FORMAT_NVdImm, 4) \
|
||||
ENTRY(NS_FORMAT_NVdVmImm, 5) \
|
||||
ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \
|
||||
ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \
|
||||
ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \
|
||||
ENTRY(NS_FORMAT_NVectorShuffle, 9) \
|
||||
ENTRY(NS_FORMAT_NVectorShift, 10) \
|
||||
ENTRY(NS_FORMAT_NVectorShift2, 11) \
|
||||
ENTRY(NS_FORMAT_NVdVnVmImm, 12) \
|
||||
ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \
|
||||
ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \
|
||||
ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \
|
||||
ENTRY(NS_FORMAT_VTBL, 16)
|
||||
|
||||
// NEON instruction sub-format further classify the NEONFrm instruction.
|
||||
#define ENTRY(n, v) n = v,
|
||||
typedef enum {
|
||||
NS_FORMATS
|
||||
NS_FORMAT_NA
|
||||
} NSFormat;
|
||||
#undef ENTRY
|
||||
|
||||
// Converts enum to const char*.
|
||||
static const inline char *stringForNSFormat(NSFormat form) {
|
||||
#define ENTRY(n, v) case n: return #n;
|
||||
switch(form) {
|
||||
NS_FORMATS
|
||||
case NS_FORMAT_NA:
|
||||
return "NA";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
#undef ENTRY
|
||||
}
|
||||
|
||||
/// Expands on the enum definitions from ARMBaseInstrInfo.h.
|
||||
/// They are being used by the disassembler implementation.
|
||||
namespace ARMII {
|
||||
enum {
|
||||
NEONRegMask = 15,
|
||||
GPRRegMask = 15,
|
||||
NEON_RegRdShift = 12,
|
||||
NEON_D_BitShift = 22,
|
||||
NEON_RegRnShift = 16,
|
||||
NEON_N_BitShift = 7,
|
||||
NEON_RegRmShift = 0,
|
||||
NEON_M_BitShift = 5
|
||||
};
|
||||
}
|
||||
|
||||
/// Utility function for extracting [From, To] bits from a uint32_t.
|
||||
static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) {
|
||||
assert(From < 32 && To < 32 && From >= To);
|
||||
return (Bits >> To) & ((1 << (From - To + 1)) - 1);
|
||||
}
|
||||
|
||||
/// Utility function for setting [From, To] bits to Val for a uint32_t.
|
||||
static inline void setSlice(uint32_t &Bits, unsigned From, unsigned To,
|
||||
uint32_t Val) {
|
||||
assert(From < 32 && To < 32 && From >= To);
|
||||
uint32_t Mask = ((1 << (From - To + 1)) - 1);
|
||||
Bits &= ~(Mask << To);
|
||||
Bits |= (Val & Mask) << To;
|
||||
}
|
||||
|
||||
/// Various utilities for checking the target specific flags.
|
||||
|
||||
/// A unary data processing instruction doesn't have an Rn operand.
|
||||
static inline bool isUnaryDP(unsigned TSFlags) {
|
||||
return (TSFlags & ARMII::UnaryDP);
|
||||
}
|
||||
|
||||
/// This four-bit field describes the addressing mode used.
|
||||
/// See also ARMBaseInstrInfo.h.
|
||||
static inline unsigned getAddrMode(unsigned TSFlags) {
|
||||
return (TSFlags & ARMII::AddrModeMask);
|
||||
}
|
||||
|
||||
/// {IndexModePre, IndexModePost}
|
||||
/// Only valid for load and store ops.
|
||||
/// See also ARMBaseInstrInfo.h.
|
||||
static inline unsigned getIndexMode(unsigned TSFlags) {
|
||||
return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
|
||||
}
|
||||
|
||||
/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList.
|
||||
static inline bool isPrePostLdSt(unsigned TSFlags) {
|
||||
return (TSFlags & ARMII::IndexModeMask) != 0;
|
||||
}
|
||||
|
||||
/// AbstractARMMCBuilder - AbstractARMMCBuilder represents an interface of ARM
|
||||
/// MCInst builder that knows how to build up the MCOperand list.
|
||||
class AbstractARMMCBuilder {
|
||||
public:
|
||||
/// Build - Build the MCInst fully and return true. Return false if any
|
||||
/// failure occurs.
|
||||
virtual bool Build(MCInst &MI, uint32_t insn) { return false; }
|
||||
};
|
||||
|
||||
/// ARMDisassemblyAlgorithm - ARMDisassemblyAlgorithm represents an interface of
|
||||
/// ARM disassembly algorithm that relies on the entries of target operand info,
|
||||
/// among other things, to solve the problem of disassembling an ARM machine
|
||||
/// instruction.
|
||||
class ARMDisassemblyAlgorithm {
|
||||
public:
|
||||
/// Return true if this algorithm successfully disassembles the instruction.
|
||||
/// NumOpsAdded is updated to reflect the number of operands added by the
|
||||
/// algorithm. NumOpsAdded may be less than NumOps, in which case, there are
|
||||
/// operands unaccounted for which need to be dealt with by the API client.
|
||||
virtual bool Solve(MCInst& MI, unsigned Opcode, uint32_t insn,
|
||||
unsigned short NumOps, unsigned &NumOpsAdded) const
|
||||
= 0;
|
||||
};
|
||||
|
||||
/// ARMBasicMCBuilder - ARMBasicMCBuilder represents a concrete subclass of
|
||||
/// ARMAbstractMCBuilder.
|
||||
class ARMBasicMCBuilder : public AbstractARMMCBuilder {
|
||||
unsigned Opcode;
|
||||
ARMFormat Format;
|
||||
NSFormat NSF;
|
||||
unsigned short NumOps;
|
||||
const ARMDisassemblyAlgorithm &Algo;
|
||||
static unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4.
|
||||
static unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially.
|
||||
|
||||
public:
|
||||
ARMBasicMCBuilder(ARMBasicMCBuilder &MCB) : AbstractARMMCBuilder(),
|
||||
Opcode(MCB.Opcode), Format(MCB.Format), NSF(MCB.NSF), NumOps(MCB.NumOps),
|
||||
Algo(MCB.Algo) {}
|
||||
|
||||
/// Opcode, Format, NSF, NumOperands, and Algo make an ARM Basic MCBuilder.
|
||||
ARMBasicMCBuilder(unsigned opc, ARMFormat format, NSFormat NSF,
|
||||
unsigned short num, const ARMDisassemblyAlgorithm &algo)
|
||||
: AbstractARMMCBuilder(), Opcode(opc), Format(format), NumOps(num),
|
||||
Algo(algo) {}
|
||||
|
||||
/// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process
|
||||
/// the possible Predicate and SBitModifier, to build the remaining MCOperand
|
||||
/// constituents.
|
||||
static bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode,
|
||||
uint32_t insn, unsigned short NumOpsRemaning);
|
||||
|
||||
/// InITBlock - InITBlock returns true if we are inside an IT block.
|
||||
static bool InITBlock() {
|
||||
return ITCounter > 0;
|
||||
}
|
||||
|
||||
/// Build - Build delegates to BuildIt to perform the heavy liftling. After
|
||||
/// that, it invokes RunBuildAfterHook where some housekeepings can be done.
|
||||
virtual bool Build(MCInst &MI, uint32_t insn) {
|
||||
bool Status = BuildIt(MI, insn);
|
||||
return RunBuildAfterHook(Status, MI, insn);
|
||||
}
|
||||
|
||||
/// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder.
|
||||
/// The general idea is to set the Opcode for the MCInst, followed by adding
|
||||
/// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates
|
||||
/// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific
|
||||
/// disassembly, followed by class method TryPredicateAndSBitModifier() to do
|
||||
/// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands.
|
||||
virtual bool BuildIt(MCInst &MI, uint32_t insn);
|
||||
|
||||
/// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary
|
||||
/// after BuildIt is finished.
|
||||
virtual bool RunBuildAfterHook(bool Status, MCInst &MI, uint32_t insn);
|
||||
|
||||
private:
|
||||
/// Get condition of the current IT instruction.
|
||||
static unsigned GetITCond() {
|
||||
return slice(ITState, 7, 4);
|
||||
}
|
||||
|
||||
/// Init ITState.
|
||||
static void InitITState(unsigned short bits7_0) {
|
||||
ITState = bits7_0;
|
||||
}
|
||||
|
||||
/// Update ITState if necessary.
|
||||
static void UpdateITState() {
|
||||
assert(ITCounter);
|
||||
--ITCounter;
|
||||
if (ITCounter == 0)
|
||||
ITState = 0;
|
||||
else {
|
||||
unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1;
|
||||
setSlice(ITState, 4, 0, NewITState4_0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// ARMMCBuilderFactory - ARMMCBuilderFactory represents the factory class that
|
||||
/// vends out ARMAbstractMCBuilder instances through its class method.
|
||||
class ARMMCBuilderFactory {
|
||||
private:
|
||||
ARMMCBuilderFactory(); // DO NOT IMPLEMENT.
|
||||
|
||||
public:
|
||||
/// CreateMCBuilder - Return an AbstractARMMCBuilder that can build up the MC
|
||||
/// infrastructure of an MCInst given the Opcode and Format of the instr.
|
||||
/// Return NULL if it fails to create/return a proper builder. API clients
|
||||
/// are responsible for freeing up of the allocated memory. Cacheing can be
|
||||
/// performed by the API clients to improve performance.
|
||||
static AbstractARMMCBuilder *CreateMCBuilder(unsigned Opcode,
|
||||
ARMFormat Format, NSFormat NSF);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
17
lib/Target/ARM/Disassembler/Makefile
Normal file
17
lib/Target/ARM/Disassembler/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- lib/Target/ARM/Disassembler/Makefile ----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
LIBRARYNAME = LLVMARMDisassembler
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
# Hack: we need to include 'main' arm target directory to grab private headers
|
||||
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
2158
lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc
Normal file
2158
lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,8 +16,9 @@ BUILT_SOURCES = ARMGenRegisterInfo.h.inc ARMGenRegisterNames.inc \
|
||||
ARMGenRegisterInfo.inc ARMGenInstrNames.inc \
|
||||
ARMGenInstrInfo.inc ARMGenAsmWriter.inc \
|
||||
ARMGenDAGISel.inc ARMGenSubtarget.inc \
|
||||
ARMGenCodeEmitter.inc ARMGenCallingConv.inc
|
||||
ARMGenCodeEmitter.inc ARMGenCallingConv.inc \
|
||||
ARMGenDisassemblerTables.inc
|
||||
|
||||
DIRS = AsmPrinter AsmParser TargetInfo
|
||||
DIRS = AsmPrinter AsmParser Disassembler TargetInfo
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -78,14 +78,16 @@ bool Thumb2ITBlockPass::InsertITBlocks(MachineBasicBlock &MBB) {
|
||||
DebugLoc ndl = NMI->getDebugLoc();
|
||||
unsigned NPredReg = 0;
|
||||
ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg);
|
||||
if (NCC == OCC) {
|
||||
Mask |= (1 << Pos);
|
||||
} else if (NCC != CC)
|
||||
if (NCC == CC || NCC == OCC)
|
||||
Mask |= (NCC & 1) << Pos;
|
||||
else
|
||||
break;
|
||||
--Pos;
|
||||
++MBBI;
|
||||
}
|
||||
Mask |= (1 << Pos);
|
||||
// Tag along (firstcond[0] << 4) with the mask.
|
||||
Mask |= (CC & 1) << 4;
|
||||
MIB.addImm(Mask);
|
||||
Modified = true;
|
||||
++NumITs;
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
define void @test(i32* %P, i32 %A, i32 %i) nounwind {
|
||||
entry:
|
||||
; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2]
|
||||
; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2]
|
||||
icmp eq i32 %i, 0 ; <i1>:0 [#uses=1]
|
||||
br i1 %0, label %return, label %bb
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
define void @test1(i32* %X, i32* %A, i32** %dest) {
|
||||
; CHECK: test1
|
||||
; CHECK: str r1, [r0, #+16]!
|
||||
; CHECK: str r1, [r0, #16]!
|
||||
%B = load i32* %A ; <i32> [#uses=1]
|
||||
%Y = getelementptr i32* %X, i32 4 ; <i32*> [#uses=2]
|
||||
store i32 %B, i32* %Y
|
||||
@ -12,7 +12,7 @@ define 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 ; <i32> [#uses=1]
|
||||
%Y = getelementptr i16* %X, i32 4 ; <i16*> [#uses=2]
|
||||
%tmp = trunc i32 %B to i16 ; <i16> [#uses=1]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "Record.h"
|
||||
#include "X86DisassemblerTables.h"
|
||||
#include "X86RecognizableInstr.h"
|
||||
#include "RISCDisassemblerEmitter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::X86Disassembler;
|
||||
|
||||
@ -124,6 +126,12 @@ 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");
|
||||
}
|
||||
|
1743
utils/TableGen/RISCDisassemblerEmitter.cpp
Normal file
1743
utils/TableGen/RISCDisassemblerEmitter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
utils/TableGen/RISCDisassemblerEmitter.h
Normal file
48
utils/TableGen/RISCDisassemblerEmitter.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===- RISCDisassemblerEmitter.h - Disassembler Generator -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: document
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef RISCDISASSEMBLEREMITTER_H
|
||||
#define RISCDISASSEMBLEREMITTER_H
|
||||
|
||||
#include "TableGenBackend.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RISCDisassemblerEmitter : public TableGenBackend {
|
||||
RecordKeeper &Records;
|
||||
public:
|
||||
RISCDisassemblerEmitter(RecordKeeper &R) : Records(R) {
|
||||
initBackend();
|
||||
}
|
||||
|
||||
~RISCDisassemblerEmitter() {
|
||||
shutdownBackend();
|
||||
}
|
||||
|
||||
// run - Output the code emitter
|
||||
void run(raw_ostream &o);
|
||||
|
||||
private:
|
||||
class RISCDEBackend;
|
||||
|
||||
RISCDEBackend *Backend;
|
||||
|
||||
void initBackend();
|
||||
void shutdownBackend();
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
@ -31,6 +31,7 @@
|
||||
#include "OptParserEmitter.h"
|
||||
#include "Record.h"
|
||||
#include "RegisterInfoEmitter.h"
|
||||
#include "RISCDisassemblerEmitter.h"
|
||||
#include "SubtargetEmitter.h"
|
||||
#include "TGParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
@ -48,6 +49,7 @@ enum ActionType {
|
||||
GenEmitter,
|
||||
GenRegisterEnums, GenRegister, GenRegisterHeader,
|
||||
GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher,
|
||||
GenRISCDisassembler,
|
||||
GenDisassembler,
|
||||
GenCallingConv,
|
||||
GenClangDiagsDefs,
|
||||
@ -84,6 +86,9 @@ 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",
|
||||
@ -229,6 +234,9 @@ 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user