mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-23 17:32:49 +00:00
This patch that enables the Mips assembler to use symbols for offset for instructions
This patch uses the generated instruction info tables to identify memory/load store instructions. After successful matching and based on the operand type and size, it generates additional instructions to the output. Contributor: Vladimir Medic git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177685 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7697370adf
commit
25df6a93f3
@ -122,6 +122,9 @@ class MipsAsmParser : public MCTargetAsmParser {
|
|||||||
SmallVectorImpl<MCInst> &Instructions);
|
SmallVectorImpl<MCInst> &Instructions);
|
||||||
void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc,
|
void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc,
|
||||||
SmallVectorImpl<MCInst> &Instructions);
|
SmallVectorImpl<MCInst> &Instructions);
|
||||||
|
void expandMemInst(MCInst &Inst, SMLoc IDLoc,
|
||||||
|
SmallVectorImpl<MCInst> &Instructions,
|
||||||
|
bool isLoad,bool isImmOpnd);
|
||||||
bool reportParseError(StringRef ErrorMsg);
|
bool reportParseError(StringRef ErrorMsg);
|
||||||
|
|
||||||
bool parseMemOffset(const MCExpr *&Res);
|
bool parseMemOffset(const MCExpr *&Res);
|
||||||
@ -171,6 +174,9 @@ class MipsAsmParser : public MCTargetAsmParser {
|
|||||||
unsigned getReg(int RC,int RegNo);
|
unsigned getReg(int RC,int RegNo);
|
||||||
|
|
||||||
int getATReg();
|
int getATReg();
|
||||||
|
|
||||||
|
bool processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||||
|
SmallVectorImpl<MCInst> &Instructions);
|
||||||
public:
|
public:
|
||||||
MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser)
|
MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser)
|
||||||
: MCTargetAsmParser(), STI(sti), Parser(parser) {
|
: MCTargetAsmParser(), STI(sti), Parser(parser) {
|
||||||
@ -395,6 +401,56 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
extern const MCInstrDesc MipsInsts[];
|
||||||
|
}
|
||||||
|
static const MCInstrDesc &getInstDesc(unsigned Opcode) {
|
||||||
|
return MipsInsts[Opcode];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||||
|
SmallVectorImpl<MCInst> &Instructions) {
|
||||||
|
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
|
||||||
|
Inst.setLoc(IDLoc);
|
||||||
|
if (MCID.mayLoad() || MCID.mayStore()) {
|
||||||
|
// Check the offset of memory operand, if it is a symbol
|
||||||
|
// reference or immediate we may have to expand instructions
|
||||||
|
for (unsigned i=0;i<MCID.getNumOperands();i++) {
|
||||||
|
const MCOperandInfo &OpInfo = MCID.OpInfo[i];
|
||||||
|
if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) ||
|
||||||
|
(OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) {
|
||||||
|
MCOperand &Op = Inst.getOperand(i);
|
||||||
|
if (Op.isImm()) {
|
||||||
|
int MemOffset = Op.getImm();
|
||||||
|
if (MemOffset < -32768 || MemOffset > 32767) {
|
||||||
|
// Offset can't exceed 16bit value
|
||||||
|
expandMemInst(Inst,IDLoc,Instructions,MCID.mayLoad(),true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (Op.isExpr()) {
|
||||||
|
const MCExpr *Expr = Op.getExpr();
|
||||||
|
if (Expr->getKind() == MCExpr::SymbolRef){
|
||||||
|
const MCSymbolRefExpr *SR =
|
||||||
|
static_cast<const MCSymbolRefExpr*>(Expr);
|
||||||
|
if (SR->getKind() == MCSymbolRefExpr::VK_None) {
|
||||||
|
// Expand symbol
|
||||||
|
expandMemInst(Inst,IDLoc,Instructions,MCID.mayLoad(),false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsExpansion(Inst))
|
||||||
|
expandInstruction(Inst, IDLoc, Instructions);
|
||||||
|
else
|
||||||
|
Instructions.push_back(Inst);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MipsAsmParser::needsExpansion(MCInst &Inst) {
|
bool MipsAsmParser::needsExpansion(MCInst &Inst) {
|
||||||
|
|
||||||
switch(Inst.getOpcode()) {
|
switch(Inst.getOpcode()) {
|
||||||
@ -541,28 +597,103 @@ void MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc,
|
||||||
|
SmallVectorImpl<MCInst> &Instructions,
|
||||||
|
bool isLoad,bool isImmOpnd) {
|
||||||
|
const MCSymbolRefExpr *SR;
|
||||||
|
MCInst TempInst;
|
||||||
|
unsigned ImmOffset,HiOffset,LoOffset;
|
||||||
|
const MCExpr *ExprOffset;
|
||||||
|
unsigned TmpRegNum;
|
||||||
|
unsigned AtRegNum = getReg((isMips64()) ? Mips::CPU64RegsRegClassID:
|
||||||
|
Mips::CPURegsRegClassID,
|
||||||
|
getATReg());
|
||||||
|
// 1st operand is either source or dst register
|
||||||
|
assert(Inst.getOperand(0).isReg() && "expected register operand kind");
|
||||||
|
unsigned RegOpNum = Inst.getOperand(0).getReg();
|
||||||
|
// 2nd operand is base register
|
||||||
|
assert(Inst.getOperand(1).isReg() && "expected register operand kind");
|
||||||
|
unsigned BaseRegNum = Inst.getOperand(1).getReg();
|
||||||
|
// 3rd operand is either immediate or expression
|
||||||
|
if (isImmOpnd) {
|
||||||
|
assert(Inst.getOperand(2).isImm() && "expected immediate operand kind");
|
||||||
|
ImmOffset = Inst.getOperand(2).getImm();
|
||||||
|
LoOffset = ImmOffset & 0x0000ffff;
|
||||||
|
HiOffset = (ImmOffset & 0xffff0000) >> 16;
|
||||||
|
// If msb of LoOffset is 1(negative number) we must increment HiOffset
|
||||||
|
if (LoOffset & 0x8000)
|
||||||
|
HiOffset++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ExprOffset = Inst.getOperand(2).getExpr();
|
||||||
|
// All instructions will have the same location
|
||||||
|
TempInst.setLoc(IDLoc);
|
||||||
|
// 1st instruction in expansion is LUi. For load instruction we can use
|
||||||
|
// the dst register as a temporary if base and dst are different,
|
||||||
|
// but for stores we must use $at
|
||||||
|
TmpRegNum = (isLoad && (BaseRegNum != RegOpNum))?RegOpNum:AtRegNum;
|
||||||
|
TempInst.setOpcode(Mips::LUi);
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(TmpRegNum));
|
||||||
|
if (isImmOpnd)
|
||||||
|
TempInst.addOperand(MCOperand::CreateImm(HiOffset));
|
||||||
|
else {
|
||||||
|
if (ExprOffset->getKind() == MCExpr::SymbolRef) {
|
||||||
|
SR = static_cast<const MCSymbolRefExpr*>(ExprOffset);
|
||||||
|
const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::
|
||||||
|
Create(SR->getSymbol().getName(),
|
||||||
|
MCSymbolRefExpr::VK_Mips_ABS_HI,
|
||||||
|
getContext());
|
||||||
|
TempInst.addOperand(MCOperand::CreateExpr(HiExpr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the instruction to the list
|
||||||
|
Instructions.push_back(TempInst);
|
||||||
|
// and prepare TempInst for next instruction
|
||||||
|
TempInst.clear();
|
||||||
|
// which is add temp register to base
|
||||||
|
TempInst.setOpcode(Mips::ADDu);
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(TmpRegNum));
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(TmpRegNum));
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(BaseRegNum));
|
||||||
|
Instructions.push_back(TempInst);
|
||||||
|
TempInst.clear();
|
||||||
|
// and finaly, create original instruction with low part
|
||||||
|
// of offset and new base
|
||||||
|
TempInst.setOpcode(Inst.getOpcode());
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(RegOpNum));
|
||||||
|
TempInst.addOperand(MCOperand::CreateReg(TmpRegNum));
|
||||||
|
if (isImmOpnd)
|
||||||
|
TempInst.addOperand(MCOperand::CreateImm(LoOffset));
|
||||||
|
else {
|
||||||
|
if (ExprOffset->getKind() == MCExpr::SymbolRef) {
|
||||||
|
const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::
|
||||||
|
Create(SR->getSymbol().getName(),
|
||||||
|
MCSymbolRefExpr::VK_Mips_ABS_LO,
|
||||||
|
getContext());
|
||||||
|
TempInst.addOperand(MCOperand::CreateExpr(LoExpr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instructions.push_back(TempInst);
|
||||||
|
TempInst.clear();
|
||||||
|
}
|
||||||
|
|
||||||
bool MipsAsmParser::
|
bool MipsAsmParser::
|
||||||
MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||||
MCStreamer &Out, unsigned &ErrorInfo,
|
MCStreamer &Out, unsigned &ErrorInfo,
|
||||||
bool MatchingInlineAsm) {
|
bool MatchingInlineAsm) {
|
||||||
MCInst Inst;
|
MCInst Inst;
|
||||||
|
SmallVector<MCInst, 8> Instructions;
|
||||||
unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
||||||
MatchingInlineAsm);
|
MatchingInlineAsm);
|
||||||
|
|
||||||
switch (MatchResult) {
|
switch (MatchResult) {
|
||||||
default: break;
|
default: break;
|
||||||
case Match_Success: {
|
case Match_Success: {
|
||||||
if (needsExpansion(Inst)) {
|
if (processInstruction(Inst,IDLoc,Instructions))
|
||||||
SmallVector<MCInst, 4> Instructions;
|
return true;
|
||||||
expandInstruction(Inst, IDLoc, Instructions);
|
for(unsigned i =0; i < Instructions.size(); i++)
|
||||||
for(unsigned i =0; i < Instructions.size(); i++){
|
Out.EmitInstruction(Instructions[i]);
|
||||||
Out.EmitInstruction(Instructions[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Inst.setLoc(IDLoc);
|
|
||||||
Out.EmitInstruction(Inst);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case Match_MissingFeature:
|
case Match_MissingFeature:
|
||||||
@ -898,24 +1029,25 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) {
|
|||||||
|
|
||||||
// Check the type of the expression
|
// Check the type of the expression
|
||||||
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal)) {
|
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal)) {
|
||||||
// it's a constant, evaluate lo or hi value
|
// It's a constant, evaluate lo or hi value
|
||||||
int Val = MCE->getValue();
|
|
||||||
if (Str == "lo") {
|
if (Str == "lo") {
|
||||||
Val = Val & 0xffff;
|
short Val = MCE->getValue();
|
||||||
|
Res = MCConstantExpr::Create(Val, getContext());
|
||||||
} else if (Str == "hi") {
|
} else if (Str == "hi") {
|
||||||
|
int Val = MCE->getValue();
|
||||||
int LoSign = Val & 0x8000;
|
int LoSign = Val & 0x8000;
|
||||||
Val = (Val & 0xffff0000) >> 16;
|
Val = (Val & 0xffff0000) >> 16;
|
||||||
//lower part is treated as signed int, so if it is negative
|
// Lower part is treated as a signed int, so if it is negative
|
||||||
//we must add 1 to hi part to compensate
|
// we must add 1 to the hi part to compensate
|
||||||
if (LoSign)
|
if (LoSign)
|
||||||
Val++;
|
Val++;
|
||||||
|
Res = MCConstantExpr::Create(Val, getContext());
|
||||||
}
|
}
|
||||||
Res = MCConstantExpr::Create(Val, getContext());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(IdVal)) {
|
if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(IdVal)) {
|
||||||
// it's a symbol, create symbolic expression from symbol
|
// It's a symbol, create symbolic expression from symbol
|
||||||
StringRef Symbol = MSRE->getSymbol().getName();
|
StringRef Symbol = MSRE->getSymbol().getName();
|
||||||
MCSymbolRefExpr::VariantKind VK = getVariantKind(Str);
|
MCSymbolRefExpr::VariantKind VK = getVariantKind(Str);
|
||||||
Res = MCSymbolRefExpr::Create(Symbol,VK,getContext());
|
Res = MCSymbolRefExpr::Create(Symbol,VK,getContext());
|
||||||
@ -940,6 +1072,7 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res) {
|
|||||||
switch(getLexer().getKind()) {
|
switch(getLexer().getKind()) {
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
|
case AsmToken::Identifier:
|
||||||
case AsmToken::Integer:
|
case AsmToken::Integer:
|
||||||
case AsmToken::Minus:
|
case AsmToken::Minus:
|
||||||
case AsmToken::Plus:
|
case AsmToken::Plus:
|
||||||
|
@ -256,6 +256,7 @@ def mem : Operand<i32> {
|
|||||||
let MIOperandInfo = (ops CPURegs, simm16);
|
let MIOperandInfo = (ops CPURegs, simm16);
|
||||||
let EncoderMethod = "getMemEncoding";
|
let EncoderMethod = "getMemEncoding";
|
||||||
let ParserMatchClass = MipsMemAsmOperand;
|
let ParserMatchClass = MipsMemAsmOperand;
|
||||||
|
let OperandType = "OPERAND_MEMORY";
|
||||||
}
|
}
|
||||||
|
|
||||||
def mem64 : Operand<i64> {
|
def mem64 : Operand<i64> {
|
||||||
@ -263,18 +264,21 @@ def mem64 : Operand<i64> {
|
|||||||
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
||||||
let EncoderMethod = "getMemEncoding";
|
let EncoderMethod = "getMemEncoding";
|
||||||
let ParserMatchClass = MipsMemAsmOperand;
|
let ParserMatchClass = MipsMemAsmOperand;
|
||||||
|
let OperandType = "OPERAND_MEMORY";
|
||||||
}
|
}
|
||||||
|
|
||||||
def mem_ea : Operand<i32> {
|
def mem_ea : Operand<i32> {
|
||||||
let PrintMethod = "printMemOperandEA";
|
let PrintMethod = "printMemOperandEA";
|
||||||
let MIOperandInfo = (ops CPURegs, simm16);
|
let MIOperandInfo = (ops CPURegs, simm16);
|
||||||
let EncoderMethod = "getMemEncoding";
|
let EncoderMethod = "getMemEncoding";
|
||||||
|
let OperandType = "OPERAND_MEMORY";
|
||||||
}
|
}
|
||||||
|
|
||||||
def mem_ea_64 : Operand<i64> {
|
def mem_ea_64 : Operand<i64> {
|
||||||
let PrintMethod = "printMemOperandEA";
|
let PrintMethod = "printMemOperandEA";
|
||||||
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
||||||
let EncoderMethod = "getMemEncoding";
|
let EncoderMethod = "getMemEncoding";
|
||||||
|
let OperandType = "OPERAND_MEMORY";
|
||||||
}
|
}
|
||||||
|
|
||||||
// size operand of ext instruction
|
// size operand of ext instruction
|
||||||
|
@ -16,6 +16,22 @@
|
|||||||
# CHECK: lui $7, 1 # encoding: [0x01,0x00,0x07,0x3c]
|
# CHECK: lui $7, 1 # encoding: [0x01,0x00,0x07,0x3c]
|
||||||
# CHECK: ori $7, $7, 2 # encoding: [0x02,0x00,0xe7,0x34]
|
# CHECK: ori $7, $7, 2 # encoding: [0x02,0x00,0xe7,0x34]
|
||||||
# CHECK: addu $7, $7, $8 # encoding: [0x21,0x38,0xe8,0x00]
|
# CHECK: addu $7, $7, $8 # encoding: [0x21,0x38,0xe8,0x00]
|
||||||
|
# CHECK: lui $10, %hi(symbol) # encoding: [A,A,0x0a,0x3c]
|
||||||
|
# CHECK: # fixup A - offset: 0, value: symbol@ABS_HI, kind: fixup_Mips_HI16
|
||||||
|
# CHECK: addu $10, $10, $4 # encoding: [0x21,0x50,0x44,0x01]
|
||||||
|
# CHECK: lw $10, %lo(symbol)($10) # encoding: [A,A,0x4a,0x8d]
|
||||||
|
# CHECK: # fixup A - offset: 0, value: symbol@ABS_LO, kind: fixup_Mips_LO16
|
||||||
|
# CHECK: lui $1, %hi(symbol) # encoding: [A,A,0x01,0x3c]
|
||||||
|
# CHECK: # fixup A - offset: 0, value: symbol@ABS_HI, kind: fixup_Mips_HI16
|
||||||
|
# CHECK: addu $1, $1, $9 # encoding: [0x21,0x08,0x29,0x00]
|
||||||
|
# CHECK: sw $10, %lo(symbol)($1) # encoding: [A,A,0x2a,0xac]
|
||||||
|
# CHECK: # fixup A - offset: 0, value: symbol@ABS_LO, kind: fixup_Mips_LO16
|
||||||
|
# CHECK: lui $10, 10 # encoding: [0x0a,0x00,0x0a,0x3c]
|
||||||
|
# CHECK: addu $10, $10, $4 # encoding: [0x21,0x50,0x44,0x01]
|
||||||
|
# CHECK: lw $10, 123($10) # encoding: [0x7b,0x00,0x4a,0x8d]
|
||||||
|
# CHECK: lui $1, 2 # encoding: [0x02,0x00,0x01,0x3c]
|
||||||
|
# CHECK: addu $1, $1, $9 # encoding: [0x21,0x08,0x29,0x00]
|
||||||
|
# CHECK: sw $10, 57920($1) # encoding: [0x40,0xe2,0x2a,0xac]
|
||||||
|
|
||||||
li $5,123
|
li $5,123
|
||||||
li $6,-2345
|
li $6,-2345
|
||||||
@ -25,3 +41,9 @@
|
|||||||
la $7,65538
|
la $7,65538
|
||||||
la $a0, 20($a1)
|
la $a0, 20($a1)
|
||||||
la $7,65538($8)
|
la $7,65538($8)
|
||||||
|
|
||||||
|
lw $t2, symbol($a0)
|
||||||
|
sw $t2, symbol($t1)
|
||||||
|
|
||||||
|
lw $t2, 655483($a0)
|
||||||
|
sw $t2, 123456($t1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user