2014-01-04 19:30:13 +08:00
|
|
|
//===-- SparcAsmParser.cpp - Parse Sparc assembly to MCInst instructions --===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "MCTargetDesc/SparcMCTargetDesc.h"
|
2014-01-07 16:00:49 +08:00
|
|
|
#include "MCTargetDesc/SparcMCExpr.h"
|
2014-01-04 19:30:13 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
#include "llvm/MC/MCInst.h"
|
2014-03-01 13:07:21 +08:00
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
2014-01-04 19:30:13 +08:00
|
|
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2014-03-01 13:07:21 +08:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2014-01-04 19:30:13 +08:00
|
|
|
#include "llvm/MC/MCTargetAsmParser.h"
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// The generated AsmMatcher SparcGenAsmMatcher uses "Sparc" as the target
|
|
|
|
// namespace. But SPARC backend uses "SP" as its namespace.
|
|
|
|
namespace llvm {
|
|
|
|
namespace Sparc {
|
|
|
|
using namespace SP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
2014-01-07 09:49:11 +08:00
|
|
|
class SparcOperand;
|
2014-01-04 19:30:13 +08:00
|
|
|
class SparcAsmParser : public MCTargetAsmParser {
|
|
|
|
|
|
|
|
MCSubtargetInfo &STI;
|
|
|
|
MCAsmParser &Parser;
|
|
|
|
|
|
|
|
/// @name Auto-generated Match Functions
|
|
|
|
/// {
|
|
|
|
|
|
|
|
#define GET_ASSEMBLER_HEADER
|
|
|
|
#include "SparcGenAsmMatcher.inc"
|
|
|
|
|
|
|
|
/// }
|
|
|
|
|
|
|
|
// public interface of the MCTargetAsmParser.
|
|
|
|
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
2014-06-09 00:18:35 +08:00
|
|
|
OperandVector &Operands, MCStreamer &Out,
|
2014-08-18 19:49:42 +08:00
|
|
|
uint64_t &ErrorInfo,
|
2014-04-29 15:57:13 +08:00
|
|
|
bool MatchingInlineAsm) override;
|
|
|
|
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
|
2014-01-04 19:30:13 +08:00
|
|
|
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
2014-06-09 00:18:35 +08:00
|
|
|
SMLoc NameLoc, OperandVector &Operands) override;
|
2014-04-29 15:57:13 +08:00
|
|
|
bool ParseDirective(AsmToken DirectiveID) override;
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
|
2014-04-29 15:57:13 +08:00
|
|
|
unsigned Kind) override;
|
2014-01-04 19:30:13 +08:00
|
|
|
|
|
|
|
// Custom parse functions for Sparc specific operands.
|
2014-06-09 00:18:35 +08:00
|
|
|
OperandMatchResultTy parseMEMOperand(OperandVector &Operands);
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name);
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-01-07 09:49:11 +08:00
|
|
|
OperandMatchResultTy
|
2014-06-09 00:18:35 +08:00
|
|
|
parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Operand,
|
|
|
|
bool isCall = false);
|
2014-01-07 09:49:11 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
OperandMatchResultTy parseBranchModifiers(OperandVector &Operands);
|
2014-03-02 04:08:48 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
// returns true if Tok is matched to a register and returns register in RegNo.
|
2014-01-12 12:48:54 +08:00
|
|
|
bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo,
|
|
|
|
unsigned &RegKind);
|
|
|
|
|
2014-01-07 16:00:49 +08:00
|
|
|
bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
|
2014-03-01 10:18:04 +08:00
|
|
|
bool parseDirectiveWord(unsigned Size, SMLoc L);
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-03-01 10:18:04 +08:00
|
|
|
bool is64Bit() const { return STI.getTargetTriple().startswith("sparcv9"); }
|
2015-05-19 00:43:33 +08:00
|
|
|
|
|
|
|
void expandSET(MCInst &Inst, SMLoc IDLoc,
|
|
|
|
SmallVectorImpl<MCInst> &Instructions);
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
public:
|
|
|
|
SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
|
2014-04-23 19:16:03 +08:00
|
|
|
const MCInstrInfo &MII,
|
|
|
|
const MCTargetOptions &Options)
|
2014-01-04 19:30:13 +08:00
|
|
|
: MCTargetAsmParser(), STI(sti), Parser(parser) {
|
|
|
|
// Initialize the set of available features.
|
|
|
|
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned IntRegs[32] = {
|
|
|
|
Sparc::G0, Sparc::G1, Sparc::G2, Sparc::G3,
|
|
|
|
Sparc::G4, Sparc::G5, Sparc::G6, Sparc::G7,
|
|
|
|
Sparc::O0, Sparc::O1, Sparc::O2, Sparc::O3,
|
|
|
|
Sparc::O4, Sparc::O5, Sparc::O6, Sparc::O7,
|
|
|
|
Sparc::L0, Sparc::L1, Sparc::L2, Sparc::L3,
|
|
|
|
Sparc::L4, Sparc::L5, Sparc::L6, Sparc::L7,
|
|
|
|
Sparc::I0, Sparc::I1, Sparc::I2, Sparc::I3,
|
|
|
|
Sparc::I4, Sparc::I5, Sparc::I6, Sparc::I7 };
|
|
|
|
|
|
|
|
static unsigned FloatRegs[32] = {
|
|
|
|
Sparc::F0, Sparc::F1, Sparc::F2, Sparc::F3,
|
|
|
|
Sparc::F4, Sparc::F5, Sparc::F6, Sparc::F7,
|
|
|
|
Sparc::F8, Sparc::F9, Sparc::F10, Sparc::F11,
|
|
|
|
Sparc::F12, Sparc::F13, Sparc::F14, Sparc::F15,
|
|
|
|
Sparc::F16, Sparc::F17, Sparc::F18, Sparc::F19,
|
|
|
|
Sparc::F20, Sparc::F21, Sparc::F22, Sparc::F23,
|
|
|
|
Sparc::F24, Sparc::F25, Sparc::F26, Sparc::F27,
|
|
|
|
Sparc::F28, Sparc::F29, Sparc::F30, Sparc::F31 };
|
|
|
|
|
|
|
|
static unsigned DoubleRegs[32] = {
|
|
|
|
Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3,
|
|
|
|
Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7,
|
|
|
|
Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9,
|
|
|
|
Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15,
|
|
|
|
Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19,
|
|
|
|
Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23,
|
|
|
|
Sparc::D24, Sparc::D25, Sparc::D26, Sparc::D27,
|
|
|
|
Sparc::D28, Sparc::D29, Sparc::D30, Sparc::D31 };
|
|
|
|
|
|
|
|
static unsigned QuadFPRegs[32] = {
|
|
|
|
Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3,
|
|
|
|
Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7,
|
2014-01-24 13:24:01 +08:00
|
|
|
Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11,
|
2014-01-04 19:30:13 +08:00
|
|
|
Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
|
|
|
|
|
2015-05-19 00:29:48 +08:00
|
|
|
static unsigned ASRRegs[32] = {
|
|
|
|
SP::Y, SP::ASR1, SP::ASR2, SP::ASR3,
|
|
|
|
SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7,
|
|
|
|
SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11,
|
|
|
|
SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
|
|
|
|
SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
|
|
|
|
SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
|
|
|
|
SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
|
|
|
|
SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
|
2014-01-04 19:30:13 +08:00
|
|
|
|
|
|
|
/// SparcOperand - Instances of this class represent a parsed Sparc machine
|
|
|
|
/// instruction.
|
|
|
|
class SparcOperand : public MCParsedAsmOperand {
|
|
|
|
public:
|
|
|
|
enum RegisterKind {
|
|
|
|
rk_None,
|
|
|
|
rk_IntReg,
|
|
|
|
rk_FloatReg,
|
|
|
|
rk_DoubleReg,
|
|
|
|
rk_QuadReg,
|
2015-05-19 00:38:47 +08:00
|
|
|
rk_Special,
|
2014-01-04 19:30:13 +08:00
|
|
|
};
|
2015-05-19 00:38:47 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
private:
|
|
|
|
enum KindTy {
|
|
|
|
k_Token,
|
|
|
|
k_Register,
|
|
|
|
k_Immediate,
|
|
|
|
k_MemoryReg,
|
|
|
|
k_MemoryImm
|
|
|
|
} Kind;
|
|
|
|
|
|
|
|
SMLoc StartLoc, EndLoc;
|
|
|
|
|
|
|
|
struct Token {
|
|
|
|
const char *Data;
|
|
|
|
unsigned Length;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RegOp {
|
|
|
|
unsigned RegNum;
|
|
|
|
RegisterKind Kind;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ImmOp {
|
|
|
|
const MCExpr *Val;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct MemOp {
|
|
|
|
unsigned Base;
|
|
|
|
unsigned OffsetReg;
|
|
|
|
const MCExpr *Off;
|
|
|
|
};
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct Token Tok;
|
|
|
|
struct RegOp Reg;
|
|
|
|
struct ImmOp Imm;
|
|
|
|
struct MemOp Mem;
|
|
|
|
};
|
|
|
|
public:
|
2014-06-09 00:18:35 +08:00
|
|
|
SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
|
|
|
|
|
2014-04-29 15:57:13 +08:00
|
|
|
bool isToken() const override { return Kind == k_Token; }
|
|
|
|
bool isReg() const override { return Kind == k_Register; }
|
|
|
|
bool isImm() const override { return Kind == k_Immediate; }
|
|
|
|
bool isMem() const override { return isMEMrr() || isMEMri(); }
|
2014-01-04 19:30:13 +08:00
|
|
|
bool isMEMrr() const { return Kind == k_MemoryReg; }
|
|
|
|
bool isMEMri() const { return Kind == k_MemoryImm; }
|
|
|
|
|
2014-01-12 12:48:54 +08:00
|
|
|
bool isFloatReg() const {
|
|
|
|
return (Kind == k_Register && Reg.Kind == rk_FloatReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isFloatOrDoubleReg() const {
|
|
|
|
return (Kind == k_Register && (Reg.Kind == rk_FloatReg
|
|
|
|
|| Reg.Kind == rk_DoubleReg));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
StringRef getToken() const {
|
|
|
|
assert(Kind == k_Token && "Invalid access!");
|
|
|
|
return StringRef(Tok.Data, Tok.Length);
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:57:13 +08:00
|
|
|
unsigned getReg() const override {
|
2014-01-04 19:30:13 +08:00
|
|
|
assert((Kind == k_Register) && "Invalid access!");
|
|
|
|
return Reg.RegNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MCExpr *getImm() const {
|
|
|
|
assert((Kind == k_Immediate) && "Invalid access!");
|
|
|
|
return Imm.Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getMemBase() const {
|
|
|
|
assert((Kind == k_MemoryReg || Kind == k_MemoryImm) && "Invalid access!");
|
|
|
|
return Mem.Base;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getMemOffsetReg() const {
|
|
|
|
assert((Kind == k_MemoryReg) && "Invalid access!");
|
|
|
|
return Mem.OffsetReg;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MCExpr *getMemOff() const {
|
|
|
|
assert((Kind == k_MemoryImm) && "Invalid access!");
|
|
|
|
return Mem.Off;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getStartLoc - Get the location of the first token of this operand.
|
2014-04-29 15:57:13 +08:00
|
|
|
SMLoc getStartLoc() const override {
|
2014-01-04 19:30:13 +08:00
|
|
|
return StartLoc;
|
|
|
|
}
|
|
|
|
/// getEndLoc - Get the location of the last token of this operand.
|
2014-04-29 15:57:13 +08:00
|
|
|
SMLoc getEndLoc() const override {
|
2014-01-04 19:30:13 +08:00
|
|
|
return EndLoc;
|
|
|
|
}
|
|
|
|
|
2014-04-29 15:57:13 +08:00
|
|
|
void print(raw_ostream &OS) const override {
|
2014-01-04 19:30:13 +08:00
|
|
|
switch (Kind) {
|
|
|
|
case k_Token: OS << "Token: " << getToken() << "\n"; break;
|
|
|
|
case k_Register: OS << "Reg: #" << getReg() << "\n"; break;
|
|
|
|
case k_Immediate: OS << "Imm: " << getImm() << "\n"; break;
|
|
|
|
case k_MemoryReg: OS << "Mem: " << getMemBase() << "+"
|
|
|
|
<< getMemOffsetReg() << "\n"; break;
|
2014-04-28 12:05:08 +08:00
|
|
|
case k_MemoryImm: assert(getMemOff() != nullptr);
|
2014-01-04 19:30:13 +08:00
|
|
|
OS << "Mem: " << getMemBase()
|
|
|
|
<< "+" << *getMemOff()
|
|
|
|
<< "\n"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void addRegOperands(MCInst &Inst, unsigned N) const {
|
|
|
|
assert(N == 1 && "Invalid number of operands!");
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(getReg()));
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void addImmOperands(MCInst &Inst, unsigned N) const {
|
|
|
|
assert(N == 1 && "Invalid number of operands!");
|
|
|
|
const MCExpr *Expr = getImm();
|
|
|
|
addExpr(Inst, Expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addExpr(MCInst &Inst, const MCExpr *Expr) const{
|
|
|
|
// Add as immediate when possible. Null MCExpr = 0.
|
2014-04-25 13:30:21 +08:00
|
|
|
if (!Expr)
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createImm(0));
|
2014-01-04 19:30:13 +08:00
|
|
|
else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createImm(CE->getValue()));
|
2014-01-04 19:30:13 +08:00
|
|
|
else
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createExpr(Expr));
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void addMEMrrOperands(MCInst &Inst, unsigned N) const {
|
|
|
|
assert(N == 2 && "Invalid number of operands!");
|
|
|
|
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(getMemBase()));
|
2014-01-04 19:30:13 +08:00
|
|
|
|
|
|
|
assert(getMemOffsetReg() != 0 && "Invalid offset");
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void addMEMriOperands(MCInst &Inst, unsigned N) const {
|
|
|
|
assert(N == 2 && "Invalid number of operands!");
|
|
|
|
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(getMemBase()));
|
2014-01-04 19:30:13 +08:00
|
|
|
|
|
|
|
const MCExpr *Expr = getMemOff();
|
|
|
|
addExpr(Inst, Expr);
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand> CreateToken(StringRef Str, SMLoc S) {
|
|
|
|
auto Op = make_unique<SparcOperand>(k_Token);
|
2014-01-04 19:30:13 +08:00
|
|
|
Op->Tok.Data = Str.data();
|
|
|
|
Op->Tok.Length = Str.size();
|
|
|
|
Op->StartLoc = S;
|
|
|
|
Op->EndLoc = S;
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand> CreateReg(unsigned RegNum, unsigned Kind,
|
|
|
|
SMLoc S, SMLoc E) {
|
|
|
|
auto Op = make_unique<SparcOperand>(k_Register);
|
2014-01-04 19:30:13 +08:00
|
|
|
Op->Reg.RegNum = RegNum;
|
2014-01-12 12:48:54 +08:00
|
|
|
Op->Reg.Kind = (SparcOperand::RegisterKind)Kind;
|
2014-01-04 19:30:13 +08:00
|
|
|
Op->StartLoc = S;
|
|
|
|
Op->EndLoc = E;
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand> CreateImm(const MCExpr *Val, SMLoc S,
|
|
|
|
SMLoc E) {
|
|
|
|
auto Op = make_unique<SparcOperand>(k_Immediate);
|
2014-01-04 19:30:13 +08:00
|
|
|
Op->Imm.Val = Val;
|
|
|
|
Op->StartLoc = S;
|
|
|
|
Op->EndLoc = E;
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static bool MorphToDoubleReg(SparcOperand &Op) {
|
|
|
|
unsigned Reg = Op.getReg();
|
|
|
|
assert(Op.Reg.Kind == rk_FloatReg);
|
2014-01-12 12:48:54 +08:00
|
|
|
unsigned regIdx = Reg - Sparc::F0;
|
|
|
|
if (regIdx % 2 || regIdx > 31)
|
2014-06-09 00:18:35 +08:00
|
|
|
return false;
|
|
|
|
Op.Reg.RegNum = DoubleRegs[regIdx / 2];
|
|
|
|
Op.Reg.Kind = rk_DoubleReg;
|
|
|
|
return true;
|
2014-01-12 12:48:54 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static bool MorphToQuadReg(SparcOperand &Op) {
|
|
|
|
unsigned Reg = Op.getReg();
|
2014-01-12 12:48:54 +08:00
|
|
|
unsigned regIdx = 0;
|
2014-06-09 00:18:35 +08:00
|
|
|
switch (Op.Reg.Kind) {
|
2014-06-18 13:05:13 +08:00
|
|
|
default: llvm_unreachable("Unexpected register kind!");
|
2014-01-12 12:48:54 +08:00
|
|
|
case rk_FloatReg:
|
|
|
|
regIdx = Reg - Sparc::F0;
|
|
|
|
if (regIdx % 4 || regIdx > 31)
|
2014-06-09 00:18:35 +08:00
|
|
|
return false;
|
2014-01-12 12:48:54 +08:00
|
|
|
Reg = QuadFPRegs[regIdx / 4];
|
|
|
|
break;
|
|
|
|
case rk_DoubleReg:
|
|
|
|
regIdx = Reg - Sparc::D0;
|
|
|
|
if (regIdx % 2 || regIdx > 31)
|
2014-06-09 00:18:35 +08:00
|
|
|
return false;
|
2014-01-12 12:48:54 +08:00
|
|
|
Reg = QuadFPRegs[regIdx / 2];
|
|
|
|
break;
|
|
|
|
}
|
2014-06-09 00:18:35 +08:00
|
|
|
Op.Reg.RegNum = Reg;
|
|
|
|
Op.Reg.Kind = rk_QuadReg;
|
|
|
|
return true;
|
2014-01-12 12:48:54 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand>
|
|
|
|
MorphToMEMrr(unsigned Base, std::unique_ptr<SparcOperand> Op) {
|
2014-01-07 09:49:11 +08:00
|
|
|
unsigned offsetReg = Op->getReg();
|
|
|
|
Op->Kind = k_MemoryReg;
|
|
|
|
Op->Mem.Base = Base;
|
|
|
|
Op->Mem.OffsetReg = offsetReg;
|
2014-04-25 13:30:21 +08:00
|
|
|
Op->Mem.Off = nullptr;
|
2014-01-07 09:49:11 +08:00
|
|
|
return Op;
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand>
|
2015-04-29 22:54:44 +08:00
|
|
|
CreateMEMr(unsigned Base, SMLoc S, SMLoc E) {
|
|
|
|
auto Op = make_unique<SparcOperand>(k_MemoryReg);
|
2014-01-07 09:49:11 +08:00
|
|
|
Op->Mem.Base = Base;
|
2015-04-29 22:54:44 +08:00
|
|
|
Op->Mem.OffsetReg = Sparc::G0; // always 0
|
|
|
|
Op->Mem.Off = nullptr;
|
2014-01-07 09:49:11 +08:00
|
|
|
Op->StartLoc = S;
|
|
|
|
Op->EndLoc = E;
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
static std::unique_ptr<SparcOperand>
|
|
|
|
MorphToMEMri(unsigned Base, std::unique_ptr<SparcOperand> Op) {
|
2014-01-07 09:49:11 +08:00
|
|
|
const MCExpr *Imm = Op->getImm();
|
|
|
|
Op->Kind = k_MemoryImm;
|
|
|
|
Op->Mem.Base = Base;
|
|
|
|
Op->Mem.OffsetReg = 0;
|
|
|
|
Op->Mem.Off = Imm;
|
|
|
|
return Op;
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // end namespace
|
|
|
|
|
2015-05-19 00:43:33 +08:00
|
|
|
void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
|
|
|
|
SmallVectorImpl<MCInst> &Instructions) {
|
|
|
|
MCOperand MCRegOp = Inst.getOperand(0);
|
|
|
|
MCOperand MCValOp = Inst.getOperand(1);
|
|
|
|
assert(MCRegOp.isReg());
|
|
|
|
assert(MCValOp.isImm() || MCValOp.isExpr());
|
|
|
|
|
|
|
|
// the imm operand can be either an expression or an immediate.
|
|
|
|
bool IsImm = Inst.getOperand(1).isImm();
|
|
|
|
uint64_t ImmValue = IsImm ? MCValOp.getImm() : 0;
|
|
|
|
const MCExpr *ValExpr;
|
|
|
|
if (IsImm)
|
2015-05-30 09:25:56 +08:00
|
|
|
ValExpr = MCConstantExpr::create(ImmValue, getContext());
|
2015-05-19 00:43:33 +08:00
|
|
|
else
|
|
|
|
ValExpr = MCValOp.getExpr();
|
|
|
|
|
|
|
|
MCOperand PrevReg = MCOperand::createReg(Sparc::G0);
|
|
|
|
|
|
|
|
if (!IsImm || (ImmValue & ~0x1fff)) {
|
|
|
|
MCInst TmpInst;
|
|
|
|
const MCExpr *Expr =
|
2015-05-30 09:25:56 +08:00
|
|
|
SparcMCExpr::create(SparcMCExpr::VK_Sparc_HI, ValExpr, getContext());
|
2015-05-19 00:43:33 +08:00
|
|
|
TmpInst.setLoc(IDLoc);
|
|
|
|
TmpInst.setOpcode(SP::SETHIi);
|
|
|
|
TmpInst.addOperand(MCRegOp);
|
|
|
|
TmpInst.addOperand(MCOperand::createExpr(Expr));
|
|
|
|
Instructions.push_back(TmpInst);
|
|
|
|
PrevReg = MCRegOp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsImm || ((ImmValue & 0x1fff) != 0 || ImmValue == 0)) {
|
|
|
|
MCInst TmpInst;
|
|
|
|
const MCExpr *Expr =
|
2015-05-30 09:25:56 +08:00
|
|
|
SparcMCExpr::create(SparcMCExpr::VK_Sparc_LO, ValExpr, getContext());
|
2015-05-19 00:43:33 +08:00
|
|
|
TmpInst.setLoc(IDLoc);
|
|
|
|
TmpInst.setOpcode(SP::ORri);
|
|
|
|
TmpInst.addOperand(MCRegOp);
|
|
|
|
TmpInst.addOperand(PrevReg);
|
|
|
|
TmpInst.addOperand(MCOperand::createExpr(Expr));
|
|
|
|
Instructions.push_back(TmpInst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
|
|
OperandVector &Operands,
|
|
|
|
MCStreamer &Out,
|
2014-08-18 19:49:42 +08:00
|
|
|
uint64_t &ErrorInfo,
|
2014-06-09 00:18:35 +08:00
|
|
|
bool MatchingInlineAsm) {
|
2014-01-04 19:30:13 +08:00
|
|
|
MCInst Inst;
|
|
|
|
SmallVector<MCInst, 8> Instructions;
|
|
|
|
unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
|
|
|
MatchingInlineAsm);
|
|
|
|
switch (MatchResult) {
|
|
|
|
case Match_Success: {
|
2015-05-19 00:43:33 +08:00
|
|
|
switch (Inst.getOpcode()) {
|
|
|
|
default:
|
|
|
|
Inst.setLoc(IDLoc);
|
|
|
|
Instructions.push_back(Inst);
|
|
|
|
break;
|
|
|
|
case SP::SET:
|
|
|
|
expandSET(Inst, IDLoc, Instructions);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const MCInst &I : Instructions) {
|
|
|
|
Out.EmitInstruction(I, STI);
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Match_MissingFeature:
|
|
|
|
return Error(IDLoc,
|
|
|
|
"instruction requires a CPU feature not currently enabled");
|
|
|
|
|
|
|
|
case Match_InvalidOperand: {
|
|
|
|
SMLoc ErrorLoc = IDLoc;
|
2014-08-18 19:49:42 +08:00
|
|
|
if (ErrorInfo != ~0ULL) {
|
2014-01-04 19:30:13 +08:00
|
|
|
if (ErrorInfo >= Operands.size())
|
|
|
|
return Error(IDLoc, "too few operands for instruction");
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
ErrorLoc = ((SparcOperand &)*Operands[ErrorInfo]).getStartLoc();
|
2014-01-04 19:30:13 +08:00
|
|
|
if (ErrorLoc == SMLoc())
|
|
|
|
ErrorLoc = IDLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error(ErrorLoc, "invalid operand for instruction");
|
|
|
|
}
|
|
|
|
case Match_MnemonicFail:
|
2014-03-02 02:54:52 +08:00
|
|
|
return Error(IDLoc, "invalid instruction mnemonic");
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
2015-01-03 16:16:34 +08:00
|
|
|
llvm_unreachable("Implement any new match types added!");
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SparcAsmParser::
|
|
|
|
ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc)
|
|
|
|
{
|
|
|
|
const AsmToken &Tok = Parser.getTok();
|
|
|
|
StartLoc = Tok.getLoc();
|
|
|
|
EndLoc = Tok.getEndLoc();
|
|
|
|
RegNo = 0;
|
|
|
|
if (getLexer().getKind() != AsmToken::Percent)
|
|
|
|
return false;
|
|
|
|
Parser.Lex();
|
2014-01-12 12:48:54 +08:00
|
|
|
unsigned regKind = SparcOperand::rk_None;
|
|
|
|
if (matchRegisterName(Tok, RegNo, regKind)) {
|
2014-01-04 19:30:13 +08:00
|
|
|
Parser.Lex();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error(StartLoc, "invalid register name");
|
|
|
|
}
|
|
|
|
|
2014-08-18 19:49:42 +08:00
|
|
|
static void applyMnemonicAliases(StringRef &Mnemonic, uint64_t Features,
|
2014-03-03 06:55:53 +08:00
|
|
|
unsigned VariantID);
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
|
|
|
|
StringRef Name, SMLoc NameLoc,
|
|
|
|
OperandVector &Operands) {
|
2014-03-02 02:54:52 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
// First operand in MCInst is instruction mnemonic.
|
|
|
|
Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
|
|
|
|
|
2014-03-03 06:55:53 +08:00
|
|
|
// apply mnemonic aliases, if any, so that we can parse operands correctly.
|
|
|
|
applyMnemonicAliases(Name, getAvailableFeatures(), 0);
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
|
|
|
// Read the first operand.
|
2014-03-02 04:08:48 +08:00
|
|
|
if (getLexer().is(AsmToken::Comma)) {
|
|
|
|
if (parseBranchModifiers(Operands) != MatchOperand_Success) {
|
|
|
|
SMLoc Loc = getLexer().getLoc();
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return Error(Loc, "unexpected token");
|
|
|
|
}
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
if (parseOperand(Operands, Name) != MatchOperand_Success) {
|
|
|
|
SMLoc Loc = getLexer().getLoc();
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return Error(Loc, "unexpected token");
|
|
|
|
}
|
|
|
|
|
|
|
|
while (getLexer().is(AsmToken::Comma)) {
|
|
|
|
Parser.Lex(); // Eat the comma.
|
|
|
|
// Parse and remember the operand.
|
|
|
|
if (parseOperand(Operands, Name) != MatchOperand_Success) {
|
|
|
|
SMLoc Loc = getLexer().getLoc();
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return Error(Loc, "unexpected token");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
|
|
|
SMLoc Loc = getLexer().getLoc();
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return Error(Loc, "unexpected token");
|
|
|
|
}
|
|
|
|
Parser.Lex(); // Consume the EndOfStatement.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SparcAsmParser::
|
|
|
|
ParseDirective(AsmToken DirectiveID)
|
|
|
|
{
|
2014-03-01 10:18:04 +08:00
|
|
|
StringRef IDVal = DirectiveID.getString();
|
|
|
|
|
|
|
|
if (IDVal == ".byte")
|
|
|
|
return parseDirectiveWord(1, DirectiveID.getLoc());
|
|
|
|
|
|
|
|
if (IDVal == ".half")
|
|
|
|
return parseDirectiveWord(2, DirectiveID.getLoc());
|
|
|
|
|
|
|
|
if (IDVal == ".word")
|
|
|
|
return parseDirectiveWord(4, DirectiveID.getLoc());
|
|
|
|
|
|
|
|
if (IDVal == ".nword")
|
|
|
|
return parseDirectiveWord(is64Bit() ? 8 : 4, DirectiveID.getLoc());
|
|
|
|
|
|
|
|
if (is64Bit() && IDVal == ".xword")
|
|
|
|
return parseDirectiveWord(8, DirectiveID.getLoc());
|
|
|
|
|
|
|
|
if (IDVal == ".register") {
|
|
|
|
// For now, ignore .register directive.
|
|
|
|
Parser.eatToEndOfStatement();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let the MC layer to handle other directives.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SparcAsmParser:: parseDirectiveWord(unsigned Size, SMLoc L) {
|
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
|
|
|
for (;;) {
|
|
|
|
const MCExpr *Value;
|
|
|
|
if (getParser().parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
getParser().getStreamer().EmitValue(Value, Size);
|
|
|
|
|
|
|
|
if (getLexer().is(AsmToken::EndOfStatement))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// FIXME: Improve diagnostic.
|
|
|
|
if (getLexer().isNot(AsmToken::Comma))
|
|
|
|
return Error(L, "unexpected token in directive");
|
|
|
|
Parser.Lex();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Parser.Lex();
|
2014-01-04 19:30:13 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
SparcAsmParser::OperandMatchResultTy
|
|
|
|
SparcAsmParser::parseMEMOperand(OperandVector &Operands) {
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-01-07 09:49:11 +08:00
|
|
|
SMLoc S, E;
|
|
|
|
unsigned BaseReg = 0;
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-01-07 09:49:11 +08:00
|
|
|
if (ParseRegister(BaseReg, S, E)) {
|
|
|
|
return MatchOperand_NoMatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (getLexer().getKind()) {
|
|
|
|
default: return MatchOperand_NoMatch;
|
|
|
|
|
2014-01-10 09:48:17 +08:00
|
|
|
case AsmToken::Comma:
|
2014-01-07 09:49:11 +08:00
|
|
|
case AsmToken::RBrac:
|
|
|
|
case AsmToken::EndOfStatement:
|
2015-04-29 22:54:44 +08:00
|
|
|
Operands.push_back(SparcOperand::CreateMEMr(BaseReg, S, E));
|
2014-01-07 09:49:11 +08:00
|
|
|
return MatchOperand_Success;
|
|
|
|
|
|
|
|
case AsmToken:: Plus:
|
|
|
|
Parser.Lex(); // Eat the '+'
|
|
|
|
break;
|
|
|
|
case AsmToken::Minus:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<SparcOperand> Offset;
|
2014-01-07 09:49:11 +08:00
|
|
|
OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset);
|
|
|
|
if (ResTy != MatchOperand_Success || !Offset)
|
|
|
|
return MatchOperand_NoMatch;
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
Operands.push_back(
|
|
|
|
Offset->isImm() ? SparcOperand::MorphToMEMri(BaseReg, std::move(Offset))
|
|
|
|
: SparcOperand::MorphToMEMrr(BaseReg, std::move(Offset)));
|
2014-01-07 09:49:11 +08:00
|
|
|
|
|
|
|
return MatchOperand_Success;
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
SparcAsmParser::OperandMatchResultTy
|
|
|
|
SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
|
2014-01-07 09:49:11 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
|
2014-01-07 09:49:11 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
// If there wasn't a custom match, try the generic matcher below. Otherwise,
|
|
|
|
// there was a match, but an error occurred, in which case, just return that
|
|
|
|
// the operand parsing failed.
|
2014-01-07 09:49:11 +08:00
|
|
|
if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail)
|
2014-01-04 19:30:13 +08:00
|
|
|
return ResTy;
|
|
|
|
|
2014-01-07 09:49:11 +08:00
|
|
|
if (getLexer().is(AsmToken::LBrac)) {
|
|
|
|
// Memory operand
|
|
|
|
Operands.push_back(SparcOperand::CreateToken("[",
|
|
|
|
Parser.getTok().getLoc()));
|
|
|
|
Parser.Lex(); // Eat the [
|
|
|
|
|
2014-02-07 15:34:49 +08:00
|
|
|
if (Mnemonic == "cas" || Mnemonic == "casx") {
|
|
|
|
SMLoc S = Parser.getTok().getLoc();
|
|
|
|
if (getLexer().getKind() != AsmToken::Percent)
|
|
|
|
return MatchOperand_NoMatch;
|
|
|
|
Parser.Lex(); // eat %
|
|
|
|
|
|
|
|
unsigned RegNo, RegKind;
|
|
|
|
if (!matchRegisterName(Parser.getTok(), RegNo, RegKind))
|
|
|
|
return MatchOperand_NoMatch;
|
|
|
|
|
|
|
|
Parser.Lex(); // Eat the identifier token.
|
|
|
|
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1);
|
|
|
|
Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E));
|
|
|
|
ResTy = MatchOperand_Success;
|
|
|
|
} else {
|
|
|
|
ResTy = parseMEMOperand(Operands);
|
|
|
|
}
|
|
|
|
|
2014-01-07 09:49:11 +08:00
|
|
|
if (ResTy != MatchOperand_Success)
|
|
|
|
return ResTy;
|
|
|
|
|
|
|
|
if (!getLexer().is(AsmToken::RBrac))
|
|
|
|
return MatchOperand_ParseFail;
|
|
|
|
|
|
|
|
Operands.push_back(SparcOperand::CreateToken("]",
|
|
|
|
Parser.getTok().getLoc()));
|
|
|
|
Parser.Lex(); // Eat the ]
|
Sparc: Add the "alternate address space" load/store instructions.
- Adds support for the asm syntax, which has an immediate integer
"ASI" (address space identifier) appearing after an address, before
a comma.
- Adds the various-width load, store, and swap in alternate address
space instructions. (ldsba, ldsha, lduba, lduha, lda, stba, stha,
sta, swapa)
This does not attempt to hook these instructions up to pointer address
spaces in LLVM, although that would probably be a reasonable thing to
do in the future.
Differential Revision: http://reviews.llvm.org/D8904
llvm-svn: 237581
2015-05-19 00:35:04 +08:00
|
|
|
|
|
|
|
// Parse an optional address-space identifier after the address.
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
std::unique_ptr<SparcOperand> Op;
|
|
|
|
ResTy = parseSparcAsmOperand(Op, false);
|
|
|
|
if (ResTy != MatchOperand_Success || !Op)
|
|
|
|
return MatchOperand_ParseFail;
|
|
|
|
Operands.push_back(std::move(Op));
|
|
|
|
}
|
2014-01-07 09:49:11 +08:00
|
|
|
return MatchOperand_Success;
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
std::unique_ptr<SparcOperand> Op;
|
2014-03-02 11:39:39 +08:00
|
|
|
|
2014-03-02 14:28:15 +08:00
|
|
|
ResTy = parseSparcAsmOperand(Op, (Mnemonic == "call"));
|
2014-01-07 09:49:11 +08:00
|
|
|
if (ResTy != MatchOperand_Success || !Op)
|
|
|
|
return MatchOperand_ParseFail;
|
|
|
|
|
|
|
|
// Push the parsed operand into the list of operands
|
2014-06-09 00:18:35 +08:00
|
|
|
Operands.push_back(std::move(Op));
|
2014-01-07 09:49:11 +08:00
|
|
|
|
|
|
|
return MatchOperand_Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
SparcAsmParser::OperandMatchResultTy
|
2014-06-09 00:18:35 +08:00
|
|
|
SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
|
|
|
|
bool isCall) {
|
2014-01-07 09:49:11 +08:00
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
SMLoc S = Parser.getTok().getLoc();
|
|
|
|
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
|
|
|
const MCExpr *EVal;
|
2014-01-07 09:49:11 +08:00
|
|
|
|
2014-04-25 13:30:21 +08:00
|
|
|
Op = nullptr;
|
2014-01-04 19:30:13 +08:00
|
|
|
switch (getLexer().getKind()) {
|
2014-01-07 09:49:11 +08:00
|
|
|
default: break;
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
case AsmToken::Percent:
|
|
|
|
Parser.Lex(); // Eat the '%'.
|
|
|
|
unsigned RegNo;
|
2014-01-12 12:48:54 +08:00
|
|
|
unsigned RegKind;
|
|
|
|
if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) {
|
2014-01-08 14:14:52 +08:00
|
|
|
StringRef name = Parser.getTok().getString();
|
2014-01-04 19:30:13 +08:00
|
|
|
Parser.Lex(); // Eat the identifier token.
|
2014-01-07 16:00:49 +08:00
|
|
|
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
2014-01-08 14:14:52 +08:00
|
|
|
switch (RegNo) {
|
|
|
|
default:
|
2014-01-12 12:48:54 +08:00
|
|
|
Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
|
2014-01-08 14:14:52 +08:00
|
|
|
break;
|
2015-05-19 00:38:47 +08:00
|
|
|
case Sparc::PSR:
|
|
|
|
Op = SparcOperand::CreateToken("%psr", S);
|
|
|
|
break;
|
|
|
|
case Sparc::WIM:
|
|
|
|
Op = SparcOperand::CreateToken("%wim", S);
|
|
|
|
break;
|
|
|
|
case Sparc::TBR:
|
|
|
|
Op = SparcOperand::CreateToken("%tbr", S);
|
|
|
|
break;
|
2014-01-08 14:14:52 +08:00
|
|
|
case Sparc::ICC:
|
|
|
|
if (name == "xcc")
|
|
|
|
Op = SparcOperand::CreateToken("%xcc", S);
|
|
|
|
else
|
|
|
|
Op = SparcOperand::CreateToken("%icc", S);
|
|
|
|
break;
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2014-01-07 16:00:49 +08:00
|
|
|
if (matchSparcAsmModifiers(EVal, E)) {
|
|
|
|
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
|
|
|
Op = SparcOperand::CreateImm(EVal, S, E);
|
|
|
|
}
|
2014-01-07 09:49:11 +08:00
|
|
|
break;
|
2014-01-04 19:30:13 +08:00
|
|
|
|
|
|
|
case AsmToken::Minus:
|
|
|
|
case AsmToken::Integer:
|
2015-04-30 02:48:29 +08:00
|
|
|
case AsmToken::LParen:
|
2014-01-07 16:00:49 +08:00
|
|
|
if (!getParser().parseExpression(EVal, E))
|
2014-01-07 09:49:11 +08:00
|
|
|
Op = SparcOperand::CreateImm(EVal, S, E);
|
2014-01-04 19:30:13 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AsmToken::Identifier: {
|
|
|
|
StringRef Identifier;
|
2014-01-07 09:49:11 +08:00
|
|
|
if (!getParser().parseIdentifier(Identifier)) {
|
2014-01-07 16:00:49 +08:00
|
|
|
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
|
2014-01-07 09:49:11 +08:00
|
|
|
getContext());
|
2014-03-01 13:07:21 +08:00
|
|
|
if (isCall &&
|
|
|
|
getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_)
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = SparcMCExpr::create(SparcMCExpr::VK_Sparc_WPLT30, Res,
|
2014-03-01 13:07:21 +08:00
|
|
|
getContext());
|
2014-01-07 09:49:11 +08:00
|
|
|
Op = SparcOperand::CreateImm(Res, S, E);
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-01-07 09:49:11 +08:00
|
|
|
return (Op) ? MatchOperand_Success : MatchOperand_ParseFail;
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
SparcAsmParser::OperandMatchResultTy
|
|
|
|
SparcAsmParser::parseBranchModifiers(OperandVector &Operands) {
|
2014-03-02 04:08:48 +08:00
|
|
|
|
|
|
|
// parse (,a|,pn|,pt)+
|
|
|
|
|
|
|
|
while (getLexer().is(AsmToken::Comma)) {
|
|
|
|
|
|
|
|
Parser.Lex(); // Eat the comma
|
|
|
|
|
|
|
|
if (!getLexer().is(AsmToken::Identifier))
|
|
|
|
return MatchOperand_ParseFail;
|
|
|
|
StringRef modName = Parser.getTok().getString();
|
|
|
|
if (modName == "a" || modName == "pn" || modName == "pt") {
|
|
|
|
Operands.push_back(SparcOperand::CreateToken(modName,
|
|
|
|
Parser.getTok().getLoc()));
|
|
|
|
Parser.Lex(); // eat the identifier.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return MatchOperand_Success;
|
|
|
|
}
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
|
|
|
|
unsigned &RegNo,
|
2014-01-12 12:48:54 +08:00
|
|
|
unsigned &RegKind)
|
2014-01-04 19:30:13 +08:00
|
|
|
{
|
|
|
|
int64_t intVal = 0;
|
|
|
|
RegNo = 0;
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_None;
|
2014-01-04 19:30:13 +08:00
|
|
|
if (Tok.is(AsmToken::Identifier)) {
|
|
|
|
StringRef name = Tok.getString();
|
|
|
|
|
|
|
|
// %fp
|
|
|
|
if (name.equals("fp")) {
|
|
|
|
RegNo = Sparc::I6;
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// %sp
|
|
|
|
if (name.equals("sp")) {
|
|
|
|
RegNo = Sparc::O6;
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("y")) {
|
|
|
|
RegNo = Sparc::Y;
|
2015-05-19 00:38:47 +08:00
|
|
|
RegKind = SparcOperand::rk_Special;
|
2015-05-19 00:29:48 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.substr(0, 3).equals_lower("asr")
|
|
|
|
&& !name.substr(3).getAsInteger(10, intVal)
|
|
|
|
&& intVal > 0 && intVal < 32) {
|
|
|
|
RegNo = ASRRegs[intVal];
|
2015-05-19 00:38:47 +08:00
|
|
|
RegKind = SparcOperand::rk_Special;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("icc")) {
|
|
|
|
RegNo = Sparc::ICC;
|
2015-05-19 00:38:47 +08:00
|
|
|
RegKind = SparcOperand::rk_Special;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("psr")) {
|
|
|
|
RegNo = Sparc::PSR;
|
|
|
|
RegKind = SparcOperand::rk_Special;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("wim")) {
|
|
|
|
RegNo = Sparc::WIM;
|
|
|
|
RegKind = SparcOperand::rk_Special;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("tbr")) {
|
|
|
|
RegNo = Sparc::TBR;
|
|
|
|
RegKind = SparcOperand::rk_Special;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name.equals("xcc")) {
|
|
|
|
// FIXME:: check 64bit.
|
|
|
|
RegNo = Sparc::ICC;
|
2015-05-19 00:38:47 +08:00
|
|
|
RegKind = SparcOperand::rk_Special;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// %fcc0 - %fcc3
|
|
|
|
if (name.substr(0, 3).equals_lower("fcc")
|
|
|
|
&& !name.substr(3).getAsInteger(10, intVal)
|
|
|
|
&& intVal < 4) {
|
|
|
|
// FIXME: check 64bit and handle %fcc1 - %fcc3
|
2014-03-02 11:39:39 +08:00
|
|
|
RegNo = Sparc::FCC0 + intVal;
|
2015-05-19 00:38:47 +08:00
|
|
|
RegKind = SparcOperand::rk_Special;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// %g0 - %g7
|
|
|
|
if (name.substr(0, 1).equals_lower("g")
|
|
|
|
&& !name.substr(1).getAsInteger(10, intVal)
|
|
|
|
&& intVal < 8) {
|
|
|
|
RegNo = IntRegs[intVal];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// %o0 - %o7
|
|
|
|
if (name.substr(0, 1).equals_lower("o")
|
|
|
|
&& !name.substr(1).getAsInteger(10, intVal)
|
|
|
|
&& intVal < 8) {
|
|
|
|
RegNo = IntRegs[8 + intVal];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (name.substr(0, 1).equals_lower("l")
|
|
|
|
&& !name.substr(1).getAsInteger(10, intVal)
|
|
|
|
&& intVal < 8) {
|
|
|
|
RegNo = IntRegs[16 + intVal];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (name.substr(0, 1).equals_lower("i")
|
|
|
|
&& !name.substr(1).getAsInteger(10, intVal)
|
|
|
|
&& intVal < 8) {
|
|
|
|
RegNo = IntRegs[24 + intVal];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// %f0 - %f31
|
|
|
|
if (name.substr(0, 1).equals_lower("f")
|
|
|
|
&& !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
|
2014-01-12 12:48:54 +08:00
|
|
|
RegNo = FloatRegs[intVal];
|
|
|
|
RegKind = SparcOperand::rk_FloatReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// %f32 - %f62
|
|
|
|
if (name.substr(0, 1).equals_lower("f")
|
|
|
|
&& !name.substr(1, 2).getAsInteger(10, intVal)
|
|
|
|
&& intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
|
2014-01-12 12:48:54 +08:00
|
|
|
// FIXME: Check V9
|
2014-01-24 05:41:10 +08:00
|
|
|
RegNo = DoubleRegs[intVal/2];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_DoubleReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// %r0 - %r31
|
|
|
|
if (name.substr(0, 1).equals_lower("r")
|
|
|
|
&& !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
|
|
|
|
RegNo = IntRegs[intVal];
|
2014-01-12 12:48:54 +08:00
|
|
|
RegKind = SparcOperand::rk_IntReg;
|
2014-01-04 19:30:13 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-01 13:07:21 +08:00
|
|
|
static bool hasGOTReference(const MCExpr *Expr) {
|
|
|
|
switch (Expr->getKind()) {
|
|
|
|
case MCExpr::Target:
|
|
|
|
if (const SparcMCExpr *SE = dyn_cast<SparcMCExpr>(Expr))
|
|
|
|
return hasGOTReference(SE->getSubExpr());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MCExpr::Constant:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MCExpr::Binary: {
|
|
|
|
const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
|
|
|
|
return hasGOTReference(BE->getLHS()) || hasGOTReference(BE->getRHS());
|
|
|
|
}
|
|
|
|
|
|
|
|
case MCExpr::SymbolRef: {
|
|
|
|
const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
|
|
|
|
return (SymRef.getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_");
|
|
|
|
}
|
|
|
|
|
|
|
|
case MCExpr::Unary:
|
|
|
|
return hasGOTReference(cast<MCUnaryExpr>(Expr)->getSubExpr());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2014-01-04 19:30:13 +08:00
|
|
|
|
2014-01-07 16:00:49 +08:00
|
|
|
bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
|
|
|
|
SMLoc &EndLoc)
|
|
|
|
{
|
|
|
|
AsmToken Tok = Parser.getTok();
|
|
|
|
if (!Tok.is(AsmToken::Identifier))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
StringRef name = Tok.getString();
|
|
|
|
|
|
|
|
SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name);
|
|
|
|
|
|
|
|
if (VK == SparcMCExpr::VK_Sparc_None)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Parser.Lex(); // Eat the identifier.
|
|
|
|
if (Parser.getTok().getKind() != AsmToken::LParen)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Parser.Lex(); // Eat the LParen token.
|
|
|
|
const MCExpr *subExpr;
|
|
|
|
if (Parser.parseParenExpression(subExpr, EndLoc))
|
|
|
|
return false;
|
2014-03-01 13:07:21 +08:00
|
|
|
|
|
|
|
bool isPIC = getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_;
|
|
|
|
|
|
|
|
switch(VK) {
|
|
|
|
default: break;
|
|
|
|
case SparcMCExpr::VK_Sparc_LO:
|
|
|
|
VK = (hasGOTReference(subExpr)
|
|
|
|
? SparcMCExpr::VK_Sparc_PC10
|
|
|
|
: (isPIC ? SparcMCExpr::VK_Sparc_GOT10 : VK));
|
|
|
|
break;
|
|
|
|
case SparcMCExpr::VK_Sparc_HI:
|
|
|
|
VK = (hasGOTReference(subExpr)
|
|
|
|
? SparcMCExpr::VK_Sparc_PC22
|
|
|
|
: (isPIC ? SparcMCExpr::VK_Sparc_GOT22 : VK));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
EVal = SparcMCExpr::create(VK, subExpr, getContext());
|
2014-01-07 16:00:49 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-04 19:30:13 +08:00
|
|
|
extern "C" void LLVMInitializeSparcAsmParser() {
|
|
|
|
RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
|
|
|
|
RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
|
2015-04-30 04:30:57 +08:00
|
|
|
RegisterMCAsmParser<SparcAsmParser> C(TheSparcelTarget);
|
2014-01-04 19:30:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define GET_REGISTER_MATCHER
|
|
|
|
#define GET_MATCHER_IMPLEMENTATION
|
|
|
|
#include "SparcGenAsmMatcher.inc"
|
2014-01-12 12:48:54 +08:00
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
unsigned SparcAsmParser::validateTargetOperandClass(MCParsedAsmOperand &GOp,
|
|
|
|
unsigned Kind) {
|
|
|
|
SparcOperand &Op = (SparcOperand &)GOp;
|
|
|
|
if (Op.isFloatOrDoubleReg()) {
|
2014-01-12 12:48:54 +08:00
|
|
|
switch (Kind) {
|
|
|
|
default: break;
|
|
|
|
case MCK_DFPRegs:
|
2014-06-09 00:18:35 +08:00
|
|
|
if (!Op.isFloatReg() || SparcOperand::MorphToDoubleReg(Op))
|
2014-01-12 12:48:54 +08:00
|
|
|
return MCTargetAsmParser::Match_Success;
|
|
|
|
break;
|
|
|
|
case MCK_QFPRegs:
|
|
|
|
if (SparcOperand::MorphToQuadReg(Op))
|
|
|
|
return MCTargetAsmParser::Match_Success;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Match_InvalidOperand;
|
|
|
|
}
|