diff options
author | Jim Grosbach <grosbach@apple.com> | 2011-09-08 22:07:06 +0000 |
---|---|---|
committer | Jim Grosbach <grosbach@apple.com> | 2011-09-08 22:07:06 +0000 |
commit | a77295db19527503d6b290e4f34f273d0a789365 (patch) | |
tree | 0e8bbf22b44dd8b031c1d516d4abcdf668b1ea7d /lib/Target/ARM | |
parent | 7ec8fb8830108574b58c85c740d1857ccd2b0aba (diff) | |
download | llvm-a77295db19527503d6b290e4f34f273d0a789365.tar.gz llvm-a77295db19527503d6b290e4f34f273d0a789365.tar.bz2 llvm-a77295db19527503d6b290e4f34f273d0a789365.tar.xz |
Thumb2 assembly parsing and encoding for LDRD(immediate).
Refactor operand handling for STRD as well. Tests for that forthcoming.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@139322 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM')
-rw-r--r-- | lib/Target/ARM/ARMCodeEmitter.cpp | 2 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrFormats.td | 17 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrThumb2.td | 44 | ||||
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 71 | ||||
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 76 | ||||
-rw-r--r-- | lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 41 |
6 files changed, 226 insertions, 25 deletions
diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index a94f40ae74..d587eca385 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -207,6 +207,8 @@ namespace { const { return 0; } unsigned getT2AddrModeImm8OpValue(const MachineInstr &MI, unsigned Op) const { return 0; } + unsigned getT2Imm8s4OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } unsigned getT2AddrModeImm8s4OpValue(const MachineInstr &MI, unsigned Op) const { return 0; } unsigned getT2AddrModeImm8OffsetOpValue(const MachineInstr &MI, unsigned Op) diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 9387cf0ab1..67a74e04b1 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1100,8 +1100,8 @@ class T2Ipc<dag oops, dag iops, InstrItinClass itin, string opc, string asm, list<dag> pattern> : Thumb2I<oops, iops, AddrModeT2_pc, 4, itin, opc, asm, "", pattern>; class T2Ii8s4<bit P, bit W, bit isLoad, dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list<dag> pattern> - : Thumb2I<oops, iops, AddrModeT2_i8s4, 4, itin, opc, asm, "", + string opc, string asm, string cstr, list<dag> pattern> + : Thumb2I<oops, iops, AddrModeT2_i8s4, 4, itin, opc, asm, cstr, pattern> { bits<4> Rt; bits<4> Rt2; @@ -1117,14 +1117,14 @@ class T2Ii8s4<bit P, bit W, bit isLoad, dag oops, dag iops, InstrItinClass itin, let Inst{11-8} = Rt2{3-0}; let Inst{7-0} = addr{7-0}; } - -class T2Ii8s4Tied<bit P, bit W, bit isLoad, dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list<dag> pattern> - : Thumb2I<oops, iops, AddrModeT2_i8s4, 4, itin, opc, asm, "$base = $wb", +class T2Ii8s4post<bit P, bit W, bit isLoad, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, string cstr, + list<dag> pattern> + : Thumb2I<oops, iops, AddrModeT2_i8s4, 4, itin, opc, asm, cstr, pattern> { bits<4> Rt; bits<4> Rt2; - bits<4> base; + bits<4> addr; bits<9> imm; let Inst{31-25} = 0b1110100; let Inst{24} = P; @@ -1132,13 +1132,12 @@ class T2Ii8s4Tied<bit P, bit W, bit isLoad, dag oops, dag iops, InstrItinClass i let Inst{22} = 1; let Inst{21} = W; let Inst{20} = isLoad; - let Inst{19-16} = base{3-0}; + let Inst{19-16} = addr; let Inst{15-12} = Rt{3-0}; let Inst{11-8} = Rt2{3-0}; let Inst{7-0} = imm{7-0}; } - class T2sI<dag oops, dag iops, InstrItinClass itin, string opc, string asm, list<dag> pattern> : Thumb2sI<oops, iops, AddrModeNone, 4, itin, opc, asm, "", pattern>; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 3e64c1905c..c95d8aa571 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -164,15 +164,19 @@ def t2am_imm8_offset : Operand<i32>, } // t2addrmode_imm8s4 := reg +/- (imm8 << 2) +def MemImm8s4OffsetAsmOperand : AsmOperandClass {let Name = "MemImm8s4Offset";} def t2addrmode_imm8s4 : Operand<i32> { let PrintMethod = "printT2AddrModeImm8s4Operand"; let EncoderMethod = "getT2AddrModeImm8s4OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8s4"; + let ParserMatchClass = MemImm8s4OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } +def t2am_imm8s4_offset_asmoperand : AsmOperandClass { let Name = "Imm8s4"; } def t2am_imm8s4_offset : Operand<i32> { let PrintMethod = "printT2AddrModeImm8s4OffsetOperand"; + let EncoderMethod = "getT2Imm8s4OpValue"; let DecoderMethod = "DecodeT2Imm8S4"; } @@ -1193,7 +1197,7 @@ let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { // Load doubleword def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$Rt, rGPR:$Rt2), (ins t2addrmode_imm8s4:$addr), - IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", []>; + IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "", []>; } // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 // zextload i1 -> zextload i8 @@ -1344,7 +1348,7 @@ defm t2STRH:T2I_st<0b01,"strh", IIC_iStore_bh_i, IIC_iStore_bh_si, let mayLoad = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs), (ins GPR:$Rt, GPR:$Rt2, t2addrmode_imm8s4:$addr), - IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", []>; + IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "", []>; // Indexed stores def t2STR_PRE : T2Ipreldst<0, 0b10, 0, 1, (outs GPRnopc:$Rn_wb), @@ -1424,23 +1428,31 @@ def t2STRHT : T2IstT<0b01, "strht", IIC_iStore_bh_i>; // ldrd / strd pre / post variants // For disassembly only. -def t2LDRD_PRE : T2Ii8s4Tied<1, 1, 1, - (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), - (ins GPR:$base, t2am_imm8s4_offset:$imm), IIC_iLoad_d_ru, - "ldrd", "\t$Rt, $Rt2, [$base, $imm]!", []>; +def t2LDRD_PRE : T2Ii8s4<1, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), + (ins t2addrmode_imm8s4:$addr), IIC_iLoad_d_ru, + "ldrd", "\t$Rt, $Rt2, $addr!", "$addr.base = $wb", []> { + let AsmMatchConverter = "cvtT2LdrdPre"; + let DecoderMethod = "DecodeT2LDRDPreInstruction"; +} -def t2LDRD_POST : T2Ii8s4Tied<0, 1, 1, - (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), - (ins GPR:$base, t2am_imm8s4_offset:$imm), IIC_iLoad_d_ru, - "ldrd", "\t$Rt, $Rt2, [$base], $imm", []>; +def t2LDRD_POST : T2Ii8s4post<0, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), + (ins addr_offset_none:$addr, t2am_imm8s4_offset:$imm), + IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr, $imm", + "$addr.base = $wb", []>; -def t2STRD_PRE : T2Ii8s4Tied<1, 1, 0, (outs GPR:$wb), - (ins rGPR:$Rt, rGPR:$Rt2, GPR:$base, t2am_imm8s4_offset:$imm), - IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, [$base, $imm]!", []>; +def t2STRD_PRE : T2Ii8s4<1, 1, 0, (outs GPR:$wb), + (ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4:$addr), + IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr!", + "$addr.base = $wb", []> { + let AsmMatchConverter = "cvtT2StrdPre"; + let DecoderMethod = "DecodeT2STRDPreInstruction"; +} -def t2STRD_POST : T2Ii8s4Tied<0, 1, 0, (outs GPR:$wb), - (ins rGPR:$Rt, rGPR:$Rt2, GPR:$base, t2am_imm8s4_offset:$imm), - IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, [$base], $imm", []>; +def t2STRD_POST : T2Ii8s4post<0, 1, 0, (outs GPR:$wb), + (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr, + t2am_imm8s4_offset:$imm), + IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr, $imm", + "$addr.base = $wb", []>; // T2Ipl (Preload Data/Instruction) signals the memory system of possible future // data/instruction access. These are for disassembly only. diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index abe55050b3..afab484a17 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -158,6 +158,10 @@ class ARMAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*>&); // Asm Match Converter Methods + bool cvtT2LdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl<MCParsedAsmOperand*> &); + bool cvtT2StrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl<MCParsedAsmOperand*> &); bool cvtLdWriteBackRegT2AddrModeImm8(MCInst &Inst, unsigned Opcode, const SmallVectorImpl<MCParsedAsmOperand*> &); bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, @@ -463,6 +467,14 @@ public: bool isITMask() const { return Kind == ITCondMask; } bool isITCondCode() const { return Kind == CondCode; } bool isImm() const { return Kind == Immediate; } + bool isImm8s4() const { + if (Kind != Immediate) + return false; + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ((Value & 3) == 0) && Value >= -1020 && Value <= 1020; + } bool isImm0_1020s4() const { if (Kind != Immediate) return false; @@ -736,6 +748,14 @@ public: int64_t Val = Mem.OffsetImm->getValue(); return Val >= 0 && Val <= 1020 && (Val % 4) == 0; } + bool isMemImm8s4Offset() const { + if (Kind != Memory || Mem.OffsetRegNum != 0) + return false; + // Immediate offset a multiple of 4 in range [-1020, 1020]. + if (!Mem.OffsetImm) return true; + int64_t Val = Mem.OffsetImm->getValue(); + return Val >= -1020 && Val <= 1020 && (Val & 3) == 0; + } bool isMemImm8Offset() const { if (Kind != Memory || Mem.OffsetRegNum != 0) return false; @@ -908,6 +928,14 @@ public: addExpr(Inst, getImm()); } + void addImm8s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // FIXME: We really want to scale the value here, but the LDRD/STRD + // instruction don't encode operands that way yet. + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm()); + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + } + void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate is scaled by four in the encoding and is stored @@ -1111,6 +1139,13 @@ public: Inst.addOperand(MCOperand::CreateImm(Val)); } + void addMemImm8s4OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + void addMemImm8OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0; @@ -2400,6 +2435,42 @@ parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { return MatchOperand_Success; } +/// cvtT2LdrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtT2LdrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateReg(0)); + // addr + ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + +/// cvtT2StrdPre - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtT2StrdPre(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateReg(0)); + // Rt, Rt2 + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + ((ARMOperand*)Operands[3])->addRegOperands(Inst, 1); + // addr + ((ARMOperand*)Operands[4])->addMemImm8s4OffsetOperands(Inst, 2); + // pred + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + /// cvtLdWriteBackRegT2AddrModeImm8 - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 66e64d3ffc..fad7068fff 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -293,6 +293,10 @@ static DecodeStatus DecodeThumbBLTargetOperand(llvm::MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); static DecodeStatus DecodeIT(llvm::MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeT2LDRDPreInstruction(llvm::MCInst &Inst,unsigned Insn, + uint64_t Address, const void *Decoder); +static DecodeStatus DecodeT2STRDPreInstruction(llvm::MCInst &Inst,unsigned Insn, + uint64_t Address, const void *Decoder); #include "ARMGenDisassemblerTables.inc" #include "ARMGenInstrInfo.inc" @@ -3649,3 +3653,75 @@ static DecodeStatus DecodeIT(llvm::MCInst &Inst, unsigned Insn, Inst.addOperand(MCOperand::CreateImm(mask)); return S; } + +static DecodeStatus +DecodeT2LDRDPreInstruction(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned Rt = fieldFromInstruction32(Insn, 12, 4); + unsigned Rt2 = fieldFromInstruction32(Insn, 8, 4); + unsigned Rn = fieldFromInstruction32(Insn, 16, 4); + unsigned addr = fieldFromInstruction32(Insn, 0, 8); + unsigned W = fieldFromInstruction32(Insn, 21, 1); + unsigned U = fieldFromInstruction32(Insn, 23, 1); + unsigned P = fieldFromInstruction32(Insn, 24, 1); + bool writeback = (W == 1) | (P == 0); + + addr |= (U << 8) | (Rn << 9); + + if (writeback && (Rn == Rt || Rn == Rt2)) + Check(S, MCDisassembler::SoftFail); + if (Rt == Rt2) + Check(S, MCDisassembler::SoftFail); + + // Rt + if (!Check(S, DecoderGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + // Rt2 + if (!Check(S, DecoderGPRRegisterClass(Inst, Rt2, Address, Decoder))) + return MCDisassembler::Fail; + // Writeback operand + if (!Check(S, DecoderGPRRegisterClass(Inst, Rn, Address, Decoder))) + return MCDisassembler::Fail; + // addr + if (!Check(S, DecodeT2AddrModeImm8s4(Inst, addr, Address, Decoder))) + return MCDisassembler::Fail; + + return S; +} + +static DecodeStatus +DecodeT2STRDPreInstruction(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + unsigned Rt = fieldFromInstruction32(Insn, 12, 4); + unsigned Rt2 = fieldFromInstruction32(Insn, 8, 4); + unsigned Rn = fieldFromInstruction32(Insn, 16, 4); + unsigned addr = fieldFromInstruction32(Insn, 0, 8); + unsigned W = fieldFromInstruction32(Insn, 21, 1); + unsigned U = fieldFromInstruction32(Insn, 23, 1); + unsigned P = fieldFromInstruction32(Insn, 24, 1); + bool writeback = (W == 1) | (P == 0); + + addr |= (U << 8) | (Rn << 9); + + if (writeback && (Rn == Rt || Rn == Rt2)) + Check(S, MCDisassembler::SoftFail); + + // Writeback operand + if (!Check(S, DecoderGPRRegisterClass(Inst, Rn, Address, Decoder))) + return MCDisassembler::Fail; + // Rt + if (!Check(S, DecoderGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + // Rt2 + if (!Check(S, DecoderGPRRegisterClass(Inst, Rt2, Address, Decoder))) + return MCDisassembler::Fail; + // addr + if (!Check(S, DecodeT2AddrModeImm8s4(Inst, addr, Address, Decoder))) + return MCDisassembler::Fail; + + return S; +} diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index 69ec197af5..34b4e3d6b3 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -144,6 +144,10 @@ public: /// operand. uint32_t getT2AddrModeImm8s4OpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups) const; + /// getT2Imm8s4OpValue - Return encoding info for '+/- imm8<<2' + /// operand. + uint32_t getT2Imm8s4OpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl<MCFixup> &Fixups) const; /// getLdStSORegOpValue - Return encoding info for 'reg +/- reg shop imm' @@ -720,6 +724,37 @@ getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx, return Binary; } +/// getT2Imm8s4OpValue - Return encoding info for +/// '+/- imm8<<2' operand. +uint32_t ARMMCCodeEmitter:: +getT2Imm8s4OpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl<MCFixup> &Fixups) const { + // FIXME: The immediate operand should have already been encoded like this + // before ever getting here. The encoder method should just need to combine + // the MI operands for the register and the offset into a single + // representation for the complex operand in the .td file. This isn't just + // style, unfortunately. As-is, we can't represent the distinct encoding + // for #-0. + + // {8} = (U)nsigned (add == '1', sub == '0') + // {7-0} = imm8 + int32_t Imm8 = MI.getOperand(OpIdx).getImm(); + bool isAdd = Imm8 >= 0; + + // Immediate is always encoded as positive. The 'U' bit controls add vs sub. + if (Imm8 < 0) + Imm8 = -Imm8; + + // Scaled by 4. + Imm8 /= 4; + + uint32_t Binary = Imm8 & 0xff; + // Immediate is always encoded as positive. The 'U' bit controls add vs sub. + if (isAdd) + Binary |= (1 << 8); + return Binary; +} + /// getT2AddrModeImm8s4OpValue - Return encoding info for /// 'reg +/- imm8<<2' operand. uint32_t ARMMCCodeEmitter:: @@ -746,6 +781,12 @@ getT2AddrModeImm8s4OpValue(const MCInst &MI, unsigned OpIdx, } else isAdd = EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm8, Fixups); + // FIXME: The immediate operand should have already been encoded like this + // before ever getting here. The encoder method should just need to combine + // the MI operands for the register and the offset into a single + // representation for the complex operand in the .td file. This isn't just + // style, unfortunately. As-is, we can't represent the distinct encoding + // for #-0. uint32_t Binary = (Imm8 >> 2) & 0xff; // Immediate is always encoded as positive. The 'U' bit controls add vs sub. if (isAdd) |