mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-10 06:00:30 +00:00
- Implement asm parsing support for LDRT, LDRBT, STRT, STRBT and
{STR,LDC}{2}_PRE. - Fixed the encoding in some places. - Some of those instructions were using am2offset and now use addrmode2. Codegen isn't affected, instructions which use SelectAddrMode2Offset were not touched. - Teach printAddrMode2Operand to check by the addressing mode which index mode to print. - This is a work in progress, more work to come. The idea is to change places which use am2offset to use addrmode2 instead, as to unify assembly parser. - Add testcases for assembly parser git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@128585 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c0e6d780cd
commit
40829ed6f5
@ -200,6 +200,51 @@ inline static unsigned getARMRegisterNumbering(unsigned Reg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ARMII {
|
namespace ARMII {
|
||||||
|
|
||||||
|
/// ARM Addressing Modes
|
||||||
|
enum AddrMode {
|
||||||
|
AddrModeNone = 0,
|
||||||
|
AddrMode1 = 1,
|
||||||
|
AddrMode2 = 2,
|
||||||
|
AddrMode3 = 3,
|
||||||
|
AddrMode4 = 4,
|
||||||
|
AddrMode5 = 5,
|
||||||
|
AddrMode6 = 6,
|
||||||
|
AddrModeT1_1 = 7,
|
||||||
|
AddrModeT1_2 = 8,
|
||||||
|
AddrModeT1_4 = 9,
|
||||||
|
AddrModeT1_s = 10, // i8 * 4 for pc and sp relative data
|
||||||
|
AddrModeT2_i12 = 11,
|
||||||
|
AddrModeT2_i8 = 12,
|
||||||
|
AddrModeT2_so = 13,
|
||||||
|
AddrModeT2_pc = 14, // +/- i12 for pc relative data
|
||||||
|
AddrModeT2_i8s4 = 15, // i8 * 4
|
||||||
|
AddrMode_i12 = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static const char *AddrModeToString(AddrMode addrmode) {
|
||||||
|
switch (addrmode) {
|
||||||
|
default: llvm_unreachable("Unknown memory operation");
|
||||||
|
case AddrModeNone: return "AddrModeNone";
|
||||||
|
case AddrMode1: return "AddrMode1";
|
||||||
|
case AddrMode2: return "AddrMode2";
|
||||||
|
case AddrMode3: return "AddrMode3";
|
||||||
|
case AddrMode4: return "AddrMode4";
|
||||||
|
case AddrMode5: return "AddrMode5";
|
||||||
|
case AddrMode6: return "AddrMode6";
|
||||||
|
case AddrModeT1_1: return "AddrModeT1_1";
|
||||||
|
case AddrModeT1_2: return "AddrModeT1_2";
|
||||||
|
case AddrModeT1_4: return "AddrModeT1_4";
|
||||||
|
case AddrModeT1_s: return "AddrModeT1_s";
|
||||||
|
case AddrModeT2_i12: return "AddrModeT2_i12";
|
||||||
|
case AddrModeT2_i8: return "AddrModeT2_i8";
|
||||||
|
case AddrModeT2_so: return "AddrModeT2_so";
|
||||||
|
case AddrModeT2_pc: return "AddrModeT2_pc";
|
||||||
|
case AddrModeT2_i8s4: return "AddrModeT2_i8s4";
|
||||||
|
case AddrMode_i12: return "AddrMode_i12";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Target Operand Flag enum.
|
/// Target Operand Flag enum.
|
||||||
enum TOF {
|
enum TOF {
|
||||||
//===------------------------------------------------------------------===//
|
//===------------------------------------------------------------------===//
|
||||||
|
@ -34,25 +34,7 @@ namespace ARMII {
|
|||||||
|
|
||||||
//===------------------------------------------------------------------===//
|
//===------------------------------------------------------------------===//
|
||||||
// This four-bit field describes the addressing mode used.
|
// This four-bit field describes the addressing mode used.
|
||||||
|
AddrModeMask = 0x1f, // The AddrMode enums are declared in ARMBaseInfo.h
|
||||||
AddrModeMask = 0x1f,
|
|
||||||
AddrModeNone = 0,
|
|
||||||
AddrMode1 = 1,
|
|
||||||
AddrMode2 = 2,
|
|
||||||
AddrMode3 = 3,
|
|
||||||
AddrMode4 = 4,
|
|
||||||
AddrMode5 = 5,
|
|
||||||
AddrMode6 = 6,
|
|
||||||
AddrModeT1_1 = 7,
|
|
||||||
AddrModeT1_2 = 8,
|
|
||||||
AddrModeT1_4 = 9,
|
|
||||||
AddrModeT1_s = 10, // i8 * 4 for pc and sp relative data
|
|
||||||
AddrModeT2_i12 = 11,
|
|
||||||
AddrModeT2_i8 = 12,
|
|
||||||
AddrModeT2_so = 13,
|
|
||||||
AddrModeT2_pc = 14, // +/- i12 for pc relative data
|
|
||||||
AddrModeT2_i8s4 = 15, // i8 * 4
|
|
||||||
AddrMode_i12 = 16,
|
|
||||||
|
|
||||||
// Size* - Flags to keep track of the size of an instruction.
|
// Size* - Flags to keep track of the size of an instruction.
|
||||||
SizeShift = 5,
|
SizeShift = 5,
|
||||||
|
@ -515,15 +515,15 @@ class AI2stridx<bit isByte, bit isPre, dag oops, dag iops,
|
|||||||
: AI2ldstidx<0, isByte, isPre, oops, iops, im, f, itin, opc, asm, cstr,
|
: AI2ldstidx<0, isByte, isPre, oops, iops, im, f, itin, opc, asm, cstr,
|
||||||
pattern> {
|
pattern> {
|
||||||
// AM2 store w/ two operands: (GPR, am2offset)
|
// AM2 store w/ two operands: (GPR, am2offset)
|
||||||
|
// {17-14} Rn
|
||||||
// {13} 1 == Rm, 0 == imm12
|
// {13} 1 == Rm, 0 == imm12
|
||||||
// {12} isAdd
|
// {12} isAdd
|
||||||
// {11-0} imm12/Rm
|
// {11-0} imm12/Rm
|
||||||
bits<14> offset;
|
bits<18> addr;
|
||||||
bits<4> Rn;
|
let Inst{25} = addr{13};
|
||||||
let Inst{25} = offset{13};
|
let Inst{23} = addr{12};
|
||||||
let Inst{23} = offset{12};
|
let Inst{19-16} = addr{17-14};
|
||||||
let Inst{19-16} = Rn;
|
let Inst{11-0} = addr{11-0};
|
||||||
let Inst{11-0} = offset{11-0};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// addrmode3 instructions
|
// addrmode3 instructions
|
||||||
|
@ -498,6 +498,12 @@ def ldst_so_reg : Operand<i32>,
|
|||||||
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def MemMode2AsmOperand : AsmOperandClass {
|
||||||
|
let Name = "MemMode2";
|
||||||
|
let SuperClasses = [];
|
||||||
|
let ParserMethod = "tryParseMemMode2Operand";
|
||||||
|
}
|
||||||
|
|
||||||
// addrmode2 := reg +/- imm12
|
// addrmode2 := reg +/- imm12
|
||||||
// := reg +/- reg shop imm
|
// := reg +/- reg shop imm
|
||||||
//
|
//
|
||||||
@ -505,6 +511,7 @@ def addrmode2 : Operand<i32>,
|
|||||||
ComplexPattern<i32, 3, "SelectAddrMode2", []> {
|
ComplexPattern<i32, 3, "SelectAddrMode2", []> {
|
||||||
let EncoderMethod = "getAddrMode2OpValue";
|
let EncoderMethod = "getAddrMode2OpValue";
|
||||||
let PrintMethod = "printAddrMode2Operand";
|
let PrintMethod = "printAddrMode2Operand";
|
||||||
|
let ParserMatchClass = MemMode2AsmOperand;
|
||||||
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1656,6 +1663,7 @@ multiclass AI2_ldridx<bit isByte, string opc, InstrItinClass itin> {
|
|||||||
let Inst{23} = addr{12};
|
let Inst{23} = addr{12};
|
||||||
let Inst{19-16} = addr{17-14};
|
let Inst{19-16} = addr{17-14};
|
||||||
let Inst{11-0} = addr{11-0};
|
let Inst{11-0} = addr{11-0};
|
||||||
|
let AsmMatchConverter = "CvtLdWriteBackRegAddrMode2";
|
||||||
}
|
}
|
||||||
def _POST : AI2ldstidx<1, isByte, 0, (outs GPR:$Rt, GPR:$Rn_wb),
|
def _POST : AI2ldstidx<1, isByte, 0, (outs GPR:$Rt, GPR:$Rn_wb),
|
||||||
(ins GPR:$Rn, am2offset:$offset),
|
(ins GPR:$Rn, am2offset:$offset),
|
||||||
@ -1714,17 +1722,35 @@ defm LDRD : AI3_ldridx<0b1101, 0, "ldrd", IIC_iLoad_d_ru>;
|
|||||||
|
|
||||||
// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.
|
// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.
|
||||||
let mayLoad = 1, neverHasSideEffects = 1 in {
|
let mayLoad = 1, neverHasSideEffects = 1 in {
|
||||||
def LDRT : AI2ldstidx<1, 0, 0, (outs GPR:$dst, GPR:$base_wb),
|
def LDRT : AI2ldstidx<1, 0, 0, (outs GPR:$Rt, GPR:$base_wb),
|
||||||
(ins GPR:$base, am2offset:$offset), IndexModePost,
|
(ins addrmode2:$addr), IndexModePost, LdFrm, IIC_iLoad_ru,
|
||||||
LdFrm, IIC_iLoad_ru,
|
"ldrt", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
|
||||||
"ldrt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
|
// {17-14} Rn
|
||||||
|
// {13} 1 == Rm, 0 == imm12
|
||||||
|
// {12} isAdd
|
||||||
|
// {11-0} imm12/Rm
|
||||||
|
bits<18> addr;
|
||||||
|
let Inst{25} = addr{13};
|
||||||
|
let Inst{23} = addr{12};
|
||||||
let Inst{21} = 1; // overwrite
|
let Inst{21} = 1; // overwrite
|
||||||
|
let Inst{19-16} = addr{17-14};
|
||||||
|
let Inst{11-0} = addr{11-0};
|
||||||
|
let AsmMatchConverter = "CvtLdWriteBackRegAddrMode2";
|
||||||
}
|
}
|
||||||
def LDRBT : AI2ldstidx<1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
|
def LDRBT : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$base_wb),
|
||||||
(ins GPR:$base, am2offset:$offset), IndexModePost,
|
(ins addrmode2:$addr), IndexModePost, LdFrm, IIC_iLoad_bh_ru,
|
||||||
LdFrm, IIC_iLoad_bh_ru,
|
"ldrbt", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
|
||||||
"ldrbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
|
// {17-14} Rn
|
||||||
|
// {13} 1 == Rm, 0 == imm12
|
||||||
|
// {12} isAdd
|
||||||
|
// {11-0} imm12/Rm
|
||||||
|
bits<18> addr;
|
||||||
|
let Inst{25} = addr{13};
|
||||||
|
let Inst{23} = addr{12};
|
||||||
let Inst{21} = 1; // overwrite
|
let Inst{21} = 1; // overwrite
|
||||||
|
let Inst{19-16} = addr{17-14};
|
||||||
|
let Inst{11-0} = addr{11-0};
|
||||||
|
let AsmMatchConverter = "CvtLdWriteBackRegAddrMode2";
|
||||||
}
|
}
|
||||||
def LDRSBT : AI3ldstidx<0b1101, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
|
def LDRSBT : AI3ldstidx<0b1101, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
|
||||||
(ins GPR:$base, am3offset:$offset), IndexModePost,
|
(ins GPR:$base, am3offset:$offset), IndexModePost,
|
||||||
@ -1818,20 +1844,20 @@ def STRD_POST: AI3stdpo<(outs GPR:$base_wb),
|
|||||||
|
|
||||||
// STRT, STRBT, and STRHT are for disassembly only.
|
// STRT, STRBT, and STRHT are for disassembly only.
|
||||||
|
|
||||||
def STRT : AI2stridx<0, 0, (outs GPR:$Rn_wb),
|
def STRT : AI2stridx<0, 0, (outs GPR:$Rn_wb), (ins GPR:$Rt, addrmode2:$addr),
|
||||||
(ins GPR:$Rt, GPR:$Rn,am2offset:$offset),
|
|
||||||
IndexModePost, StFrm, IIC_iStore_ru,
|
IndexModePost, StFrm, IIC_iStore_ru,
|
||||||
"strt", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb",
|
"strt", "\t$Rt, $addr", "$addr.base = $Rn_wb",
|
||||||
[/* For disassembly only; pattern left blank */]> {
|
[/* For disassembly only; pattern left blank */]> {
|
||||||
let Inst{21} = 1; // overwrite
|
let Inst{21} = 1; // overwrite
|
||||||
|
let AsmMatchConverter = "CvtStWriteBackRegAddrMode2";
|
||||||
}
|
}
|
||||||
|
|
||||||
def STRBT : AI2stridx<1, 0, (outs GPR:$Rn_wb),
|
def STRBT : AI2stridx<1, 0, (outs GPR:$Rn_wb), (ins GPR:$Rt, addrmode2:$addr),
|
||||||
(ins GPR:$Rt, GPR:$Rn, am2offset:$offset),
|
|
||||||
IndexModePost, StFrm, IIC_iStore_bh_ru,
|
IndexModePost, StFrm, IIC_iStore_bh_ru,
|
||||||
"strbt", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb",
|
"strbt", "\t$Rt, $addr", "$addr.base = $Rn_wb",
|
||||||
[/* For disassembly only; pattern left blank */]> {
|
[/* For disassembly only; pattern left blank */]> {
|
||||||
let Inst{21} = 1; // overwrite
|
let Inst{21} = 1; // overwrite
|
||||||
|
let AsmMatchConverter = "CvtStWriteBackRegAddrMode2";
|
||||||
}
|
}
|
||||||
|
|
||||||
def STRHT: AI3sthpo<(outs GPR:$base_wb),
|
def STRHT: AI3sthpo<(outs GPR:$base_wb),
|
||||||
@ -3391,8 +3417,9 @@ def CDP2 : ABXI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1,
|
|||||||
let Inst{23-20} = opc1;
|
let Inst{23-20} = opc1;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ACI<dag oops, dag iops, string opc, string asm>
|
class ACI<dag oops, dag iops, string opc, string asm,
|
||||||
: I<oops, iops, AddrModeNone, Size4Bytes, IndexModeNone, BrFrm, NoItinerary,
|
IndexMode im = IndexModeNone>
|
||||||
|
: I<oops, iops, AddrModeNone, Size4Bytes, im, BrFrm, NoItinerary,
|
||||||
opc, asm, "", [/* For disassembly only; pattern left blank */]> {
|
opc, asm, "", [/* For disassembly only; pattern left blank */]> {
|
||||||
let Inst{27-25} = 0b110;
|
let Inst{27-25} = 0b110;
|
||||||
}
|
}
|
||||||
@ -3411,7 +3438,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, string opc> {
|
|||||||
|
|
||||||
def _PRE : ACI<(outs),
|
def _PRE : ACI<(outs),
|
||||||
(ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
|
(ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
|
||||||
opc, "\tp$cop, cr$CRd, $addr!"> {
|
opc, "\tp$cop, cr$CRd, $addr!", IndexModePre> {
|
||||||
let Inst{31-28} = op31_28;
|
let Inst{31-28} = op31_28;
|
||||||
let Inst{24} = 1; // P = 1
|
let Inst{24} = 1; // P = 1
|
||||||
let Inst{21} = 1; // W = 1
|
let Inst{21} = 1; // W = 1
|
||||||
@ -3452,7 +3479,7 @@ multiclass LdStCop<bits<4> op31_28, bit load, string opc> {
|
|||||||
|
|
||||||
def L_PRE : ACI<(outs),
|
def L_PRE : ACI<(outs),
|
||||||
(ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
|
(ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
|
||||||
!strconcat(opc, "l"), "\tp$cop, cr$CRd, $addr!"> {
|
!strconcat(opc, "l"), "\tp$cop, cr$CRd, $addr!", IndexModePre> {
|
||||||
let Inst{31-28} = op31_28;
|
let Inst{31-28} = op31_28;
|
||||||
let Inst{24} = 1; // P = 1
|
let Inst{24} = 1; // P = 1
|
||||||
let Inst{21} = 1; // W = 1
|
let Inst{21} = 1; // W = 1
|
||||||
|
@ -48,7 +48,8 @@ class ARMAsmParser : public TargetAsmParser {
|
|||||||
bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
|
bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
bool TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
|
bool TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
|
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
|
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &,
|
||||||
|
ARMII::AddrMode AddrMode);
|
||||||
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
|
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
|
||||||
bool ParsePrefix(ARMMCExpr::VariantKind &RefKind);
|
bool ParsePrefix(ARMMCExpr::VariantKind &RefKind);
|
||||||
const MCExpr *ApplyPrefixToExpr(const MCExpr *E,
|
const MCExpr *ApplyPrefixToExpr(const MCExpr *E,
|
||||||
@ -95,6 +96,14 @@ class ARMAsmParser : public TargetAsmParser {
|
|||||||
SmallVectorImpl<MCParsedAsmOperand*>&);
|
SmallVectorImpl<MCParsedAsmOperand*>&);
|
||||||
OperandMatchResultTy tryParseMSRMaskOperand(
|
OperandMatchResultTy tryParseMSRMaskOperand(
|
||||||
SmallVectorImpl<MCParsedAsmOperand*>&);
|
SmallVectorImpl<MCParsedAsmOperand*>&);
|
||||||
|
OperandMatchResultTy tryParseMemMode2Operand(
|
||||||
|
SmallVectorImpl<MCParsedAsmOperand*>&);
|
||||||
|
|
||||||
|
// Asm Match Converter Methods
|
||||||
|
bool CvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
|
bool CvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
|
ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
|
||||||
@ -172,6 +181,7 @@ class ARMOperand : public MCParsedAsmOperand {
|
|||||||
|
|
||||||
/// Combined record for all forms of ARM address expressions.
|
/// Combined record for all forms of ARM address expressions.
|
||||||
struct {
|
struct {
|
||||||
|
ARMII::AddrMode AddrMode;
|
||||||
unsigned BaseRegNum;
|
unsigned BaseRegNum;
|
||||||
union {
|
union {
|
||||||
unsigned RegNum; ///< Offset register num, when OffsetIsReg.
|
unsigned RegNum; ///< Offset register num, when OffsetIsReg.
|
||||||
@ -293,7 +303,9 @@ public:
|
|||||||
|
|
||||||
/// @name Memory Operand Accessors
|
/// @name Memory Operand Accessors
|
||||||
/// @{
|
/// @{
|
||||||
|
ARMII::AddrMode getMemAddrMode() const {
|
||||||
|
return Mem.AddrMode;
|
||||||
|
}
|
||||||
unsigned getMemBaseRegNum() const {
|
unsigned getMemBaseRegNum() const {
|
||||||
return Mem.BaseRegNum;
|
return Mem.BaseRegNum;
|
||||||
}
|
}
|
||||||
@ -338,6 +350,27 @@ public:
|
|||||||
bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
|
bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
|
||||||
bool isMemory() const { return Kind == Memory; }
|
bool isMemory() const { return Kind == Memory; }
|
||||||
bool isShifter() const { return Kind == Shifter; }
|
bool isShifter() const { return Kind == Shifter; }
|
||||||
|
bool isMemMode2() const {
|
||||||
|
if (getMemAddrMode() != ARMII::AddrMode2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (getMemOffsetIsReg())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (getMemNegative() &&
|
||||||
|
!(getMemPostindexed() || getMemPreindexed()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemOffset());
|
||||||
|
if (!CE) return false;
|
||||||
|
int64_t Value = CE->getValue();
|
||||||
|
|
||||||
|
// The offset must be in the range 0-4095 (imm12).
|
||||||
|
if (Value > 4095 || Value < -4095)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool isMemMode5() const {
|
bool isMemMode5() const {
|
||||||
if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() ||
|
if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() ||
|
||||||
getMemNegative())
|
getMemNegative())
|
||||||
@ -465,6 +498,46 @@ public:
|
|||||||
"No offset operand support in mode 7");
|
"No offset operand support in mode 7");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addMemMode2Operands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(isMemMode2() && "Invalid mode or number of operands!");
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum()));
|
||||||
|
|
||||||
|
if (getMemOffsetIsReg()) {
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(getMemOffsetRegNum()));
|
||||||
|
|
||||||
|
ARM_AM::AddrOpc AMOpc = getMemNegative() ? ARM_AM::sub : ARM_AM::add;
|
||||||
|
ARM_AM::ShiftOpc ShOpc = ARM_AM::no_shift;
|
||||||
|
int64_t ShiftAmount = 0;
|
||||||
|
|
||||||
|
if (getMemOffsetRegShifted()) {
|
||||||
|
ShOpc = getMemShiftType();
|
||||||
|
const MCConstantExpr *CE =
|
||||||
|
dyn_cast<MCConstantExpr>(getMemShiftAmount());
|
||||||
|
ShiftAmount = CE->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(AMOpc, ShiftAmount,
|
||||||
|
ShOpc)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a operand placeholder to always yield the same number of operands.
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(0));
|
||||||
|
|
||||||
|
// FIXME: #-0 is encoded differently than #0. Does the parser preserve
|
||||||
|
// the difference?
|
||||||
|
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemOffset());
|
||||||
|
assert(CE && "Non-constant mode 2 offset operand!");
|
||||||
|
int64_t Offset = CE->getValue();
|
||||||
|
|
||||||
|
if (Offset >= 0)
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(ARM_AM::add,
|
||||||
|
Offset, ARM_AM::no_shift)));
|
||||||
|
else
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM2Opc(ARM_AM::sub,
|
||||||
|
-Offset, ARM_AM::no_shift)));
|
||||||
|
}
|
||||||
|
|
||||||
void addMemMode5Operands(MCInst &Inst, unsigned N) const {
|
void addMemMode5Operands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 2 && isMemMode5() && "Invalid number of operands!");
|
assert(N == 2 && isMemMode5() && "Invalid number of operands!");
|
||||||
|
|
||||||
@ -599,9 +672,9 @@ public:
|
|||||||
return Op;
|
return Op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ARMOperand *CreateMem(unsigned BaseRegNum, bool OffsetIsReg,
|
static ARMOperand *CreateMem(ARMII::AddrMode AddrMode, unsigned BaseRegNum,
|
||||||
const MCExpr *Offset, int OffsetRegNum,
|
bool OffsetIsReg, const MCExpr *Offset,
|
||||||
bool OffsetRegShifted,
|
int OffsetRegNum, bool OffsetRegShifted,
|
||||||
enum ARM_AM::ShiftOpc ShiftType,
|
enum ARM_AM::ShiftOpc ShiftType,
|
||||||
const MCExpr *ShiftAmount, bool Preindexed,
|
const MCExpr *ShiftAmount, bool Preindexed,
|
||||||
bool Postindexed, bool Negative, bool Writeback,
|
bool Postindexed, bool Negative, bool Writeback,
|
||||||
@ -618,6 +691,7 @@ public:
|
|||||||
"Cannot have expression offset and register offset!");
|
"Cannot have expression offset and register offset!");
|
||||||
|
|
||||||
ARMOperand *Op = new ARMOperand(Memory);
|
ARMOperand *Op = new ARMOperand(Memory);
|
||||||
|
Op->Mem.AddrMode = AddrMode;
|
||||||
Op->Mem.BaseRegNum = BaseRegNum;
|
Op->Mem.BaseRegNum = BaseRegNum;
|
||||||
Op->Mem.OffsetIsReg = OffsetIsReg;
|
Op->Mem.OffsetIsReg = OffsetIsReg;
|
||||||
if (OffsetIsReg)
|
if (OffsetIsReg)
|
||||||
@ -689,7 +763,8 @@ void ARMOperand::dump(raw_ostream &OS) const {
|
|||||||
break;
|
break;
|
||||||
case Memory:
|
case Memory:
|
||||||
OS << "<memory "
|
OS << "<memory "
|
||||||
<< "base:" << getMemBaseRegNum();
|
<< "am:" << ARMII::AddrModeToString(getMemAddrMode())
|
||||||
|
<< " base:" << getMemBaseRegNum();
|
||||||
if (getMemOffsetIsReg()) {
|
if (getMemOffsetIsReg()) {
|
||||||
OS << " offset:<register " << getMemOffsetRegNum();
|
OS << " offset:<register " << getMemOffsetRegNum();
|
||||||
if (getMemOffsetRegShifted()) {
|
if (getMemOffsetRegShifted()) {
|
||||||
@ -1132,13 +1207,57 @@ tryParseMSRMaskOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
|||||||
return MatchOperand_Success;
|
return MatchOperand_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// tryParseMemMode2Operand - Try to parse memory addressing mode 2 operand.
|
||||||
|
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
|
||||||
|
tryParseMemMode2Operand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
|
SMLoc S = Parser.getTok().getLoc();
|
||||||
|
const AsmToken &Tok = Parser.getTok();
|
||||||
|
assert(Tok.is(AsmToken::LBrac) && "Token is not a \"[\"");
|
||||||
|
|
||||||
|
if (ParseMemory(Operands, ARMII::AddrMode2))
|
||||||
|
return MatchOperand_NoMatch;
|
||||||
|
|
||||||
|
return MatchOperand_Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CvtLdWriteBackRegAddrMode2 - 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::
|
||||||
|
CvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
|
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
|
||||||
|
|
||||||
|
// Create a writeback register dummy placeholder.
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(0));
|
||||||
|
|
||||||
|
((ARMOperand*)Operands[3])->addMemMode2Operands(Inst, 3);
|
||||||
|
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CvtStWriteBackRegAddrMode2 - 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::
|
||||||
|
CvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
|
// Create a writeback register dummy placeholder.
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(0));
|
||||||
|
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
|
||||||
|
((ARMOperand*)Operands[3])->addMemMode2Operands(Inst, 3);
|
||||||
|
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse an ARM memory expression, return false if successful else return true
|
/// Parse an ARM memory expression, return false if successful else return true
|
||||||
/// or an error. The first token must be a '[' when called.
|
/// or an error. The first token must be a '[' when called.
|
||||||
///
|
///
|
||||||
/// TODO Only preindexing and postindexing addressing are started, unindexed
|
/// TODO Only preindexing and postindexing addressing are started, unindexed
|
||||||
/// with option, etc are still to do.
|
/// with option, etc are still to do.
|
||||||
bool ARMAsmParser::
|
bool ARMAsmParser::
|
||||||
ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||||
|
ARMII::AddrMode AddrMode = ARMII::AddrModeNone) {
|
||||||
SMLoc S, E;
|
SMLoc S, E;
|
||||||
assert(Parser.getTok().is(AsmToken::LBrac) &&
|
assert(Parser.getTok().is(AsmToken::LBrac) &&
|
||||||
"Token is not a Left Bracket");
|
"Token is not a Left Bracket");
|
||||||
@ -1231,11 +1350,10 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
|||||||
Offset = MCConstantExpr::Create(0, getContext());
|
Offset = MCConstantExpr::Create(0, getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
Operands.push_back(ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset,
|
Operands.push_back(ARMOperand::CreateMem(AddrMode, BaseRegNum, OffsetIsReg,
|
||||||
OffsetRegNum, OffsetRegShifted,
|
Offset, OffsetRegNum, OffsetRegShifted,
|
||||||
ShiftType, ShiftAmount, Preindexed,
|
ShiftType, ShiftAmount, Preindexed,
|
||||||
Postindexed, Negative, Writeback,
|
Postindexed, Negative, Writeback, S, E));
|
||||||
S, E));
|
|
||||||
if (WBOp)
|
if (WBOp)
|
||||||
Operands.push_back(WBOp);
|
Operands.push_back(WBOp);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#define DEBUG_TYPE "asm-printer"
|
#define DEBUG_TYPE "asm-printer"
|
||||||
#include "ARMBaseInfo.h"
|
#include "ARMBaseInfo.h"
|
||||||
#include "ARMInstPrinter.h"
|
#include "ARMInstPrinter.h"
|
||||||
|
#include "ARMInstrInfo.h"
|
||||||
#include "ARMAddressingModes.h"
|
#include "ARMAddressingModes.h"
|
||||||
#include "llvm/MC/MCInst.h"
|
#include "llvm/MC/MCInst.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
@ -181,18 +182,12 @@ void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMInstPrinter::printAM2PreOrOffsetIndexOp(const MCInst *MI, unsigned Op,
|
||||||
void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op,
|
raw_ostream &O) {
|
||||||
raw_ostream &O) {
|
|
||||||
const MCOperand &MO1 = MI->getOperand(Op);
|
const MCOperand &MO1 = MI->getOperand(Op);
|
||||||
const MCOperand &MO2 = MI->getOperand(Op+1);
|
const MCOperand &MO2 = MI->getOperand(Op+1);
|
||||||
const MCOperand &MO3 = MI->getOperand(Op+2);
|
const MCOperand &MO3 = MI->getOperand(Op+2);
|
||||||
|
|
||||||
if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
|
|
||||||
printOperand(MI, Op, O);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
O << "[" << getRegisterName(MO1.getReg());
|
O << "[" << getRegisterName(MO1.getReg());
|
||||||
|
|
||||||
if (!MO2.getReg()) {
|
if (!MO2.getReg()) {
|
||||||
@ -215,6 +210,52 @@ void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op,
|
|||||||
O << "]";
|
O << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMInstPrinter::printAM2PostIndexOp(const MCInst *MI, unsigned Op,
|
||||||
|
raw_ostream &O) {
|
||||||
|
const MCOperand &MO1 = MI->getOperand(Op);
|
||||||
|
const MCOperand &MO2 = MI->getOperand(Op+1);
|
||||||
|
const MCOperand &MO3 = MI->getOperand(Op+2);
|
||||||
|
|
||||||
|
O << "[" << getRegisterName(MO1.getReg()) << "], ";
|
||||||
|
|
||||||
|
if (!MO2.getReg()) {
|
||||||
|
unsigned ImmOffs = ARM_AM::getAM2Offset(MO3.getImm());
|
||||||
|
O << '#'
|
||||||
|
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||||
|
<< ImmOffs;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||||
|
<< getRegisterName(MO2.getReg());
|
||||||
|
|
||||||
|
if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
|
||||||
|
O << ", "
|
||||||
|
<< ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm()))
|
||||||
|
<< " #" << ShImm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ARMInstPrinter::printAddrMode2Operand(const MCInst *MI, unsigned Op,
|
||||||
|
raw_ostream &O) {
|
||||||
|
const MCOperand &MO1 = MI->getOperand(Op);
|
||||||
|
|
||||||
|
if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
|
||||||
|
printOperand(MI, Op, O);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Opcode = MI->getOpcode();
|
||||||
|
const TargetInstrDesc &Desc = TM.getInstrInfo()->get(Opcode);
|
||||||
|
uint64_t TSFlags = Desc.TSFlags;
|
||||||
|
unsigned IdxMode = (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
|
||||||
|
|
||||||
|
if (IdxMode == ARMII::IndexModePost) {
|
||||||
|
printAM2PostIndexOp(MI, Op, O);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printAM2PreOrOffsetIndexOp(MI, Op, O);
|
||||||
|
}
|
||||||
|
|
||||||
void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
|
void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
|
||||||
unsigned OpNum,
|
unsigned OpNum,
|
||||||
raw_ostream &O) {
|
raw_ostream &O) {
|
||||||
|
@ -22,9 +22,11 @@ class MCOperand;
|
|||||||
class TargetMachine;
|
class TargetMachine;
|
||||||
|
|
||||||
class ARMInstPrinter : public MCInstPrinter {
|
class ARMInstPrinter : public MCInstPrinter {
|
||||||
|
private:
|
||||||
|
TargetMachine &TM;
|
||||||
public:
|
public:
|
||||||
ARMInstPrinter(TargetMachine &TM, const MCAsmInfo &MAI)
|
ARMInstPrinter(TargetMachine &_TM, const MCAsmInfo &MAI)
|
||||||
: MCInstPrinter(MAI) {}
|
: MCInstPrinter(MAI), TM(_TM) {}
|
||||||
|
|
||||||
virtual void printInst(const MCInst *MI, raw_ostream &O);
|
virtual void printInst(const MCInst *MI, raw_ostream &O);
|
||||||
virtual StringRef getOpcodeName(unsigned Opcode) const;
|
virtual StringRef getOpcodeName(unsigned Opcode) const;
|
||||||
@ -42,7 +44,11 @@ public:
|
|||||||
void printSOImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
void printSOImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||||
|
|
||||||
void printSORegOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
void printSORegOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||||
|
|
||||||
void printAddrMode2Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
void printAddrMode2Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||||
|
void printAM2PostIndexOp(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||||
|
void printAM2PreOrOffsetIndexOp(const MCInst *MI, unsigned OpNum,
|
||||||
|
raw_ostream &O);
|
||||||
void printAddrMode2OffsetOperand(const MCInst *MI, unsigned OpNum,
|
void printAddrMode2OffsetOperand(const MCInst *MI, unsigned OpNum,
|
||||||
raw_ostream &O);
|
raw_ostream &O);
|
||||||
void printAddrMode3Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
void printAddrMode3Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||||
|
34
test/MC/ARM/arm_addrmode2.s
Normal file
34
test/MC/ARM/arm_addrmode2.s
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@ RUN: llvm-mc -mcpu=cortex-a8 -triple arm-unknown-unknown -show-encoding %s | FileCheck %s
|
||||||
|
|
||||||
|
@ Post-indexed
|
||||||
|
@ CHECK: ldrt r1, [r0], r2 @ encoding: [0x02,0x10,0xb0,0xe6]
|
||||||
|
@ CHECK: ldrt r1, [r0], r2, lsr #3 @ encoding: [0xa2,0x11,0xb0,0xe6]
|
||||||
|
@ CHECK: ldrt r1, [r0], #4 @ encoding: [0x04,0x10,0xb0,0xe4]
|
||||||
|
@ CHECK: ldrbt r1, [r0], r2 @ encoding: [0x02,0x10,0xf0,0xe6]
|
||||||
|
@ CHECK: ldrbt r1, [r0], r2, lsr #3 @ encoding: [0xa2,0x11,0xf0,0xe6]
|
||||||
|
@ CHECK: ldrbt r1, [r0], #4 @ encoding: [0x04,0x10,0xf0,0xe4]
|
||||||
|
@ CHECK: strt r1, [r0], r2 @ encoding: [0x02,0x10,0xa0,0xe6]
|
||||||
|
@ CHECK: strt r1, [r0], r2, lsr #3 @ encoding: [0xa2,0x11,0xa0,0xe6]
|
||||||
|
@ CHECK: strt r1, [r0], #4 @ encoding: [0x04,0x10,0xa0,0xe4]
|
||||||
|
@ CHECK: strbt r1, [r0], r2 @ encoding: [0x02,0x10,0xe0,0xe6]
|
||||||
|
@ CHECK: strbt r1, [r0], r2, lsr #3 @ encoding: [0xa2,0x11,0xe0,0xe6]
|
||||||
|
@ CHECK: strbt r1, [r0], #4 @ encoding: [0x04,0x10,0xe0,0xe4]
|
||||||
|
ldrt r1, [r0], r2
|
||||||
|
ldrt r1, [r0], r2, lsr #3
|
||||||
|
ldrt r1, [r0], #4
|
||||||
|
ldrbt r1, [r0], r2
|
||||||
|
ldrbt r1, [r0], r2, lsr #3
|
||||||
|
ldrbt r1, [r0], #4
|
||||||
|
strt r1, [r0], r2
|
||||||
|
strt r1, [r0], r2, lsr #3
|
||||||
|
strt r1, [r0], #4
|
||||||
|
strbt r1, [r0], r2
|
||||||
|
strbt r1, [r0], r2, lsr #3
|
||||||
|
strbt r1, [r0], #4
|
||||||
|
|
||||||
|
@ Pre-indexed
|
||||||
|
@ CHECK: ldr r1, [r0, r2, lsr #3]! @ encoding: [0xa2,0x11,0xb0,0xe7]
|
||||||
|
@ CHECK: ldrb r1, [r0, r2, lsr #3]! @ encoding: [0xa2,0x11,0xf0,0xe7]
|
||||||
|
ldr r1, [r0, r2, lsr #3]!
|
||||||
|
ldrb r1, [r0, r2, lsr #3]!
|
||||||
|
|
Loading…
Reference in New Issue
Block a user