a426b286c8
patch for r263619, and unify all the URLs to point to svnweb.
845 lines
26 KiB
Diff
845 lines
26 KiB
Diff
Pull in r198484 from upstream llvm trunk (by Venkatraman Govindaraju):
|
|
|
|
[Sparc] Add the initial implementation of an asm parser for sparc/sparcv9.
|
|
|
|
Introduced here: http://svnweb.freebsd.org/changeset/base/262261
|
|
|
|
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
|
|
===================================================================
|
|
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
|
|
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
|
|
@@ -123,13 +123,18 @@ extern "C" void LLVMInitializeSparcTargetMC() {
|
|
|
|
// Register the MC instruction info.
|
|
TargetRegistry::RegisterMCInstrInfo(TheSparcTarget, createSparcMCInstrInfo);
|
|
+ TargetRegistry::RegisterMCInstrInfo(TheSparcV9Target, createSparcMCInstrInfo);
|
|
|
|
// Register the MC register info.
|
|
TargetRegistry::RegisterMCRegInfo(TheSparcTarget, createSparcMCRegisterInfo);
|
|
+ TargetRegistry::RegisterMCRegInfo(TheSparcV9Target,
|
|
+ createSparcMCRegisterInfo);
|
|
|
|
// Register the MC subtarget info.
|
|
TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget,
|
|
createSparcMCSubtargetInfo);
|
|
+ TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target,
|
|
+ createSparcMCSubtargetInfo);
|
|
|
|
TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
|
|
createMCAsmStreamer);
|
|
Index: lib/Target/Sparc/LLVMBuild.txt
|
|
===================================================================
|
|
--- lib/Target/Sparc/LLVMBuild.txt
|
|
+++ lib/Target/Sparc/LLVMBuild.txt
|
|
@@ -16,7 +16,7 @@
|
|
;===------------------------------------------------------------------------===;
|
|
|
|
[common]
|
|
-subdirectories = InstPrinter MCTargetDesc TargetInfo
|
|
+subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo
|
|
|
|
[component_0]
|
|
type = TargetGroup
|
|
Index: lib/Target/Sparc/SparcInstrInfo.td
|
|
===================================================================
|
|
--- lib/Target/Sparc/SparcInstrInfo.td
|
|
+++ lib/Target/Sparc/SparcInstrInfo.td
|
|
@@ -76,13 +76,25 @@ def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr
|
|
def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>;
|
|
|
|
// Address operands
|
|
+def SparcMEMrrAsmOperand : AsmOperandClass {
|
|
+ let Name = "MEMrr";
|
|
+ let ParserMethod = "parseMEMrrOperand";
|
|
+}
|
|
+
|
|
+def SparcMEMriAsmOperand : AsmOperandClass {
|
|
+ let Name = "MEMri";
|
|
+ let ParserMethod = "parseMEMriOperand";
|
|
+}
|
|
+
|
|
def MEMrr : Operand<iPTR> {
|
|
let PrintMethod = "printMemOperand";
|
|
let MIOperandInfo = (ops ptr_rc, ptr_rc);
|
|
+ let ParserMatchClass = SparcMEMrrAsmOperand;
|
|
}
|
|
def MEMri : Operand<iPTR> {
|
|
let PrintMethod = "printMemOperand";
|
|
let MIOperandInfo = (ops ptr_rc, i32imm);
|
|
+ let ParserMatchClass = SparcMEMriAsmOperand;
|
|
}
|
|
|
|
def TLSSym : Operand<iPTR>;
|
|
@@ -239,7 +251,10 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val>
|
|
|
|
// Pseudo instructions.
|
|
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
|
|
- : InstSP<outs, ins, asmstr, pattern>;
|
|
+ : InstSP<outs, ins, asmstr, pattern> {
|
|
+ let isCodeGenOnly = 1;
|
|
+ let isPseudo = 1;
|
|
+}
|
|
|
|
// GETPCX for PIC
|
|
let Defs = [O7] in {
|
|
@@ -503,7 +518,7 @@ defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i3
|
|
defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>;
|
|
|
|
// "LEA" forms of add (patterns to make tblgen happy)
|
|
-let Predicates = [Is32Bit] in
|
|
+let Predicates = [Is32Bit], isCodeGenOnly = 1 in
|
|
def LEA_ADDri : F3_2<2, 0b000000,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"add ${addr:arith}, $dst",
|
|
Index: lib/Target/Sparc/CMakeLists.txt
|
|
===================================================================
|
|
--- lib/Target/Sparc/CMakeLists.txt
|
|
+++ lib/Target/Sparc/CMakeLists.txt
|
|
@@ -4,6 +4,7 @@ tablegen(LLVM SparcGenRegisterInfo.inc -gen-regist
|
|
tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
|
|
tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter)
|
|
tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
|
|
+tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
|
|
tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
|
|
tablegen(LLVM SparcGenSubtargetInfo.inc -gen-subtarget)
|
|
tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv)
|
|
@@ -31,3 +32,4 @@ add_dependencies(LLVMSparcCodeGen SparcCommonTable
|
|
add_subdirectory(TargetInfo)
|
|
add_subdirectory(MCTargetDesc)
|
|
add_subdirectory(InstPrinter)
|
|
+add_subdirectory(AsmParser)
|
|
Index: lib/Target/Sparc/Makefile
|
|
===================================================================
|
|
--- lib/Target/Sparc/Makefile
|
|
+++ lib/Target/Sparc/Makefile
|
|
@@ -13,11 +13,12 @@ TARGET = Sparc
|
|
|
|
# Make sure that tblgen is run, first thing.
|
|
BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \
|
|
- SparcGenAsmWriter.inc SparcGenDAGISel.inc \
|
|
+ SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \
|
|
+ SparcGenDAGISel.inc \
|
|
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
|
|
SparcGenCodeEmitter.inc
|
|
|
|
-DIRS = InstPrinter TargetInfo MCTargetDesc
|
|
+DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc
|
|
|
|
include $(LEVEL)/Makefile.common
|
|
|
|
Index: lib/Target/Sparc/Sparc.td
|
|
===================================================================
|
|
--- lib/Target/Sparc/Sparc.td
|
|
+++ lib/Target/Sparc/Sparc.td
|
|
@@ -44,6 +44,10 @@ include "SparcInstrInfo.td"
|
|
|
|
def SparcInstrInfo : InstrInfo;
|
|
|
|
+def SparcAsmParser : AsmParser {
|
|
+ bit ShouldEmitMatchRegisterName = 0;
|
|
+}
|
|
+
|
|
//===----------------------------------------------------------------------===//
|
|
// SPARC processors supported.
|
|
//===----------------------------------------------------------------------===//
|
|
@@ -77,6 +81,7 @@ def SparcAsmWriter : AsmWriter {
|
|
def Sparc : Target {
|
|
// Pull in Instruction Info:
|
|
let InstructionSet = SparcInstrInfo;
|
|
+ let AssemblyParsers = [SparcAsmParser];
|
|
|
|
let AssemblyWriters = [SparcAsmWriter];
|
|
}
|
|
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
|
|
===================================================================
|
|
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
|
|
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
|
|
@@ -0,0 +1,614 @@
|
|
+//===-- 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"
|
|
+#include "llvm/ADT/STLExtras.h"
|
|
+#include "llvm/MC/MCContext.h"
|
|
+#include "llvm/MC/MCInst.h"
|
|
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
|
+#include "llvm/MC/MCStreamer.h"
|
|
+#include "llvm/MC/MCSubtargetInfo.h"
|
|
+#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 {
|
|
+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,
|
|
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ MCStreamer &Out, unsigned &ErrorInfo,
|
|
+ bool MatchingInlineAsm);
|
|
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
|
|
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
|
+ SMLoc NameLoc,
|
|
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands);
|
|
+ bool ParseDirective(AsmToken DirectiveID);
|
|
+
|
|
+
|
|
+ // Custom parse functions for Sparc specific operands.
|
|
+ OperandMatchResultTy
|
|
+ parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
|
|
+ OperandMatchResultTy
|
|
+ parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
|
|
+
|
|
+ OperandMatchResultTy
|
|
+ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ int ImmOffsetOrReg);
|
|
+
|
|
+ OperandMatchResultTy
|
|
+ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ StringRef Name);
|
|
+
|
|
+ // returns true if Tok is matched to a register and returns register in RegNo.
|
|
+ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
|
|
+ bool isQFP);
|
|
+
|
|
+public:
|
|
+ SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
|
|
+ const MCInstrInfo &MII)
|
|
+ : 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,
|
|
+ Sparc::Q8, Sparc::Q7, Sparc::Q8, Sparc::Q9,
|
|
+ Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
|
|
+
|
|
+
|
|
+/// 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,
|
|
+ rk_CCReg,
|
|
+ rk_Y
|
|
+ };
|
|
+private:
|
|
+ enum KindTy {
|
|
+ k_Token,
|
|
+ k_Register,
|
|
+ k_Immediate,
|
|
+ k_MemoryReg,
|
|
+ k_MemoryImm
|
|
+ } Kind;
|
|
+
|
|
+ SMLoc StartLoc, EndLoc;
|
|
+
|
|
+ SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
|
|
+
|
|
+ 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:
|
|
+ bool isToken() const { return Kind == k_Token; }
|
|
+ bool isReg() const { return Kind == k_Register; }
|
|
+ bool isImm() const { return Kind == k_Immediate; }
|
|
+ bool isMem() const { return isMEMrr() || isMEMri(); }
|
|
+ bool isMEMrr() const { return Kind == k_MemoryReg; }
|
|
+ bool isMEMri() const { return Kind == k_MemoryImm; }
|
|
+
|
|
+ StringRef getToken() const {
|
|
+ assert(Kind == k_Token && "Invalid access!");
|
|
+ return StringRef(Tok.Data, Tok.Length);
|
|
+ }
|
|
+
|
|
+ unsigned getReg() const {
|
|
+ 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.
|
|
+ SMLoc getStartLoc() const {
|
|
+ return StartLoc;
|
|
+ }
|
|
+ /// getEndLoc - Get the location of the last token of this operand.
|
|
+ SMLoc getEndLoc() const {
|
|
+ return EndLoc;
|
|
+ }
|
|
+
|
|
+ virtual void print(raw_ostream &OS) const {
|
|
+ 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;
|
|
+ case k_MemoryImm: assert(getMemOff() != 0);
|
|
+ OS << "Mem: " << getMemBase()
|
|
+ << "+" << *getMemOff()
|
|
+ << "\n"; break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void addRegOperands(MCInst &Inst, unsigned N) const {
|
|
+ assert(N == 1 && "Invalid number of operands!");
|
|
+ Inst.addOperand(MCOperand::CreateReg(getReg()));
|
|
+ }
|
|
+
|
|
+ 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.
|
|
+ if (Expr == 0)
|
|
+ Inst.addOperand(MCOperand::CreateImm(0));
|
|
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
|
|
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
|
|
+ else
|
|
+ Inst.addOperand(MCOperand::CreateExpr(Expr));
|
|
+ }
|
|
+
|
|
+ void addMEMrrOperands(MCInst &Inst, unsigned N) const {
|
|
+ assert(N == 2 && "Invalid number of operands!");
|
|
+
|
|
+ Inst.addOperand(MCOperand::CreateReg(getMemBase()));
|
|
+
|
|
+ assert(getMemOffsetReg() != 0 && "Invalid offset");
|
|
+ Inst.addOperand(MCOperand::CreateReg(getMemOffsetReg()));
|
|
+ }
|
|
+
|
|
+ void addMEMriOperands(MCInst &Inst, unsigned N) const {
|
|
+ assert(N == 2 && "Invalid number of operands!");
|
|
+
|
|
+ Inst.addOperand(MCOperand::CreateReg(getMemBase()));
|
|
+
|
|
+ const MCExpr *Expr = getMemOff();
|
|
+ addExpr(Inst, Expr);
|
|
+ }
|
|
+
|
|
+ static SparcOperand *CreateToken(StringRef Str, SMLoc S) {
|
|
+ SparcOperand *Op = new SparcOperand(k_Token);
|
|
+ Op->Tok.Data = Str.data();
|
|
+ Op->Tok.Length = Str.size();
|
|
+ Op->StartLoc = S;
|
|
+ Op->EndLoc = S;
|
|
+ return Op;
|
|
+ }
|
|
+
|
|
+ static SparcOperand *CreateReg(unsigned RegNum,
|
|
+ SparcOperand::RegisterKind Kind,
|
|
+ SMLoc S, SMLoc E) {
|
|
+ SparcOperand *Op = new SparcOperand(k_Register);
|
|
+ Op->Reg.RegNum = RegNum;
|
|
+ Op->Reg.Kind = Kind;
|
|
+ Op->StartLoc = S;
|
|
+ Op->EndLoc = E;
|
|
+ return Op;
|
|
+ }
|
|
+
|
|
+ static SparcOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
|
|
+ SparcOperand *Op = new SparcOperand(k_Immediate);
|
|
+ Op->Imm.Val = Val;
|
|
+ Op->StartLoc = S;
|
|
+ Op->EndLoc = E;
|
|
+ return Op;
|
|
+ }
|
|
+
|
|
+
|
|
+};
|
|
+
|
|
+} // end namespace
|
|
+
|
|
+bool SparcAsmParser::
|
|
+MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ MCStreamer &Out, unsigned &ErrorInfo,
|
|
+ bool MatchingInlineAsm) {
|
|
+ MCInst Inst;
|
|
+ SmallVector<MCInst, 8> Instructions;
|
|
+ unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
|
+ MatchingInlineAsm);
|
|
+ switch (MatchResult) {
|
|
+ default:
|
|
+ break;
|
|
+
|
|
+ case Match_Success: {
|
|
+ Inst.setLoc(IDLoc);
|
|
+ Out.EmitInstruction(Inst);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ case Match_MissingFeature:
|
|
+ return Error(IDLoc,
|
|
+ "instruction requires a CPU feature not currently enabled");
|
|
+
|
|
+ case Match_InvalidOperand: {
|
|
+ SMLoc ErrorLoc = IDLoc;
|
|
+ if (ErrorInfo != ~0U) {
|
|
+ if (ErrorInfo >= Operands.size())
|
|
+ return Error(IDLoc, "too few operands for instruction");
|
|
+
|
|
+ ErrorLoc = ((SparcOperand*) Operands[ErrorInfo])->getStartLoc();
|
|
+ if (ErrorLoc == SMLoc())
|
|
+ ErrorLoc = IDLoc;
|
|
+ }
|
|
+
|
|
+ return Error(ErrorLoc, "invalid operand for instruction");
|
|
+ }
|
|
+ case Match_MnemonicFail:
|
|
+ return Error(IDLoc, "invalid instruction");
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+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();
|
|
+ if (matchRegisterName(Tok, RegNo, false, false)) {
|
|
+ Parser.Lex();
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return Error(StartLoc, "invalid register name");
|
|
+}
|
|
+
|
|
+bool SparcAsmParser::
|
|
+ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
|
+ SMLoc NameLoc,
|
|
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands)
|
|
+{
|
|
+ // Check if we have valid mnemonic.
|
|
+ if (!mnemonicIsValid(Name, 0)) {
|
|
+ Parser.eatToEndOfStatement();
|
|
+ return Error(NameLoc, "Unknown instruction");
|
|
+ }
|
|
+ // First operand in MCInst is instruction mnemonic.
|
|
+ Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
|
|
+
|
|
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
|
+ // Read the first operand.
|
|
+ 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)
|
|
+{
|
|
+ // Ignore all directives for now.
|
|
+ Parser.eatToEndOfStatement();
|
|
+ return false;
|
|
+}
|
|
+
|
|
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
|
+parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ int ImmOffsetOrReg)
|
|
+{
|
|
+ // FIXME: Implement memory operand parsing here.
|
|
+ return MatchOperand_NoMatch;
|
|
+}
|
|
+
|
|
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
|
+parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
|
|
+{
|
|
+ return parseMEMOperand(Operands, 2);
|
|
+}
|
|
+
|
|
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
|
+parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
|
|
+{
|
|
+ return parseMEMOperand(Operands, 1);
|
|
+}
|
|
+
|
|
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
|
+parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
|
+ StringRef Mnemonic)
|
|
+{
|
|
+ OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
|
|
+ if (ResTy == MatchOperand_Success)
|
|
+ return ResTy;
|
|
+ // 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.
|
|
+ if (ResTy == MatchOperand_ParseFail)
|
|
+ return ResTy;
|
|
+
|
|
+ SMLoc S = Parser.getTok().getLoc();
|
|
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
|
+ const MCExpr *EVal;
|
|
+ SparcOperand *Op;
|
|
+ switch (getLexer().getKind()) {
|
|
+ case AsmToken::Percent:
|
|
+ Parser.Lex(); // Eat the '%'.
|
|
+ unsigned RegNo;
|
|
+ if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
|
|
+ Parser.Lex(); // Eat the identifier token.
|
|
+ Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
|
|
+ break;
|
|
+ }
|
|
+ // FIXME: Handle modifiers like %hi, %lo etc.,
|
|
+ return MatchOperand_ParseFail;
|
|
+
|
|
+ case AsmToken::Minus:
|
|
+ case AsmToken::Integer:
|
|
+ if (getParser().parseExpression(EVal))
|
|
+ return MatchOperand_ParseFail;
|
|
+
|
|
+ Op = SparcOperand::CreateImm(EVal, S, E);
|
|
+ break;
|
|
+
|
|
+ case AsmToken::Identifier: {
|
|
+ StringRef Identifier;
|
|
+ if (getParser().parseIdentifier(Identifier))
|
|
+ return MatchOperand_ParseFail;
|
|
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
|
+ MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
|
|
+
|
|
+ // Otherwise create a symbol reference.
|
|
+ const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
|
|
+ getContext());
|
|
+
|
|
+ Op = SparcOperand::CreateImm(Res, S, E);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case AsmToken::LBrac: // handle [
|
|
+ return parseMEMOperand(Operands, 0);
|
|
+
|
|
+ default:
|
|
+ return MatchOperand_ParseFail;
|
|
+ }
|
|
+ // Push the parsed operand into the list of operands
|
|
+ Operands.push_back(Op);
|
|
+ return MatchOperand_Success;
|
|
+}
|
|
+
|
|
+bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
|
|
+ unsigned &RegNo,
|
|
+ bool isDFP,
|
|
+ bool isQFP)
|
|
+{
|
|
+ int64_t intVal = 0;
|
|
+ RegNo = 0;
|
|
+ if (Tok.is(AsmToken::Identifier)) {
|
|
+ StringRef name = Tok.getString();
|
|
+
|
|
+ // %fp
|
|
+ if (name.equals("fp")) {
|
|
+ RegNo = Sparc::I6;
|
|
+ return true;
|
|
+ }
|
|
+ // %sp
|
|
+ if (name.equals("sp")) {
|
|
+ RegNo = Sparc::O6;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (name.equals("y")) {
|
|
+ RegNo = Sparc::Y;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (name.equals("icc")) {
|
|
+ RegNo = Sparc::ICC;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (name.equals("xcc")) {
|
|
+ // FIXME:: check 64bit.
|
|
+ RegNo = Sparc::ICC;
|
|
+ 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
|
|
+ RegNo = Sparc::FCC;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ // %g0 - %g7
|
|
+ if (name.substr(0, 1).equals_lower("g")
|
|
+ && !name.substr(1).getAsInteger(10, intVal)
|
|
+ && intVal < 8) {
|
|
+ RegNo = IntRegs[intVal];
|
|
+ return true;
|
|
+ }
|
|
+ // %o0 - %o7
|
|
+ if (name.substr(0, 1).equals_lower("o")
|
|
+ && !name.substr(1).getAsInteger(10, intVal)
|
|
+ && intVal < 8) {
|
|
+ RegNo = IntRegs[8 + intVal];
|
|
+ return true;
|
|
+ }
|
|
+ if (name.substr(0, 1).equals_lower("l")
|
|
+ && !name.substr(1).getAsInteger(10, intVal)
|
|
+ && intVal < 8) {
|
|
+ RegNo = IntRegs[16 + intVal];
|
|
+ return true;
|
|
+ }
|
|
+ if (name.substr(0, 1).equals_lower("i")
|
|
+ && !name.substr(1).getAsInteger(10, intVal)
|
|
+ && intVal < 8) {
|
|
+ RegNo = IntRegs[24 + intVal];
|
|
+ return true;
|
|
+ }
|
|
+ // %f0 - %f31
|
|
+ if (name.substr(0, 1).equals_lower("f")
|
|
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
|
|
+ if (isDFP && (intVal%2 == 0)) {
|
|
+ RegNo = DoubleRegs[intVal/2];
|
|
+ } else if (isQFP && (intVal%4 == 0)) {
|
|
+ RegNo = QuadFPRegs[intVal/4];
|
|
+ } else {
|
|
+ RegNo = FloatRegs[intVal];
|
|
+ }
|
|
+ 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)) {
|
|
+ if (isDFP) {
|
|
+ RegNo = DoubleRegs[16 + intVal/2];
|
|
+ } else if (isQFP && (intVal % 4 == 0)) {
|
|
+ RegNo = QuadFPRegs[8 + intVal/4];
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ // %r0 - %r31
|
|
+ if (name.substr(0, 1).equals_lower("r")
|
|
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
|
|
+ RegNo = IntRegs[intVal];
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+extern "C" void LLVMInitializeSparcAsmParser() {
|
|
+ RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
|
|
+ RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
|
|
+}
|
|
+
|
|
+#define GET_REGISTER_MATCHER
|
|
+#define GET_MATCHER_IMPLEMENTATION
|
|
+#include "SparcGenAsmMatcher.inc"
|
|
Index: lib/Target/Sparc/AsmParser/LLVMBuild.txt
|
|
===================================================================
|
|
--- lib/Target/Sparc/AsmParser/LLVMBuild.txt
|
|
+++ lib/Target/Sparc/AsmParser/LLVMBuild.txt
|
|
@@ -0,0 +1,23 @@
|
|
+;===- ./lib/Target/Sparc/AsmParser/LLVMBuild.txt ---------------*- Conf -*--===;
|
|
+;
|
|
+; The LLVM Compiler Infrastructure
|
|
+;
|
|
+; This file is distributed under the University of Illinois Open Source
|
|
+; License. See LICENSE.TXT for details.
|
|
+;
|
|
+;===------------------------------------------------------------------------===;
|
|
+;
|
|
+; This is an LLVMBuild description file for the components in this subdirectory.
|
|
+;
|
|
+; For more information on the LLVMBuild system, please see:
|
|
+;
|
|
+; http://llvm.org/docs/LLVMBuild.html
|
|
+;
|
|
+;===------------------------------------------------------------------------===;
|
|
+
|
|
+[component_0]
|
|
+type = Library
|
|
+name = SparcAsmParser
|
|
+parent = Sparc
|
|
+required_libraries = MC MCParser Support SparcDesc SparcInfo
|
|
+add_to_library_groups = Sparc
|
|
Index: lib/Target/Sparc/AsmParser/CMakeLists.txt
|
|
===================================================================
|
|
--- lib/Target/Sparc/AsmParser/CMakeLists.txt
|
|
+++ lib/Target/Sparc/AsmParser/CMakeLists.txt
|
|
@@ -0,0 +1,3 @@
|
|
+add_llvm_library(LLVMSparcAsmParser
|
|
+ SparcAsmParser.cpp
|
|
+ )
|
|
Index: lib/Target/Sparc/AsmParser/Makefile
|
|
===================================================================
|
|
--- lib/Target/Sparc/AsmParser/Makefile
|
|
+++ lib/Target/Sparc/AsmParser/Makefile
|
|
@@ -0,0 +1,15 @@
|
|
+##===- lib/Target/Sparc/AsmParser/Makefile ------------------*- Makefile-*-===##
|
|
+#
|
|
+# The LLVM Compiler Infrastructure
|
|
+#
|
|
+# This file is distributed under the University of Illinois Open Source
|
|
+# License. See LICENSE.TXT for details.
|
|
+#
|
|
+##===----------------------------------------------------------------------===##
|
|
+LEVEL = ../../../..
|
|
+LIBRARYNAME = LLVMSparcAsmParser
|
|
+
|
|
+# Hack: we need to include 'main' Sparc target directory to grab private headers
|
|
+CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
|
+
|
|
+include $(LEVEL)/Makefile.common
|
|
Index: lib/Target/Sparc/SparcInstr64Bit.td
|
|
===================================================================
|
|
--- lib/Target/Sparc/SparcInstr64Bit.td
|
|
+++ lib/Target/Sparc/SparcInstr64Bit.td
|
|
@@ -176,11 +176,11 @@ def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMP
|
|
def : Pat<(ctpop i64:$src), (POPCrr $src)>;
|
|
|
|
// "LEA" form of add
|
|
+let isCodeGenOnly = 1 in
|
|
def LEAX_ADDri : F3_2<2, 0b000000,
|
|
(outs I64Regs:$dst), (ins MEMri:$addr),
|
|
"add ${addr:arith}, $dst",
|
|
[(set iPTR:$dst, ADDRri:$addr)]>;
|
|
-
|
|
} // Predicates = [Is64Bit]
|
|
|
|
|