mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-18 11:20:03 +00:00
[mips] Add support for .cpsetup
Summary: Patch by Robert N. M. Watson His work was sponsored by: DARPA, AFRL Small corrections by myself. CC: theraven, matheusalmeida Differential Revision: http://llvm-reviews.chandlerc.com/D3199 llvm-svn: 204924
This commit is contained in:
parent
ffa70ad28b
commit
e4c63b7b68
@ -196,6 +196,7 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
|
||||
bool isEvaluated(const MCExpr *Expr);
|
||||
bool parseSetFeature(uint64_t Feature);
|
||||
bool parseDirectiveCPSetup();
|
||||
bool parseDirectiveSet();
|
||||
bool parseDirectiveOption();
|
||||
|
||||
@ -229,6 +230,10 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
return STI.getFeatureBits() & Mips::FeatureMicroMips;
|
||||
}
|
||||
|
||||
bool parseRegister(unsigned &RegNum);
|
||||
|
||||
bool eatComma(StringRef ErrorStr);
|
||||
|
||||
int matchRegisterName(StringRef Symbol, bool is64BitReg);
|
||||
|
||||
int matchCPURegisterName(StringRef Symbol);
|
||||
@ -249,6 +254,8 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
|
||||
unsigned getReg(int RC, int RegNo);
|
||||
|
||||
unsigned getGPR(int RegNo);
|
||||
|
||||
int getATReg();
|
||||
|
||||
// Warn if RegNo is the current assembler temporary.
|
||||
@ -1202,6 +1209,12 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) {
|
||||
return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo);
|
||||
}
|
||||
|
||||
unsigned MipsAsmParser::getGPR(int RegNo) {
|
||||
return getReg((isMips64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID,
|
||||
RegNo);
|
||||
}
|
||||
|
||||
|
||||
int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) {
|
||||
if (RegNum >
|
||||
getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs())
|
||||
@ -2501,6 +2514,123 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::parseRegister(unsigned &RegNum) {
|
||||
if (!getLexer().is(AsmToken::Dollar))
|
||||
return false;
|
||||
|
||||
Parser.Lex();
|
||||
|
||||
const AsmToken &Reg = Parser.getTok();
|
||||
if (Reg.is(AsmToken::Identifier)) {
|
||||
RegNum = matchCPURegisterName(Reg.getIdentifier());
|
||||
} else if (Reg.is(AsmToken::Integer)) {
|
||||
RegNum = Reg.getIntVal();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
Parser.Lex();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::eatComma(StringRef ErrorStr) {
|
||||
if (getLexer().isNot(AsmToken::Comma)) {
|
||||
SMLoc Loc = getLexer().getLoc();
|
||||
Parser.eatToEndOfStatement();
|
||||
return Error(Loc, ErrorStr);
|
||||
}
|
||||
|
||||
Parser.Lex(); // Eat the comma.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::parseDirectiveCPSetup() {
|
||||
unsigned FuncReg;
|
||||
unsigned Save;
|
||||
bool SaveIsReg = true;
|
||||
|
||||
if (!parseRegister(FuncReg))
|
||||
return reportParseError("expected register containing function address");
|
||||
FuncReg = getGPR(FuncReg);
|
||||
|
||||
if (!eatComma("expected comma parsing directive"))
|
||||
return true;
|
||||
|
||||
if (!parseRegister(Save)) {
|
||||
const AsmToken &Tok = Parser.getTok();
|
||||
if (Tok.is(AsmToken::Integer)) {
|
||||
Save = Tok.getIntVal();
|
||||
SaveIsReg = false;
|
||||
Parser.Lex();
|
||||
} else
|
||||
return reportParseError("expected save register or stack offset");
|
||||
} else
|
||||
Save = getGPR(Save);
|
||||
|
||||
if (!eatComma("expected comma parsing directive"))
|
||||
return true;
|
||||
|
||||
StringRef Name;
|
||||
if (Parser.parseIdentifier(Name))
|
||||
reportParseError("expected identifier");
|
||||
MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
|
||||
unsigned GPReg = getGPR(matchCPURegisterName("gp"));
|
||||
|
||||
// FIXME: The code below this point should be in the TargetStreamers.
|
||||
// Only N32 and N64 emit anything for .cpsetup
|
||||
// FIXME: We should only emit something for PIC mode too.
|
||||
if (!isN32() && !isN64())
|
||||
return false;
|
||||
|
||||
MCStreamer &TS = getStreamer();
|
||||
MCInst Inst;
|
||||
// Either store the old $gp in a register or on the stack
|
||||
if (SaveIsReg) {
|
||||
// move $save, $gpreg
|
||||
Inst.setOpcode(Mips::DADDu);
|
||||
Inst.addOperand(MCOperand::CreateReg(Save));
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateReg(getGPR(0)));
|
||||
} else {
|
||||
// sd $gpreg, offset($sp)
|
||||
Inst.setOpcode(Mips::SD);
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateReg(getGPR(matchCPURegisterName("sp"))));
|
||||
Inst.addOperand(MCOperand::CreateImm(Save));
|
||||
}
|
||||
TS.EmitInstruction(Inst, STI);
|
||||
Inst.clear();
|
||||
|
||||
const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create(
|
||||
Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI,
|
||||
getContext());
|
||||
const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create(
|
||||
Sym->getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO,
|
||||
getContext());
|
||||
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
|
||||
Inst.setOpcode(Mips::LUi);
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateExpr(HiExpr));
|
||||
TS.EmitInstruction(Inst, STI);
|
||||
Inst.clear();
|
||||
|
||||
// addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym)))
|
||||
Inst.setOpcode(Mips::ADDiu);
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateExpr(LoExpr));
|
||||
TS.EmitInstruction(Inst, STI);
|
||||
Inst.clear();
|
||||
|
||||
// daddu $gp, $gp, $funcreg
|
||||
Inst.setOpcode(Mips::DADDu);
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateReg(GPReg));
|
||||
Inst.addOperand(MCOperand::CreateReg(FuncReg));
|
||||
TS.EmitInstruction(Inst, STI);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsAsmParser::parseDirectiveSet() {
|
||||
|
||||
// Get the next token.
|
||||
@ -2692,6 +2822,9 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDVal == ".cpsetup")
|
||||
return parseDirectiveCPSetup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
36
test/MC/Mips/cpsetup.s
Normal file
36
test/MC/Mips/cpsetup.s
Normal file
@ -0,0 +1,36 @@
|
||||
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+o32 %s | \
|
||||
# RUN: FileCheck -check-prefix=ANY -check-prefix=O32 %s
|
||||
# RUN: llvm-mc -triple mips64-unknown-unknown -mattr=-n64,+n32 %s | \
|
||||
# RUN: FileCheck -check-prefix=ANY -check-prefix=NXX -check-prefix=N32 %s
|
||||
# RUN: llvm-mc -triple mips64-unknown-unknown %s | \
|
||||
# RUN: FileCheck -check-prefix=ANY -check-prefix=NXX -check-prefix=N64 %s
|
||||
|
||||
# TODO: !PIC -> no output
|
||||
|
||||
.text
|
||||
.option pic2
|
||||
t1:
|
||||
.cpsetup $25, 8, __cerror
|
||||
|
||||
# ANY-LABEL: t1:
|
||||
|
||||
# O32-NOT: __cerror
|
||||
|
||||
# NXX: sd $gp, 8($sp)
|
||||
# NXX: lui $gp, %hi(%neg(%gp_rel(__cerror)))
|
||||
# NXX: addiu $gp, $gp, %lo(%neg(%gp_rel(__cerror)))
|
||||
# N32: addu $gp, $gp, $25
|
||||
# N64: daddu $gp, $gp, $25
|
||||
|
||||
t2:
|
||||
# ANY-LABEL: t2:
|
||||
|
||||
.cpsetup $25, $2, __cerror
|
||||
|
||||
# O32-NOT: __cerror
|
||||
|
||||
# NXX: move $2, $gp
|
||||
# NXX: lui $gp, %hi(%neg(%gp_rel(__cerror)))
|
||||
# NXX: addiu $gp, $gp, %lo(%neg(%gp_rel(__cerror)))
|
||||
# N32: addu $gp, $gp, $25
|
||||
# N64: daddu $gp, $gp, $25
|
Loading…
x
Reference in New Issue
Block a user