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
|
|
|
|
2015-10-02 06:08:20 +08:00
|
|
|
// Helper function for dealing with %lo / %hi in PIC mode.
|
|
|
|
const SparcMCExpr *adjustPICRelocation(SparcMCExpr::VariantKind VK,
|
|
|
|
const MCExpr *subExpr);
|
|
|
|
|
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
|
|
|
|
2015-06-10 20:11:26 +08:00
|
|
|
bool is64Bit() const {
|
2015-09-16 00:17:27 +08:00
|
|
|
return STI.getTargetTriple().getArch() == Triple::sparcv9;
|
2015-06-10 20:11:26 +08:00
|
|
|
}
|
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)
|
2015-07-28 05:56:53 +08:00
|
|
|
: MCTargetAsmParser(Options), STI(sti), Parser(parser) {
|
2014-01-04 19:30:13 +08:00
|
|
|
// 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
|
|
|
|
[Sparc] Implement i64 load/store support for 32-bit sparc.
The LDD/STD instructions can load/store a 64bit quantity from/to
memory to/from a consecutive even/odd pair of (32-bit) registers. They
are part of SparcV8, and also present in SparcV9. (Although deprecated
there, as you can store 64bits in one register).
As recommended on llvmdev in the thread "How to enable use of 64bit
load/store for 32bit architecture" from Apr 2015, I've modeled the
64-bit load/store operations as working on a v2i32 type, rather than
making i64 a legal type, but with few legal operations. The latter
does not (currently) work, as there is much code in llvm which assumes
that if i64 is legal, operations like "add" will actually work on it.
The same assumption does not hold for v2i32 -- for vector types, it is
workable to support only load/store, and expand everything else.
This patch:
- Adds a new register class, IntPair, for even/odd pairs of registers.
- Modifies the list of reserved registers, the stack spilling code,
and register copying code to support the IntPair register class.
- Adds support in AsmParser. (note that in asm text, you write the
name of the first register of the pair only. So the parser has to
morph the single register into the equivalent paired register).
- Adds the new instructions themselves (LDD/STD/LDDA/STDA).
- Hooks up the instructions and registers as a vector type v2i32. Adds
custom legalizer to transform i64 load/stores into v2i32 load/stores
and bitcasts, so that the new instructions can actually be
generated, and marks all operations other than load/store on v2i32
as needing to be expanded.
- Copies the unfortunate SelectInlineAsm hack from ARMISelDAGToDAG.
This hack undoes the transformation of i64 operands into two
arbitrarily-allocated separate i32 registers in
SelectionDAGBuilder. and instead passes them in a single
IntPair. (Arbitrarily allocated registers are not useful, asm code
expects to be receiving a pair, which can be passed to ldd/std.)
Also adds a bunch of test cases covering all the bugs I've added along
the way.
Differential Revision: http://reviews.llvm.org/D8713
llvm-svn: 244484
2015-08-11 03:11:39 +08:00
|
|
|
static unsigned IntPairRegs[] = {
|
|
|
|
Sparc::G0_G1, Sparc::G2_G3, Sparc::G4_G5, Sparc::G6_G7,
|
|
|
|
Sparc::O0_O1, Sparc::O2_O3, Sparc::O4_O5, Sparc::O6_O7,
|
|
|
|
Sparc::L0_L1, Sparc::L2_L3, Sparc::L4_L5, Sparc::L6_L7,
|
|
|
|
Sparc::I0_I1, Sparc::I2_I3, Sparc::I4_I5, Sparc::I6_I7};
|
|
|
|
|
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,
|
[Sparc] Implement i64 load/store support for 32-bit sparc.
The LDD/STD instructions can load/store a 64bit quantity from/to
memory to/from a consecutive even/odd pair of (32-bit) registers. They
are part of SparcV8, and also present in SparcV9. (Although deprecated
there, as you can store 64bits in one register).
As recommended on llvmdev in the thread "How to enable use of 64bit
load/store for 32bit architecture" from Apr 2015, I've modeled the
64-bit load/store operations as working on a v2i32 type, rather than
making i64 a legal type, but with few legal operations. The latter
does not (currently) work, as there is much code in llvm which assumes
that if i64 is legal, operations like "add" will actually work on it.
The same assumption does not hold for v2i32 -- for vector types, it is
workable to support only load/store, and expand everything else.
This patch:
- Adds a new register class, IntPair, for even/odd pairs of registers.
- Modifies the list of reserved registers, the stack spilling code,
and register copying code to support the IntPair register class.
- Adds support in AsmParser. (note that in asm text, you write the
name of the first register of the pair only. So the parser has to
morph the single register into the equivalent paired register).
- Adds the new instructions themselves (LDD/STD/LDDA/STDA).
- Hooks up the instructions and registers as a vector type v2i32. Adds
custom legalizer to transform i64 load/stores into v2i32 load/stores
and bitcasts, so that the new instructions can actually be
generated, and marks all operations other than load/store on v2i32
as needing to be expanded.
- Copies the unfortunate SelectInlineAsm hack from ARMISelDAGToDAG.
This hack undoes the transformation of i64 operands into two
arbitrarily-allocated separate i32 registers in
SelectionDAGBuilder. and instead passes them in a single
IntPair. (Arbitrarily allocated registers are not useful, asm code
expects to be receiving a pair, which can be passed to ldd/std.)
Also adds a bunch of test cases covering all the bugs I've added along
the way.
Differential Revision: http://reviews.llvm.org/D8713
llvm-svn: 244484
2015-08-11 03:11:39 +08:00
|
|
|
rk_IntPairReg,
|
2014-01-04 19:30:13 +08:00
|
|
|
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; }
|
|
|
|
|
[Sparc] Implement i64 load/store support for 32-bit sparc.
The LDD/STD instructions can load/store a 64bit quantity from/to
memory to/from a consecutive even/odd pair of (32-bit) registers. They
are part of SparcV8, and also present in SparcV9. (Although deprecated
there, as you can store 64bits in one register).
As recommended on llvmdev in the thread "How to enable use of 64bit
load/store for 32bit architecture" from Apr 2015, I've modeled the
64-bit load/store operations as working on a v2i32 type, rather than
making i64 a legal type, but with few legal operations. The latter
does not (currently) work, as there is much code in llvm which assumes
that if i64 is legal, operations like "add" will actually work on it.
The same assumption does not hold for v2i32 -- for vector types, it is
workable to support only load/store, and expand everything else.
This patch:
- Adds a new register class, IntPair, for even/odd pairs of registers.
- Modifies the list of reserved registers, the stack spilling code,
and register copying code to support the IntPair register class.
- Adds support in AsmParser. (note that in asm text, you write the
name of the first register of the pair only. So the parser has to
morph the single register into the equivalent paired register).
- Adds the new instructions themselves (LDD/STD/LDDA/STDA).
- Hooks up the instructions and registers as a vector type v2i32. Adds
custom legalizer to transform i64 load/stores into v2i32 load/stores
and bitcasts, so that the new instructions can actually be
generated, and marks all operations other than load/store on v2i32
as needing to be expanded.
- Copies the unfortunate SelectInlineAsm hack from ARMISelDAGToDAG.
This hack undoes the transformation of i64 operands into two
arbitrarily-allocated separate i32 registers in
SelectionDAGBuilder. and instead passes them in a single
IntPair. (Arbitrarily allocated registers are not useful, asm code
expects to be receiving a pair, which can be passed to ldd/std.)
Also adds a bunch of test cases covering all the bugs I've added along
the way.
Differential Revision: http://reviews.llvm.org/D8713
llvm-svn: 244484
2015-08-11 03:11:39 +08:00
|
|
|
bool isIntReg() const {
|
|
|
|
return (Kind == k_Register && Reg.Kind == rk_IntReg);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
[Sparc] Implement i64 load/store support for 32-bit sparc.
The LDD/STD instructions can load/store a 64bit quantity from/to
memory to/from a consecutive even/odd pair of (32-bit) registers. They
are part of SparcV8, and also present in SparcV9. (Although deprecated
there, as you can store 64bits in one register).
As recommended on llvmdev in the thread "How to enable use of 64bit
load/store for 32bit architecture" from Apr 2015, I've modeled the
64-bit load/store operations as working on a v2i32 type, rather than
making i64 a legal type, but with few legal operations. The latter
does not (currently) work, as there is much code in llvm which assumes
that if i64 is legal, operations like "add" will actually work on it.
The same assumption does not hold for v2i32 -- for vector types, it is
workable to support only load/store, and expand everything else.
This patch:
- Adds a new register class, IntPair, for even/odd pairs of registers.
- Modifies the list of reserved registers, the stack spilling code,
and register copying code to support the IntPair register class.
- Adds support in AsmParser. (note that in asm text, you write the
name of the first register of the pair only. So the parser has to
morph the single register into the equivalent paired register).
- Adds the new instructions themselves (LDD/STD/LDDA/STDA).
- Hooks up the instructions and registers as a vector type v2i32. Adds
custom legalizer to transform i64 load/stores into v2i32 load/stores
and bitcasts, so that the new instructions can actually be
generated, and marks all operations other than load/store on v2i32
as needing to be expanded.
- Copies the unfortunate SelectInlineAsm hack from ARMISelDAGToDAG.
This hack undoes the transformation of i64 operands into two
arbitrarily-allocated separate i32 registers in
SelectionDAGBuilder. and instead passes them in a single
IntPair. (Arbitrarily allocated registers are not useful, asm code
expects to be receiving a pair, which can be passed to ldd/std.)
Also adds a bunch of test cases covering all the bugs I've added along
the way.
Differential Revision: http://reviews.llvm.org/D8713
llvm-svn: 244484
2015-08-11 03:11:39 +08:00
|
|
|
static bool MorphToIntPairReg(SparcOperand &Op) {
|
|
|
|
unsigned Reg = Op.getReg();
|
|
|
|
assert(Op.Reg.Kind == rk_IntReg);
|
|
|
|
unsigned regIdx = 32;
|
|
|
|
if (Reg >= Sparc::G0 && Reg <= Sparc::G7)
|
|
|
|
regIdx = Reg - Sparc::G0;
|
|
|
|
else if (Reg >= Sparc::O0 && Reg <= Sparc::O7)
|
|
|
|
regIdx = Reg - Sparc::O0 + 8;
|
|
|
|
else if (Reg >= Sparc::L0 && Reg <= Sparc::L7)
|
|
|
|
regIdx = Reg - Sparc::L0 + 16;
|
|
|
|
else if (Reg >= Sparc::I0 && Reg <= Sparc::I7)
|
|
|
|
regIdx = Reg - Sparc::I0 + 24;
|
|
|
|
if (regIdx % 2 || regIdx > 31)
|
|
|
|
return false;
|
|
|
|
Op.Reg.RegNum = IntPairRegs[regIdx / 2];
|
|
|
|
Op.Reg.Kind = rk_IntPairReg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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();
|
2015-08-21 00:16:16 +08:00
|
|
|
int64_t RawImmValue = IsImm ? MCValOp.getImm() : 0;
|
|
|
|
|
|
|
|
// Allow either a signed or unsigned 32-bit immediate.
|
2015-08-21 09:12:19 +08:00
|
|
|
if (RawImmValue < -2147483648LL || RawImmValue > 4294967295LL) {
|
2015-08-21 00:16:16 +08:00
|
|
|
Error(IDLoc, "set: argument must be between -2147483648 and 4294967295");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the value was expressed as a large unsigned number, that's ok.
|
|
|
|
// We want to see if it "looks like" a small signed number.
|
|
|
|
int32_t ImmValue = RawImmValue;
|
|
|
|
// For 'set' you can't use 'or' with a negative operand on V9 because
|
|
|
|
// that would splat the sign bit across the upper half of the destination
|
|
|
|
// register, whereas 'set' is defined to zero the high 32 bits.
|
|
|
|
bool IsEffectivelyImm13 =
|
|
|
|
IsImm && ((is64Bit() ? 0 : -4096) <= ImmValue && ImmValue < 4096);
|
2015-05-19 00:43:33 +08:00
|
|
|
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);
|
|
|
|
|
2015-08-21 00:16:16 +08:00
|
|
|
// If not just a signed imm13 value, then either we use a 'sethi' with a
|
|
|
|
// following 'or', or a 'sethi' by itself if there are no more 1 bits.
|
|
|
|
// In either case, start with the 'sethi'.
|
|
|
|
if (!IsEffectivelyImm13) {
|
2015-05-19 00:43:33 +08:00
|
|
|
MCInst TmpInst;
|
2015-10-02 06:08:20 +08:00
|
|
|
const MCExpr *Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_HI, ValExpr);
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-21 00:16:16 +08:00
|
|
|
// The low bits require touching in 3 cases:
|
|
|
|
// * A non-immediate value will always require both instructions.
|
|
|
|
// * An effectively imm13 value needs only an 'or' instruction.
|
|
|
|
// * Otherwise, an immediate that is not effectively imm13 requires the
|
|
|
|
// 'or' only if bits remain after clearing the 22 bits that 'sethi' set.
|
|
|
|
// If the low bits are known zeros, there's nothing to do.
|
|
|
|
// In the second case, and only in that case, must we NOT clear
|
|
|
|
// bits of the immediate value via the %lo() assembler function.
|
|
|
|
// Note also, the 'or' instruction doesn't mind a large value in the case
|
|
|
|
// where the operand to 'set' was 0xFFFFFzzz - it does exactly what you mean.
|
|
|
|
if (!IsImm || IsEffectivelyImm13 || (ImmValue & 0x3ff)) {
|
2015-05-19 00:43:33 +08:00
|
|
|
MCInst TmpInst;
|
2015-08-21 00:16:16 +08:00
|
|
|
const MCExpr *Expr;
|
|
|
|
if (IsEffectivelyImm13)
|
|
|
|
Expr = ValExpr;
|
|
|
|
else
|
2015-10-02 06:08:20 +08:00
|
|
|
Expr = adjustPICRelocation(SparcMCExpr::VK_Sparc_LO, ValExpr);
|
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");
|
|
|
|
}
|
|
|
|
|
2015-06-30 20:32:53 +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;
|
2015-08-20 02:34:48 +08:00
|
|
|
case Sparc::FSR:
|
|
|
|
Op = SparcOperand::CreateToken("%fsr", S);
|
|
|
|
break;
|
2015-05-19 00:38:47 +08:00
|
|
|
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:
|
2015-08-18 03:55:01 +08:00
|
|
|
case AsmToken::Dot:
|
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;
|
2015-08-19 21:55:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// %fprs is an alias of %asr6.
|
|
|
|
if (name.equals("fprs")) {
|
|
|
|
RegNo = ASRRegs[6];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-20 02:34:48 +08:00
|
|
|
if (name.equals("fsr")) {
|
|
|
|
RegNo = Sparc::FSR;
|
|
|
|
RegKind = SparcOperand::rk_Special;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-19 00:38:47 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-06-18 23:05:15 +08:00
|
|
|
// Determine if an expression contains a reference to the symbol
|
|
|
|
// "_GLOBAL_OFFSET_TABLE_".
|
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
|
|
|
|
2015-10-02 06:08:20 +08:00
|
|
|
const SparcMCExpr *
|
|
|
|
SparcAsmParser::adjustPICRelocation(SparcMCExpr::VariantKind VK,
|
|
|
|
const MCExpr *subExpr)
|
|
|
|
{
|
|
|
|
// When in PIC mode, "%lo(...)" and "%hi(...)" behave differently.
|
|
|
|
// If the expression refers contains _GLOBAL_OFFSETE_TABLE, it is
|
|
|
|
// actually a %pc10 or %pc22 relocation. Otherwise, they are interpreted
|
|
|
|
// as %got10 or %got22 relocation.
|
|
|
|
|
|
|
|
if (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) {
|
|
|
|
switch(VK) {
|
|
|
|
default: break;
|
|
|
|
case SparcMCExpr::VK_Sparc_LO:
|
|
|
|
VK = (hasGOTReference(subExpr) ? SparcMCExpr::VK_Sparc_PC10
|
|
|
|
: SparcMCExpr::VK_Sparc_GOT10);
|
|
|
|
break;
|
|
|
|
case SparcMCExpr::VK_Sparc_HI:
|
|
|
|
VK = (hasGOTReference(subExpr) ? SparcMCExpr::VK_Sparc_PC22
|
|
|
|
: SparcMCExpr::VK_Sparc_GOT22);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SparcMCExpr::create(VK, subExpr, getContext());
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2015-10-02 06:08:20 +08:00
|
|
|
EVal = adjustPICRelocation(VK, subExpr);
|
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;
|
|
|
|
}
|
|
|
|
}
|
[Sparc] Implement i64 load/store support for 32-bit sparc.
The LDD/STD instructions can load/store a 64bit quantity from/to
memory to/from a consecutive even/odd pair of (32-bit) registers. They
are part of SparcV8, and also present in SparcV9. (Although deprecated
there, as you can store 64bits in one register).
As recommended on llvmdev in the thread "How to enable use of 64bit
load/store for 32bit architecture" from Apr 2015, I've modeled the
64-bit load/store operations as working on a v2i32 type, rather than
making i64 a legal type, but with few legal operations. The latter
does not (currently) work, as there is much code in llvm which assumes
that if i64 is legal, operations like "add" will actually work on it.
The same assumption does not hold for v2i32 -- for vector types, it is
workable to support only load/store, and expand everything else.
This patch:
- Adds a new register class, IntPair, for even/odd pairs of registers.
- Modifies the list of reserved registers, the stack spilling code,
and register copying code to support the IntPair register class.
- Adds support in AsmParser. (note that in asm text, you write the
name of the first register of the pair only. So the parser has to
morph the single register into the equivalent paired register).
- Adds the new instructions themselves (LDD/STD/LDDA/STDA).
- Hooks up the instructions and registers as a vector type v2i32. Adds
custom legalizer to transform i64 load/stores into v2i32 load/stores
and bitcasts, so that the new instructions can actually be
generated, and marks all operations other than load/store on v2i32
as needing to be expanded.
- Copies the unfortunate SelectInlineAsm hack from ARMISelDAGToDAG.
This hack undoes the transformation of i64 operands into two
arbitrarily-allocated separate i32 registers in
SelectionDAGBuilder. and instead passes them in a single
IntPair. (Arbitrarily allocated registers are not useful, asm code
expects to be receiving a pair, which can be passed to ldd/std.)
Also adds a bunch of test cases covering all the bugs I've added along
the way.
Differential Revision: http://reviews.llvm.org/D8713
llvm-svn: 244484
2015-08-11 03:11:39 +08:00
|
|
|
if (Op.isIntReg() && Kind == MCK_IntPair) {
|
|
|
|
if (SparcOperand::MorphToIntPairReg(Op))
|
|
|
|
return MCTargetAsmParser::Match_Success;
|
|
|
|
}
|
2014-01-12 12:48:54 +08:00
|
|
|
return Match_InvalidOperand;
|
|
|
|
}
|