mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-09 13:33:17 +00:00
Add support to the ARM asm parser for the register-shifted-register forms of basic instructions like ADD. More work left to be done to support other instances of shifter ops in the ISA.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127917 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
31649e61bc
commit
0082830cb2
@ -381,11 +381,17 @@ def rot_imm : Operand<i32>, PatLeaf<(i32 imm), [{
|
||||
let EncoderMethod = "getRotImmOpValue";
|
||||
}
|
||||
|
||||
def ShifterAsmOperand : AsmOperandClass {
|
||||
let Name = "Shifter";
|
||||
let SuperClasses = [];
|
||||
}
|
||||
|
||||
// shift_imm: An integer that encodes a shift amount and the type of shift
|
||||
// (currently either asr or lsl) using the same encoding used for the
|
||||
// immediates in so_reg operands.
|
||||
def shift_imm : Operand<i32> {
|
||||
let PrintMethod = "printShiftImmOperand";
|
||||
let ParserMatchClass = ShifterAsmOperand;
|
||||
}
|
||||
|
||||
// shifter_operand operands: so_reg and so_imm.
|
||||
@ -394,14 +400,14 @@ def so_reg : Operand<i32>, // reg reg imm
|
||||
[shl,srl,sra,rotr]> {
|
||||
let EncoderMethod = "getSORegOpValue";
|
||||
let PrintMethod = "printSORegOperand";
|
||||
let MIOperandInfo = (ops GPR, GPR, i32imm);
|
||||
let MIOperandInfo = (ops GPR, GPR, shift_imm);
|
||||
}
|
||||
def shift_so_reg : Operand<i32>, // reg reg imm
|
||||
ComplexPattern<i32, 3, "SelectShiftShifterOperandReg",
|
||||
[shl,srl,sra,rotr]> {
|
||||
let EncoderMethod = "getSORegOpValue";
|
||||
let PrintMethod = "printSORegOperand";
|
||||
let MIOperandInfo = (ops GPR, GPR, i32imm);
|
||||
let MIOperandInfo = (ops GPR, GPR, shift_imm);
|
||||
}
|
||||
|
||||
// so_imm - Match a 32-bit shifter_operand immediate operand, which is an
|
||||
|
@ -29,15 +29,6 @@
|
||||
#include "llvm/ADT/Twine.h"
|
||||
using namespace llvm;
|
||||
|
||||
/// Shift types used for register controlled shifts in ARM memory addressing.
|
||||
enum ShiftType {
|
||||
Lsl,
|
||||
Lsr,
|
||||
Asr,
|
||||
Ror,
|
||||
Rrx
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
class ARMOperand;
|
||||
@ -55,6 +46,7 @@ class ARMAsmParser : public TargetAsmParser {
|
||||
int TryParseRegister();
|
||||
virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
|
||||
bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
bool TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
|
||||
@ -65,13 +57,14 @@ class ARMAsmParser : public TargetAsmParser {
|
||||
|
||||
bool ParseMemoryOffsetReg(bool &Negative,
|
||||
bool &OffsetRegShifted,
|
||||
enum ShiftType &ShiftType,
|
||||
enum ARM_AM::ShiftOpc &ShiftType,
|
||||
const MCExpr *&ShiftAmount,
|
||||
const MCExpr *&Offset,
|
||||
bool &OffsetIsReg,
|
||||
int &OffsetRegNum,
|
||||
SMLoc &E);
|
||||
bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E);
|
||||
bool ParseShift(enum ARM_AM::ShiftOpc &St,
|
||||
const MCExpr *&ShiftAmount, SMLoc &E);
|
||||
bool ParseDirectiveWord(unsigned Size, SMLoc L);
|
||||
bool ParseDirectiveThumb(SMLoc L);
|
||||
bool ParseDirectiveThumbFunc(SMLoc L);
|
||||
@ -136,6 +129,7 @@ class ARMOperand : public MCParsedAsmOperand {
|
||||
RegisterList,
|
||||
DPRRegisterList,
|
||||
SPRRegisterList,
|
||||
Shifter,
|
||||
Token
|
||||
} Kind;
|
||||
|
||||
@ -184,7 +178,7 @@ class ARMOperand : public MCParsedAsmOperand {
|
||||
const MCExpr *Value; ///< Offset value, when !OffsetIsReg.
|
||||
} Offset;
|
||||
const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
|
||||
enum ShiftType ShiftType; // used when OffsetRegShifted is true
|
||||
enum ARM_AM::ShiftOpc ShiftType; // used when OffsetRegShifted is true
|
||||
unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true
|
||||
unsigned Preindexed : 1;
|
||||
unsigned Postindexed : 1;
|
||||
@ -192,6 +186,11 @@ class ARMOperand : public MCParsedAsmOperand {
|
||||
unsigned Negative : 1; // only used when OffsetIsReg is true
|
||||
unsigned Writeback : 1;
|
||||
} Mem;
|
||||
|
||||
struct {
|
||||
ARM_AM::ShiftOpc ShiftTy;
|
||||
unsigned RegNum;
|
||||
} Shift;
|
||||
};
|
||||
|
||||
ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
|
||||
@ -234,6 +233,10 @@ public:
|
||||
break;
|
||||
case ProcIFlags:
|
||||
IFlags = o.IFlags;
|
||||
break;
|
||||
case Shifter:
|
||||
Shift = o.Shift;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,7 +313,7 @@ public:
|
||||
assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!");
|
||||
return Mem.ShiftAmount;
|
||||
}
|
||||
enum ShiftType getMemShiftType() const {
|
||||
enum ARM_AM::ShiftOpc getMemShiftType() const {
|
||||
assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!");
|
||||
return Mem.ShiftType;
|
||||
}
|
||||
@ -334,6 +337,7 @@ public:
|
||||
bool isToken() const { return Kind == Token; }
|
||||
bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
|
||||
bool isMemory() const { return Kind == Memory; }
|
||||
bool isShifter() const { return Kind == Shifter; }
|
||||
bool isMemMode5() const {
|
||||
if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() ||
|
||||
getMemNegative())
|
||||
@ -402,6 +406,12 @@ public:
|
||||
Inst.addOperand(MCOperand::CreateReg(getReg()));
|
||||
}
|
||||
|
||||
void addShifterOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::CreateImm(
|
||||
ARM_AM::getSORegOpc(Shift.ShiftTy, 0)));
|
||||
}
|
||||
|
||||
void addRegListOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
const SmallVectorImpl<unsigned> &RegList = getRegList();
|
||||
@ -525,6 +535,15 @@ public:
|
||||
return Op;
|
||||
}
|
||||
|
||||
static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy,
|
||||
SMLoc S, SMLoc E) {
|
||||
ARMOperand *Op = new ARMOperand(Shifter);
|
||||
Op->Shift.ShiftTy = ShTy;
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = E;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static ARMOperand *
|
||||
CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs,
|
||||
SMLoc StartLoc, SMLoc EndLoc) {
|
||||
@ -555,7 +574,8 @@ public:
|
||||
|
||||
static ARMOperand *CreateMem(unsigned BaseRegNum, bool OffsetIsReg,
|
||||
const MCExpr *Offset, int OffsetRegNum,
|
||||
bool OffsetRegShifted, enum ShiftType ShiftType,
|
||||
bool OffsetRegShifted,
|
||||
enum ARM_AM::ShiftOpc ShiftType,
|
||||
const MCExpr *ShiftAmount, bool Preindexed,
|
||||
bool Postindexed, bool Negative, bool Writeback,
|
||||
SMLoc S, SMLoc E) {
|
||||
@ -676,6 +696,9 @@ void ARMOperand::dump(raw_ostream &OS) const {
|
||||
case Register:
|
||||
OS << "<register " << getReg() << ">";
|
||||
break;
|
||||
case Shifter:
|
||||
OS << "<shifter " << getShiftOpcStr(Shift.ShiftTy) << ">";
|
||||
break;
|
||||
case RegisterList:
|
||||
case DPRRegisterList:
|
||||
case SPRRegisterList: {
|
||||
@ -738,6 +761,42 @@ int ARMAsmParser::TryParseRegister() {
|
||||
return RegNum;
|
||||
}
|
||||
|
||||
/// Try to parse a register name. The token must be an Identifier when called,
|
||||
/// and if it is a register name the token is eaten and the register number is
|
||||
/// returned. Otherwise return -1.
|
||||
///
|
||||
bool ARMAsmParser::TryParseShiftRegister(
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||
SMLoc S = Parser.getTok().getLoc();
|
||||
const AsmToken &Tok = Parser.getTok();
|
||||
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
|
||||
|
||||
std::string upperCase = Tok.getString().str();
|
||||
std::string lowerCase = LowercaseString(upperCase);
|
||||
ARM_AM::ShiftOpc ShiftTy = StringSwitch<ARM_AM::ShiftOpc>(lowerCase)
|
||||
.Case("lsl", ARM_AM::lsl)
|
||||
.Case("lsr", ARM_AM::lsr)
|
||||
.Case("asr", ARM_AM::asr)
|
||||
.Case("ror", ARM_AM::ror)
|
||||
.Case("rrx", ARM_AM::rrx)
|
||||
.Default(ARM_AM::no_shift);
|
||||
|
||||
if (ShiftTy == ARM_AM::no_shift)
|
||||
return true;
|
||||
|
||||
Parser.Lex(); // Eat shift-type operand;
|
||||
int RegNum = TryParseRegister();
|
||||
if (RegNum == -1)
|
||||
return Error(Parser.getTok().getLoc(), "register expected");
|
||||
|
||||
Operands.push_back(ARMOperand::CreateReg(RegNum,S, Parser.getTok().getLoc()));
|
||||
Operands.push_back(ARMOperand::CreateShifter(ShiftTy,
|
||||
S, Parser.getTok().getLoc()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Try to parse a register name. The token must be an Identifier when called.
|
||||
/// If it's a register, an AsmOperand is created. Another AsmOperand is created
|
||||
/// if there is a "writeback". 'true' if it's not a register.
|
||||
@ -1083,7 +1142,7 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||
ARMOperand *WBOp = 0;
|
||||
int OffsetRegNum = -1;
|
||||
bool OffsetRegShifted = false;
|
||||
enum ShiftType ShiftType = Lsl;
|
||||
enum ARM_AM::ShiftOpc ShiftType = ARM_AM::lsl;
|
||||
const MCExpr *ShiftAmount = 0;
|
||||
const MCExpr *Offset = 0;
|
||||
|
||||
@ -1165,7 +1224,7 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||
/// we return false on success or an error otherwise.
|
||||
bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative,
|
||||
bool &OffsetRegShifted,
|
||||
enum ShiftType &ShiftType,
|
||||
enum ARM_AM::ShiftOpc &ShiftType,
|
||||
const MCExpr *&ShiftAmount,
|
||||
const MCExpr *&Offset,
|
||||
bool &OffsetIsReg,
|
||||
@ -1226,28 +1285,28 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative,
|
||||
/// ( lsl | lsr | asr | ror ) , # shift_amount
|
||||
/// rrx
|
||||
/// and returns true if it parses a shift otherwise it returns false.
|
||||
bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount,
|
||||
SMLoc &E) {
|
||||
bool ARMAsmParser::ParseShift(ARM_AM::ShiftOpc &St,
|
||||
const MCExpr *&ShiftAmount, SMLoc &E) {
|
||||
const AsmToken &Tok = Parser.getTok();
|
||||
if (Tok.isNot(AsmToken::Identifier))
|
||||
return true;
|
||||
StringRef ShiftName = Tok.getString();
|
||||
if (ShiftName == "lsl" || ShiftName == "LSL")
|
||||
St = Lsl;
|
||||
St = ARM_AM::lsl;
|
||||
else if (ShiftName == "lsr" || ShiftName == "LSR")
|
||||
St = Lsr;
|
||||
St = ARM_AM::lsr;
|
||||
else if (ShiftName == "asr" || ShiftName == "ASR")
|
||||
St = Asr;
|
||||
St = ARM_AM::asr;
|
||||
else if (ShiftName == "ror" || ShiftName == "ROR")
|
||||
St = Ror;
|
||||
St = ARM_AM::ror;
|
||||
else if (ShiftName == "rrx" || ShiftName == "RRX")
|
||||
St = Rrx;
|
||||
St = ARM_AM::rrx;
|
||||
else
|
||||
return true;
|
||||
Parser.Lex(); // Eat shift type token.
|
||||
|
||||
// Rrx stands alone.
|
||||
if (St == Rrx)
|
||||
if (St == ARM_AM::rrx)
|
||||
return false;
|
||||
|
||||
// Otherwise, there must be a '#' and a shift amount.
|
||||
@ -1286,6 +1345,9 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||
case AsmToken::Identifier:
|
||||
if (!TryParseRegisterWithWriteBack(Operands))
|
||||
return false;
|
||||
if (!TryParseShiftRegister(Operands))
|
||||
return false;
|
||||
|
||||
|
||||
// Fall though for the Identifier case that is not a register or a
|
||||
// special name.
|
||||
|
@ -282,3 +282,5 @@
|
||||
@ CHECK: msr cpsr_fsxc, r0 @ encoding: [0x00,0xf0,0x2f,0xe1]
|
||||
msr cpsr_fsxc, r0
|
||||
|
||||
@ CHECK: add r1, r2, r3, lsl r4 @ encoding: [0x13,0x14,0x82,0xe0]
|
||||
add r1, r2, r3, lsl r4
|
||||
|
Loading…
x
Reference in New Issue
Block a user