mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-15 07:34:33 +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);
|
||||
void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc,
|
||||
SmallVectorImpl<MCInst> &Instructions);
|
||||
void expandMemInst(MCInst &Inst, SMLoc IDLoc,
|
||||
SmallVectorImpl<MCInst> &Instructions,
|
||||
bool isLoad,bool isImmOpnd);
|
||||
bool reportParseError(StringRef ErrorMsg);
|
||||
|
||||
bool parseMemOffset(const MCExpr *&Res);
|
||||
@ -171,6 +174,9 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
unsigned getReg(int RC,int RegNo);
|
||||
|
||||
int getATReg();
|
||||
|
||||
bool processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
SmallVectorImpl<MCInst> &Instructions);
|
||||
public:
|
||||
MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &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) {
|
||||
|
||||
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::
|
||||
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: {
|
||||
if (needsExpansion(Inst)) {
|
||||
SmallVector<MCInst, 4> Instructions;
|
||||
expandInstruction(Inst, IDLoc, Instructions);
|
||||
for(unsigned i =0; i < Instructions.size(); i++){
|
||||
Out.EmitInstruction(Instructions[i]);
|
||||
}
|
||||
} else {
|
||||
Inst.setLoc(IDLoc);
|
||||
Out.EmitInstruction(Inst);
|
||||
}
|
||||
if (processInstruction(Inst,IDLoc,Instructions))
|
||||
return true;
|
||||
for(unsigned i =0; i < Instructions.size(); i++)
|
||||
Out.EmitInstruction(Instructions[i]);
|
||||
return false;
|
||||
}
|
||||
case Match_MissingFeature:
|
||||
@ -898,24 +1029,25 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) {
|
||||
|
||||
// Check the type of the expression
|
||||
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal)) {
|
||||
// it's a constant, evaluate lo or hi value
|
||||
int Val = MCE->getValue();
|
||||
// It's a constant, evaluate lo or hi value
|
||||
if (Str == "lo") {
|
||||
Val = Val & 0xffff;
|
||||
short Val = MCE->getValue();
|
||||
Res = MCConstantExpr::Create(Val, getContext());
|
||||
} else if (Str == "hi") {
|
||||
int Val = MCE->getValue();
|
||||
int LoSign = Val & 0x8000;
|
||||
Val = (Val & 0xffff0000) >> 16;
|
||||
//lower part is treated as signed int, so if it is negative
|
||||
//we must add 1 to hi part to compensate
|
||||
// Lower part is treated as a signed int, so if it is negative
|
||||
// we must add 1 to the hi part to compensate
|
||||
if (LoSign)
|
||||
Val++;
|
||||
Res = MCConstantExpr::Create(Val, getContext());
|
||||
}
|
||||
Res = MCConstantExpr::Create(Val, getContext());
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
MCSymbolRefExpr::VariantKind VK = getVariantKind(Str);
|
||||
Res = MCSymbolRefExpr::Create(Symbol,VK,getContext());
|
||||
@ -940,6 +1072,7 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res) {
|
||||
switch(getLexer().getKind()) {
|
||||
default:
|
||||
return true;
|
||||
case AsmToken::Identifier:
|
||||
case AsmToken::Integer:
|
||||
case AsmToken::Minus:
|
||||
case AsmToken::Plus:
|
||||
|
@ -256,6 +256,7 @@ def mem : Operand<i32> {
|
||||
let MIOperandInfo = (ops CPURegs, simm16);
|
||||
let EncoderMethod = "getMemEncoding";
|
||||
let ParserMatchClass = MipsMemAsmOperand;
|
||||
let OperandType = "OPERAND_MEMORY";
|
||||
}
|
||||
|
||||
def mem64 : Operand<i64> {
|
||||
@ -263,18 +264,21 @@ def mem64 : Operand<i64> {
|
||||
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
||||
let EncoderMethod = "getMemEncoding";
|
||||
let ParserMatchClass = MipsMemAsmOperand;
|
||||
let OperandType = "OPERAND_MEMORY";
|
||||
}
|
||||
|
||||
def mem_ea : Operand<i32> {
|
||||
let PrintMethod = "printMemOperandEA";
|
||||
let MIOperandInfo = (ops CPURegs, simm16);
|
||||
let EncoderMethod = "getMemEncoding";
|
||||
let OperandType = "OPERAND_MEMORY";
|
||||
}
|
||||
|
||||
def mem_ea_64 : Operand<i64> {
|
||||
let PrintMethod = "printMemOperandEA";
|
||||
let MIOperandInfo = (ops CPU64Regs, simm16_64);
|
||||
let EncoderMethod = "getMemEncoding";
|
||||
let OperandType = "OPERAND_MEMORY";
|
||||
}
|
||||
|
||||
// size operand of ext instruction
|
||||
|
@ -16,6 +16,22 @@
|
||||
# CHECK: lui $7, 1 # encoding: [0x01,0x00,0x07,0x3c]
|
||||
# CHECK: ori $7, $7, 2 # encoding: [0x02,0x00,0xe7,0x34]
|
||||
# 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 $6,-2345
|
||||
@ -25,3 +41,9 @@
|
||||
la $7,65538
|
||||
la $a0, 20($a1)
|
||||
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