From 7ce057983ea7b8ad42d5cca1bb5d3f6941662269 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Wed, 3 Aug 2011 23:50:40 +0000 Subject: [PATCH] ARM refactoring assembly parsing of memory address operands. Memory operand parsing is a bit haphazzard at the moment, in no small part due to the even more haphazzard representations of memory operands in the .td files. Start cleaning that all up, at least a bit. The addressing modes in the .td files will be being simplified to not be so monolithic, especially with regards to immediate vs. register offsets and post-indexed addressing. addrmode3 is on its way with this patch, for example. This patch is foundational to enable going back to smaller incremental patches for the individual memory referencing instructions themselves. It does just enough to get the basics in place and handle the "make check" regression tests we already have. Follow-up work will be fleshing out the details and adding more robust test cases for the individual instructions, starting with ARM mode and moving from there into Thumb and Thumb2. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@136845 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMCodeEmitter.cpp | 2 + lib/Target/ARM/ARMInstrFormats.td | 45 +- lib/Target/ARM/ARMInstrInfo.td | 161 +++- lib/Target/ARM/ARMInstrThumb.td | 22 +- lib/Target/ARM/ARMInstrThumb2.td | 8 +- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 869 ++++++++---------- .../ARM/Disassembler/ARMDisassembler.cpp | 8 +- .../ARM/Disassembler/ARMDisassemblerCore.cpp | 37 +- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp | 14 +- lib/Target/ARM/InstPrinter/ARMInstPrinter.h | 7 +- .../ARM/MCTargetDesc/ARMAddressingModes.h | 3 +- .../ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 16 + test/MC/ARM/arm_addrmode3.s | 8 +- test/MC/ARM/thumb2_instructions.s | 2 + test/MC/Disassembler/ARM/arm-tests.txt | 7 +- utils/TableGen/EDEmitter.cpp | 6 +- 16 files changed, 577 insertions(+), 638 deletions(-) diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index e0720b3da8f..7d4eb6f18f9 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -266,6 +266,8 @@ namespace { const { return 0;} uint32_t getAddrMode2OffsetOpValue(const MachineInstr &MI, unsigned OpIdx) const { return 0;} + uint32_t getPostIdxRegOpValue(const MachineInstr &MI, unsigned OpIdx) + const { return 0;} uint32_t getAddrMode3OffsetOpValue(const MachineInstr &MI, unsigned OpIdx) const { return 0;} uint32_t getAddrMode3OpValue(const MachineInstr &MI, unsigned Op) diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 769fecf6d87..c3d9e39dfa6 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -597,29 +597,24 @@ class AI3ldstidx op, bit op20, bit isLd, bit isPre, dag oops, dag iops, // FIXME: Merge with the above class when addrmode2 gets used for LDR, LDRB // but for now use this class for LDRSBT, LDRHT, LDSHT. -class AI3ldstidxT op, bit op20, bit isLd, bit isPre, dag oops, dag iops, +class AI3ldstidxT op, bit isLoad, dag oops, dag iops, IndexMode im, Format f, InstrItinClass itin, string opc, string asm, string cstr, list pattern> - : I { + : I { // {13} 1 == imm8, 0 == Rm // {12-9} Rn // {8} isAdd // {7-4} imm7_4/zero // {3-0} imm3_0/Rm - bits<14> addr; + bits<4> addr; bits<4> Rt; let Inst{27-25} = 0b000; - let Inst{24} = isPre; // P bit - let Inst{23} = addr{8}; // U bit - let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm - let Inst{20} = op20; // L bit - let Inst{19-16} = addr{12-9}; // Rn + let Inst{24} = 0; // P bit + let Inst{21} = 1; + let Inst{20} = isLoad; // L bit + let Inst{19-16} = addr; // Rn let Inst{15-12} = Rt; // Rt - let Inst{11-8} = addr{7-4}; // imm7_4/zero let Inst{7-4} = op; - let Inst{3-0} = addr{3-0}; // imm3_0/Rm - let AsmMatchConverter = "cvtLdWriteBackRegAddrMode3"; } class AI3stridx op, bit isByte, bit isPre, dag oops, dag iops, @@ -690,32 +685,6 @@ class AI3stdpr pattern> - : I { - // {13} 1 == imm8, 0 == Rm - // {12-9} Rn - // {8} isAdd - // {7-4} imm7_4/zero - // {3-0} imm3_0/Rm - bits<14> addr; - bits<4> Rt; - let Inst{3-0} = addr{3-0}; // imm3_0/Rm - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{11-8} = addr{7-4}; // imm7_4/zero - let Inst{15-12} = Rt; // Rt - let Inst{19-16} = addr{12-9}; // Rn - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm - let Inst{23} = addr{8}; // U bit - let Inst{24} = 0; // P bit - let Inst{27-25} = 0b000; -} class AI3stdpo pattern> : I, PatLeaf<(imm), [{ return Imm > 0 && Imm <= 16; }], // Define ARM specific addressing modes. // addrmode_imm12 := reg +/- imm12 // +def MemImm12OffsetAsmOperand : AsmOperandClass { let Name = "MemImm12Offset"; } def addrmode_imm12 : Operand, ComplexPattern { // 12-bit immediate operand. Note that instructions using this encode @@ -598,30 +599,58 @@ def addrmode_imm12 : Operand, let EncoderMethod = "getAddrModeImm12OpValue"; let PrintMethod = "printAddrModeImm12Operand"; + let ParserMatchClass = MemImm12OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // ldst_so_reg := reg +/- reg shop imm // +def MemRegOffsetAsmOperand : AsmOperandClass { let Name = "MemRegOffset"; } def ldst_so_reg : Operand, ComplexPattern { let EncoderMethod = "getLdStSORegOpValue"; // FIXME: Simplify the printer let PrintMethod = "printAddrMode2Operand"; - let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); + let ParserMatchClass = MemRegOffsetAsmOperand; + let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$shift); } +// postidx_imm8 := +/- [0,255] +// +// 9 bit value: +// {8} 1 is imm8 is non-negative. 0 otherwise. +// {7-0} [0,255] imm8 value. +def PostIdxImm8AsmOperand : AsmOperandClass { let Name = "PostIdxImm8"; } +def postidx_imm8 : Operand { + let PrintMethod = "printPostIdxImm8Operand"; + let ParserMatchClass = PostIdxImm8AsmOperand; + let MIOperandInfo = (ops i32imm); +} + +// postidx_reg := +/- reg +// +def PostIdxRegAsmOperand : AsmOperandClass { + let Name = "PostIdxReg"; + let ParserMethod = "parsePostIdxReg"; +} +def postidx_reg : Operand { + let EncoderMethod = "getPostIdxRegOpValue"; + let PrintMethod = "printAddrMode3OffsetOperand"; + let ParserMatchClass = PostIdxRegAsmOperand; + let MIOperandInfo = (ops GPR, i32imm); +} + + // addrmode2 := reg +/- imm12 // := reg +/- reg shop imm // -def MemMode2AsmOperand : AsmOperandClass { - let Name = "MemMode2"; - let ParserMethod = "parseMemMode2Operand"; -} +// FIXME: addrmode2 should be refactored the rest of the way to always +// use explicit imm vs. reg versions above (addrmode_imm12 and ldst_so_reg). +def AddrMode2AsmOperand : AsmOperandClass { let Name = "AddrMode2"; } def addrmode2 : Operand, ComplexPattern { let EncoderMethod = "getAddrMode2OpValue"; let PrintMethod = "printAddrMode2Operand"; - let ParserMatchClass = MemMode2AsmOperand; + let ParserMatchClass = AddrMode2AsmOperand; let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); } @@ -645,15 +674,11 @@ def am2offset_imm : Operand, // addrmode3 := reg +/- reg // addrmode3 := reg +/- imm8 // -def MemMode3AsmOperand : AsmOperandClass { - let Name = "MemMode3"; - let ParserMethod = "parseMemMode3Operand"; -} +//def AddrMode3AsmOperand : AsmOperandClass { let Name = "AddrMode3"; } def addrmode3 : Operand, ComplexPattern { let EncoderMethod = "getAddrMode3OpValue"; let PrintMethod = "printAddrMode3Operand"; - let ParserMatchClass = MemMode3AsmOperand; let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); } @@ -674,13 +699,13 @@ def ldstm_mode : OptionalDefOperand { // addrmode5 := reg +/- imm8*4 // -def MemMode5AsmOperand : AsmOperandClass { let Name = "MemMode5"; } +def AddrMode5AsmOperand : AsmOperandClass { let Name = "AddrMode5"; } def addrmode5 : Operand, ComplexPattern { let PrintMethod = "printAddrMode5Operand"; - let MIOperandInfo = (ops GPR:$base, i32imm); - let ParserMatchClass = MemMode5AsmOperand; let EncoderMethod = "getAddrMode5OpValue"; + let ParserMatchClass = AddrMode5AsmOperand; + let MIOperandInfo = (ops GPR:$base, i32imm); } // addrmode6 := reg with optional alignment @@ -728,11 +753,11 @@ def addrmodepc : Operand, // addr_offset_none := reg // -def MemMode7AsmOperand : AsmOperandClass { let Name = "MemMode7"; } +def MemNoOffsetAsmOperand : AsmOperandClass { let Name = "MemNoOffset"; } def addr_offset_none : Operand { let PrintMethod = "printAddrMode7Operand"; - let MIOperandInfo = (ops GPR); - let ParserMatchClass = MemMode7AsmOperand; + let ParserMatchClass = MemNoOffsetAsmOperand; + let MIOperandInfo = (ops GPR:$base); } def nohash_imm : Operand { @@ -1822,7 +1847,7 @@ defm STRB : AI_str1<1, "strb", IIC_iStore_bh_r, IIC_iStore_bh_si, // Special LDR for loads from non-pc-relative constpools. let canFoldAsLoad = 1, mayLoad = 1, neverHasSideEffects = 1, - isReMaterializable = 1 in + isReMaterializable = 1, isCodeGenOnly = 1 in def LDRcp : AI2ldst<0b010, 1, 0, (outs GPR:$Rt), (ins addrmode_imm12:$addr), AddrMode_i12, LdFrm, IIC_iLoad_r, "ldr", "\t$Rt, $addr", []> { @@ -2002,21 +2027,35 @@ def LDRBT : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$base_wb), let Inst{11-0} = addr{11-0}; let AsmMatchConverter = "cvtLdWriteBackRegAddrMode2"; } -def LDRSBT : AI3ldstidxT<0b1101, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb), - (ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru, - "ldrsbt", "\t$Rt, $addr", "$addr.base = $base_wb", []> { - let Inst{21} = 1; // overwrite -} -def LDRHT : AI3ldstidxT<0b1011, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb), - (ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru, - "ldrht", "\t$Rt, $addr", "$addr.base = $base_wb", []> { - let Inst{21} = 1; // overwrite -} -def LDRSHT : AI3ldstidxT<0b1111, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb), - (ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru, - "ldrsht", "\t$Rt, $addr", "$addr.base = $base_wb", []> { - let Inst{21} = 1; // overwrite + +multiclass AI3ldrT op, string opc> { + def i : AI3ldstidxT { + bits<9> offset; + let Inst{23} = offset{8}; + let Inst{22} = 1; + let Inst{11-8} = offset{7-4}; + let Inst{3-0} = offset{3-0}; + let AsmMatchConverter = "cvtLdExtTWriteBackImm"; + } + def r : AI3ldstidxT { + bits<5> Rm; + let Inst{23} = Rm{4}; + let Inst{22} = 0; + let Inst{11-8} = 0; + let Inst{3-0} = Rm{3-0}; + let AsmMatchConverter = "cvtLdExtTWriteBackReg"; + } } + +defm LDRSBT : AI3ldrT<0b1101, "ldrsbt">; +defm LDRHT : AI3ldrT<0b1011, "ldrht">; +defm LDRSHT : AI3ldrT<0b1111, "ldrsht">; } // Store @@ -2156,7 +2195,7 @@ def STRD_POST: AI3stdpo<(outs GPR:$base_wb), } } // mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 -// STRT, STRBT, and STRHT are for disassembly only. +// STRT, STRBT, and STRHT def STRTr : AI2stridxT<0, 0, (outs GPR:$Rn_wb), (ins GPR:$Rt, ldst_so_reg:$addr), @@ -2201,15 +2240,35 @@ def STRBTi : AI2stridxT<1, 0, (outs GPR:$Rn_wb), let AsmMatchConverter = "cvtStWriteBackRegAddrMode2"; } - -def STRHT: AI3sthpo<(outs GPR:$base_wb), (ins GPR:$Rt, addrmode3:$addr), - StMiscFrm, IIC_iStore_bh_ru, - "strht", "\t$Rt, $addr", "$addr.base = $base_wb", - [/* For disassembly only; pattern left blank */]> { - let Inst{21} = 1; // overwrite - let AsmMatchConverter = "cvtStWriteBackRegAddrMode3"; +multiclass AI3strT op, string opc> { + def i : AI3ldstidxT { + bits<9> offset; + let Inst{23} = offset{8}; + let Inst{22} = 1; + let Inst{11-8} = offset{7-4}; + let Inst{3-0} = offset{3-0}; + let AsmMatchConverter = "cvtStExtTWriteBackImm"; + } + def r : AI3ldstidxT { + bits<5> Rm; + let Inst{23} = Rm{4}; + let Inst{22} = 0; + let Inst{11-8} = 0; + let Inst{3-0} = Rm{3-0}; + let AsmMatchConverter = "cvtStExtTWriteBackReg"; + } } + +defm STRHT : AI3strT<0b1011, "strht">; + + //===----------------------------------------------------------------------===// // Load / store multiple Instructions. // @@ -3758,8 +3817,8 @@ def LDREXB : AIldrex<0b10, (outs GPR:$Rt), (ins addr_offset_none:$addr), "ldrexb", "\t$Rt, $addr", []>; def LDREXH : AIldrex<0b11, (outs GPR:$Rt), (ins addr_offset_none:$addr), NoItinerary, "ldrexh", "\t$Rt, $addr", []>; -def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr), NoItinerary, - "ldrex", "\t$Rt, $addr", []>; +def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr), + NoItinerary, "ldrex", "\t$Rt, $addr", []>; let hasExtraDefRegAllocReq = 1 in def LDREXD: AIldrex<0b01, (outs GPR:$Rt, GPR:$Rt2),(ins addr_offset_none:$addr), NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", []>; @@ -3844,7 +3903,7 @@ def CDP2 : ABXI<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1, class ACI : InoP { + opc, asm, "", []> { let Inst{27-25} = 0b110; } @@ -3914,8 +3973,9 @@ multiclass LdStCop op31_28, bit load, dag ops, string opc, string cond>{ } def L_POST : ACI<(outs), - !con((ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr), ops), - !strconcat(!strconcat(opc, "l"), cond), "\tp$cop, cr$CRd, $addr", + !con((ins nohash_imm:$cop, nohash_imm:$CRd, addr_offset_none:$addr, + i32imm:$offset), ops), + !strconcat(!strconcat(opc, "l"), cond), "\tp$cop, cr$CRd, $addr, $offset", IndexModePost> { let Inst{31-28} = op31_28; let Inst{24} = 0; // P = 0 @@ -4491,3 +4551,14 @@ def : MnemonicAlias<"srsea", "srsdb">; def : MnemonicAlias<"srsfd", "srsia">; def : MnemonicAlias<"srsed", "srsib">; def : MnemonicAlias<"srs", "srsia">; + +// LDRSBT/LDRHT/LDRSHT post-index offset if optional. +// Note that the write-back output register is a dummy operand for MC (it's +// only meaningful for codegen), so we just pass zero here. +// FIXME: tblgen not cooperating with argument conversions. +//def : InstAlias<"ldrsbt${p} $Rt, $addr", +// (LDRSBTi GPR:$Rt, GPR:$Rt, addr_offset_none:$addr, 0,pred:$p)>; +//def : InstAlias<"ldrht${p} $Rt, $addr", +// (LDRHTi GPR:$Rt, GPR:$Rt, addr_offset_none:$addr, 0, pred:$p)>; +//def : InstAlias<"ldrsht${p} $Rt, $addr", +// (LDRSHTi GPR:$Rt, GPR:$Rt, addr_offset_none:$addr, 0, pred:$p)>; diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index bd6d1a0c7d9..e0c03179200 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -94,18 +94,9 @@ def t_blxtarget : Operand { } } -def MemModeRegThumbAsmOperand : AsmOperandClass { - let Name = "MemModeRegThumb"; - let SuperClasses = []; -} - -def MemModeImmThumbAsmOperand : AsmOperandClass { - let Name = "MemModeImmThumb"; - let SuperClasses = []; -} - // t_addrmode_rr := reg + reg // +def t_addrmode_rr_asm_operand : AsmOperandClass { let Name = "MemThumbRR"; } def t_addrmode_rr : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; @@ -119,22 +110,22 @@ def t_addrmode_rrs1 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; + let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); - let ParserMatchClass = MemModeRegThumbAsmOperand; } def t_addrmode_rrs2 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; + let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); - let ParserMatchClass = MemModeRegThumbAsmOperand; } def t_addrmode_rrs4 : Operand, ComplexPattern { let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; + let ParserMatchClass = t_addrmode_rr_asm_operand; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); - let ParserMatchClass = MemModeRegThumbAsmOperand; } // t_addrmode_is4 := reg + imm5 * 4 @@ -144,7 +135,6 @@ def t_addrmode_is4 : Operand, let EncoderMethod = "getAddrModeISOpValue"; let PrintMethod = "printThumbAddrModeImm5S4Operand"; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); - let ParserMatchClass = MemModeImmThumbAsmOperand; } // t_addrmode_is2 := reg + imm5 * 2 @@ -154,7 +144,6 @@ def t_addrmode_is2 : Operand, let EncoderMethod = "getAddrModeISOpValue"; let PrintMethod = "printThumbAddrModeImm5S2Operand"; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); - let ParserMatchClass = MemModeImmThumbAsmOperand; } // t_addrmode_is1 := reg + imm5 @@ -164,7 +153,6 @@ def t_addrmode_is1 : Operand, let EncoderMethod = "getAddrModeISOpValue"; let PrintMethod = "printThumbAddrModeImm5S1Operand"; let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); - let ParserMatchClass = MemModeImmThumbAsmOperand; } // t_addrmode_sp := sp + imm8 * 4 @@ -174,14 +162,12 @@ def t_addrmode_sp : Operand, let EncoderMethod = "getAddrModeThumbSPOpValue"; let PrintMethod = "printThumbAddrModeSPOperand"; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); - let ParserMatchClass = MemModeImmThumbAsmOperand; } // t_addrmode_pc :=