mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-14 07:09:08 +00:00
[mips] Implement .ent, .end, .frame, .mask and .fmask assembler directives
Patch by Matheus Almeida and Toma Tabacu Differential Revision: http://reviews.llvm.org/D4179 llvm-svn: 215359
This commit is contained in:
parent
47a35d9c2a
commit
2d3d6ee5ce
@ -82,6 +82,10 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
MCSubtargetInfo &STI;
|
||||
MCAsmParser &Parser;
|
||||
MipsAssemblerOptions Options;
|
||||
MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a
|
||||
// nullptr, which indicates that no function is currently
|
||||
// selected. This usually happens after an '.end func'
|
||||
// directive.
|
||||
|
||||
#define GET_ASSEMBLER_HEADER
|
||||
#include "MipsGenAsmMatcher.inc"
|
||||
@ -285,6 +289,8 @@ public:
|
||||
|
||||
if (!isABI_O32() && !useOddSPReg() != 0)
|
||||
report_fatal_error("-mno-odd-spreg requires the O32 ABI");
|
||||
|
||||
CurrentFn = nullptr;
|
||||
}
|
||||
|
||||
MCAsmParser &getParser() const { return Parser; }
|
||||
@ -3055,22 +3061,151 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
parseDataDirective(8, DirectiveID.getLoc());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDVal == ".ent") {
|
||||
// Ignore this directive for now.
|
||||
Parser.Lex();
|
||||
StringRef SymbolName;
|
||||
|
||||
if (Parser.parseIdentifier(SymbolName)) {
|
||||
reportParseError("expected identifier after .ent");
|
||||
return false;
|
||||
}
|
||||
|
||||
// There's an undocumented extension that allows an integer to
|
||||
// follow the name of the procedure which AFAICS is ignored by GAS.
|
||||
// Example: .ent foo,2
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
if (getLexer().isNot(AsmToken::Comma)) {
|
||||
// Even though we accept this undocumented extension for compatibility
|
||||
// reasons, the additional integer argument does not actually change
|
||||
// the behaviour of the '.ent' directive, so we would like to discourage
|
||||
// its use. We do this by not referring to the extended version in
|
||||
// error messages which are not directly related to its use.
|
||||
reportParseError("unexpected token, expected end of statement");
|
||||
return false;
|
||||
}
|
||||
Parser.Lex(); // Eat the comma.
|
||||
const MCExpr *DummyNumber;
|
||||
int64_t DummyNumberVal;
|
||||
// If the user was explicitly trying to use the extended version,
|
||||
// we still give helpful extension-related error messages.
|
||||
if (Parser.parseExpression(DummyNumber)) {
|
||||
reportParseError("expected number after comma");
|
||||
return false;
|
||||
}
|
||||
if (!DummyNumber->EvaluateAsAbsolute(DummyNumberVal)) {
|
||||
reportParseError("expected an absolute expression after comma");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not the end of the statement, report an error.
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
reportParseError("unexpected token, expected end of statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
|
||||
|
||||
getTargetStreamer().emitDirectiveEnt(*Sym);
|
||||
CurrentFn = Sym;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDVal == ".end") {
|
||||
// Ignore this directive for now.
|
||||
Parser.Lex();
|
||||
StringRef SymbolName;
|
||||
|
||||
if (Parser.parseIdentifier(SymbolName)) {
|
||||
reportParseError("expected identifier after .end");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
reportParseError("unexpected token, expected end of statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CurrentFn == nullptr) {
|
||||
reportParseError(".end used without .ent");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((SymbolName != CurrentFn->getName())) {
|
||||
reportParseError(".end symbol does not match .ent symbol");
|
||||
return false;
|
||||
}
|
||||
|
||||
getTargetStreamer().emitDirectiveEnd(SymbolName);
|
||||
CurrentFn = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDVal == ".frame") {
|
||||
// Ignore this directive for now.
|
||||
Parser.eatToEndOfStatement();
|
||||
// .frame $stack_reg, frame_size_in_bytes, $return_reg
|
||||
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg;
|
||||
OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg);
|
||||
if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) {
|
||||
reportParseError("expected stack register");
|
||||
return false;
|
||||
}
|
||||
|
||||
MipsOperand &StackRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]);
|
||||
if (!StackRegOpnd.isGPRAsmReg()) {
|
||||
reportParseError(StackRegOpnd.getStartLoc(),
|
||||
"expected general purpose register");
|
||||
return false;
|
||||
}
|
||||
unsigned StackReg = StackRegOpnd.getGPR32Reg();
|
||||
|
||||
if (Parser.getTok().is(AsmToken::Comma))
|
||||
Parser.Lex();
|
||||
else {
|
||||
reportParseError("unexpected token, expected comma");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the frame size.
|
||||
const MCExpr *FrameSize;
|
||||
int64_t FrameSizeVal;
|
||||
|
||||
if (Parser.parseExpression(FrameSize)) {
|
||||
reportParseError("expected frame size value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FrameSize->EvaluateAsAbsolute(FrameSizeVal)) {
|
||||
reportParseError("frame size not an absolute expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Parser.getTok().is(AsmToken::Comma))
|
||||
Parser.Lex();
|
||||
else {
|
||||
reportParseError("unexpected token, expected comma");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the return register.
|
||||
TmpReg.clear();
|
||||
ResTy = ParseAnyRegister(TmpReg);
|
||||
if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) {
|
||||
reportParseError("expected return register");
|
||||
return false;
|
||||
}
|
||||
|
||||
MipsOperand &ReturnRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]);
|
||||
if (!ReturnRegOpnd.isGPRAsmReg()) {
|
||||
reportParseError(ReturnRegOpnd.getStartLoc(),
|
||||
"expected general purpose register");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is not the end of the statement, report an error.
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
reportParseError("unexpected token, expected end of statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
getTargetStreamer().emitFrame(StackReg, FrameSizeVal,
|
||||
ReturnRegOpnd.getGPR32Reg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3078,15 +3213,61 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
return parseDirectiveSet();
|
||||
}
|
||||
|
||||
if (IDVal == ".fmask") {
|
||||
// Ignore this directive for now.
|
||||
Parser.eatToEndOfStatement();
|
||||
return false;
|
||||
}
|
||||
if (IDVal == ".mask" || IDVal == ".fmask") {
|
||||
// .mask bitmask, frame_offset
|
||||
// bitmask: One bit for each register used.
|
||||
// frame_offset: Offset from Canonical Frame Address ($sp on entry) where
|
||||
// first register is expected to be saved.
|
||||
// Examples:
|
||||
// .mask 0x80000000, -4
|
||||
// .fmask 0x80000000, -4
|
||||
//
|
||||
|
||||
if (IDVal == ".mask") {
|
||||
// Ignore this directive for now.
|
||||
Parser.eatToEndOfStatement();
|
||||
// Parse the bitmask
|
||||
const MCExpr *BitMask;
|
||||
int64_t BitMaskVal;
|
||||
|
||||
if (Parser.parseExpression(BitMask)) {
|
||||
reportParseError("expected bitmask value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BitMask->EvaluateAsAbsolute(BitMaskVal)) {
|
||||
reportParseError("bitmask not an absolute expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Parser.getTok().is(AsmToken::Comma))
|
||||
Parser.Lex();
|
||||
else {
|
||||
reportParseError("unexpected token, expected comma");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the frame_offset
|
||||
const MCExpr *FrameOffset;
|
||||
int64_t FrameOffsetVal;
|
||||
|
||||
if (Parser.parseExpression(FrameOffset)) {
|
||||
reportParseError("expected frame offset value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FrameOffset->EvaluateAsAbsolute(FrameOffsetVal)) {
|
||||
reportParseError("frame offset not an absolute expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is not the end of the statement, report an error.
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
reportParseError("unexpected token, expected end of statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDVal == ".mask")
|
||||
getTargetStreamer().emitMask(BitMaskVal, FrameOffsetVal);
|
||||
else
|
||||
getTargetStreamer().emitFMask(BitMaskVal, FrameOffsetVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,9 @@
|
||||
using namespace llvm;
|
||||
|
||||
MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S)
|
||||
: MCTargetStreamer(S), canHaveModuleDirective(true) {}
|
||||
: MCTargetStreamer(S), canHaveModuleDirective(true) {
|
||||
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
|
||||
}
|
||||
void MipsTargetStreamer::emitDirectiveSetMicroMips() {}
|
||||
void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {}
|
||||
void MipsTargetStreamer::emitDirectiveSetMips16() {}
|
||||
@ -492,11 +494,45 @@ void MipsTargetELFStreamer::emitDirectiveSetNoAt() {
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) {
|
||||
// FIXME: implement.
|
||||
MCAssembler &MCA = getStreamer().getAssembler();
|
||||
MCContext &Context = MCA.getContext();
|
||||
MCStreamer &OS = getStreamer();
|
||||
|
||||
const MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS,
|
||||
ELF::SHF_ALLOC | ELF::SHT_REL,
|
||||
SectionKind::getMetadata());
|
||||
|
||||
const MCSymbolRefExpr *ExprRef =
|
||||
MCSymbolRefExpr::Create(Name, MCSymbolRefExpr::VK_None, Context);
|
||||
|
||||
MCSectionData &SecData = MCA.getOrCreateSectionData(*Sec);
|
||||
SecData.setAlignment(4);
|
||||
|
||||
OS.PushSection();
|
||||
|
||||
OS.SwitchSection(Sec);
|
||||
|
||||
OS.EmitValueImpl(ExprRef, 4);
|
||||
|
||||
OS.EmitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask
|
||||
OS.EmitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset
|
||||
|
||||
OS.EmitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask
|
||||
OS.EmitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset
|
||||
|
||||
OS.EmitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset
|
||||
OS.EmitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg
|
||||
OS.EmitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg
|
||||
|
||||
// The .end directive marks the end of a procedure. Invalidate
|
||||
// the information gathered up until this point.
|
||||
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
|
||||
|
||||
OS.PopSection();
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {
|
||||
// FIXME: implement.
|
||||
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitDirectiveAbiCalls() {
|
||||
@ -542,18 +578,28 @@ void MipsTargetELFStreamer::emitDirectiveOptionPic2() {
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize,
|
||||
unsigned ReturnReg) {
|
||||
// FIXME: implement.
|
||||
unsigned ReturnReg_) {
|
||||
MCContext &Context = getStreamer().getAssembler().getContext();
|
||||
const MCRegisterInfo *RegInfo = Context.getRegisterInfo();
|
||||
|
||||
FrameInfoSet = true;
|
||||
FrameReg = RegInfo->getEncodingValue(StackReg);
|
||||
FrameOffset = StackSize;
|
||||
ReturnReg = RegInfo->getEncodingValue(ReturnReg_);
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask,
|
||||
int CPUTopSavedRegOff) {
|
||||
// FIXME: implement.
|
||||
GPRInfoSet = true;
|
||||
GPRBitMask = CPUBitmask;
|
||||
GPROffset = CPUTopSavedRegOff;
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask,
|
||||
int FPUTopSavedRegOff) {
|
||||
// FIXME: implement.
|
||||
FPRInfoSet = true;
|
||||
FPRBitMask = FPUBitmask;
|
||||
FPROffset = FPUTopSavedRegOff;
|
||||
}
|
||||
|
||||
void MipsTargetELFStreamer::emitDirectiveSetMips1() {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define MIPSTARGETSTREAMER_H
|
||||
|
||||
#include "llvm/MC/MCELFStreamer.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "MCTargetDesc/MipsABIFlagsSection.h"
|
||||
|
||||
@ -97,6 +98,19 @@ public:
|
||||
protected:
|
||||
MipsABIFlagsSection ABIFlagsSection;
|
||||
|
||||
bool GPRInfoSet;
|
||||
unsigned GPRBitMask;
|
||||
int GPROffset;
|
||||
|
||||
bool FPRInfoSet;
|
||||
unsigned FPRBitMask;
|
||||
int FPROffset;
|
||||
|
||||
bool FrameInfoSet;
|
||||
int FrameOffset;
|
||||
unsigned FrameReg;
|
||||
unsigned ReturnReg;
|
||||
|
||||
private:
|
||||
bool canHaveModuleDirective;
|
||||
};
|
||||
|
42
test/MC/Mips/mips-pdr-bad.s
Normal file
42
test/MC/Mips/mips-pdr-bad.s
Normal file
@ -0,0 +1,42 @@
|
||||
# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r2 2>%t1
|
||||
# RUN: FileCheck %s < %t1 -check-prefix=ASM
|
||||
|
||||
.text
|
||||
|
||||
.ent # ASM: :[[@LINE]]:14: error: expected identifier after .ent
|
||||
.ent bar, # ASM: :[[@LINE]]:19: error: expected number after comma
|
||||
.ent foo, bar # AMS: :[[@LINE]]:23: error: expected an absolute expression after comma
|
||||
.ent foo, 5, bar # AMS: :[[@LINE]]:20: error: unexpected token, expected end of statement
|
||||
|
||||
.frame # ASM: :[[@LINE]]:16: error: expected stack register
|
||||
.frame bar # ASM: :[[@LINE]]:16: error: expected stack register
|
||||
.frame $f1, 8, # ASM: :[[@LINE]]:16: error: expected general purpose register
|
||||
.frame $sp # ASM: :[[@LINE]]:20: error: unexpected token, expected comma
|
||||
.frame $sp, # ASM: :[[@LINE]]:21: error: expected frame size value
|
||||
.frame $sp, bar # ASM: :[[@LINE]]:25: error: frame size not an absolute expression
|
||||
.frame $sp, 8 # ASM: :[[@LINE]]:23: error: unexpected token, expected comma
|
||||
.frame $sp, 8, # ASM: :[[@LINE]]:24: error: expected return register
|
||||
.frame $sp, 8, $f1 # ASM: :[[@LINE]]:24: error: expected general purpose register
|
||||
.frame $sp, 8, $ra, foo # ASM: :[[@LINE]]:27: error: unexpected token, expected end of statement
|
||||
|
||||
.mask # ASM: :[[@LINE]]:16: error: expected bitmask value
|
||||
.mask foo # ASM: :[[@LINE]]:19: error: bitmask not an absolute expression
|
||||
.mask 0x80000000 # ASM: :[[@LINE]]:26: error: unexpected token, expected comma
|
||||
.mask 0x80000000, # ASM: :[[@LINE]]:27: error: expected frame offset value
|
||||
.mask 0x80000000, foo # ASM: :[[@LINE]]:31: error: frame offset not an absolute expression
|
||||
.mask 0x80000000, -4, bar # ASM: :[[@LINE]]:29: error: unexpected token, expected end of statement
|
||||
|
||||
.fmask # ASM: :[[@LINE]]:17: error: expected bitmask value
|
||||
.fmask foo # ASM: :[[@LINE]]:20: error: bitmask not an absolute expression
|
||||
.fmask 0x80000000 # ASM: :[[@LINE]]:27: error: unexpected token, expected comma
|
||||
.fmask 0x80000000, # ASM: :[[@LINE]]:28: error: expected frame offset value
|
||||
.fmask 0x80000000, foo # ASM: :[[@LINE]]:32: error: frame offset not an absolute expression
|
||||
.fmask 0x80000000, -4, bar # ASM: :[[@LINE]]:30: error: unexpected token, expected end of statement
|
||||
|
||||
.end # ASM: :[[@LINE]]:14: error: expected identifier after .end
|
||||
.ent _local_foo_bar
|
||||
.end _local_foo_bar, foo # ASM: :[[@LINE]]:28: error: unexpected token, expected end of statement
|
||||
.end _local_foo_bar
|
||||
.end _local_foo # ASM: :[[@LINE]]:25: error: .end used without .ent
|
||||
.ent _local_foo, 2
|
||||
.end _local_foo_bar # ASM: :[[@LINE]]:29: error: .end symbol does not match .ent symbol
|
64
test/MC/Mips/mips-pdr.s
Normal file
64
test/MC/Mips/mips-pdr.s
Normal file
@ -0,0 +1,64 @@
|
||||
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=asm | \
|
||||
# RUN: FileCheck %s -check-prefix=ASMOUT
|
||||
|
||||
# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=obj -o - | \
|
||||
# RUN: llvm-readobj -s -section-data | \
|
||||
# RUN: FileCheck %s -check-prefix=OBJOUT
|
||||
|
||||
# ASMOUT: .text
|
||||
# ASMOUT: .type _local_foo,@function
|
||||
# ASMOUT: .ent _local_foo
|
||||
# ASMOUT:_local_foo:
|
||||
# ASMOUT: .frame $fp,16,$ra
|
||||
# ASMOUT: .mask 0x10101010,-4
|
||||
# ASMOUT: .fmask 0x01010101,-8
|
||||
# ASMOUT: .end _local_foo
|
||||
# ASMOUT: .size local_foo,
|
||||
|
||||
# OBJOUT: Section {
|
||||
# OBJOUT: Name: .pdr
|
||||
# OBJOUT: Type: SHT_PROGBITS (0x1)
|
||||
# OBJOUT: Flags [ (0xB)
|
||||
# OBJOUT: SHF_ALLOC (0x2)
|
||||
# OBJOUT: SHF_WRITE (0x1)
|
||||
# OBJOUT: ]
|
||||
# OBJOUT: Size: 64
|
||||
# OBJOUT: SectionData (
|
||||
# OBJOUT: 0000: 00000000 10101010 FFFFFFFC 01010101
|
||||
# OBJOUT: 0010: FFFFFFF8 00000010 0000001E 0000001F
|
||||
# OBJOUT: 0020: 00000000 10101010 FFFFFFFC 01010101
|
||||
# OBJOUT: 0030: FFFFFFF8 00000010 0000001E 0000001F
|
||||
# OBJOUT: )
|
||||
# OBJOUT: }
|
||||
|
||||
# We should also check if relocation information was correctly generated.
|
||||
# OBJOUT: Section {
|
||||
# OBJOUT: Name: .rel.pdr
|
||||
# OBJOUT: Type: SHT_REL (0x9)
|
||||
# OBJOUT: Flags [ (0x0)
|
||||
# OBJOUT: ]
|
||||
# OBJOUT: Size: 16
|
||||
# OBJOUT: SectionData (
|
||||
# OBJOUT: 0000: 00000000 00000202 00000020 00000802
|
||||
# OBJOUT: )
|
||||
# OBJOUT: }
|
||||
|
||||
.text
|
||||
.type _local_foo,@function
|
||||
.ent _local_foo
|
||||
_local_foo:
|
||||
.frame $fp,16,$ra
|
||||
.mask 0x10101010,-4
|
||||
.fmask 0x01010101,-8
|
||||
.end _local_foo
|
||||
.size local_foo,.-_local_foo
|
||||
|
||||
.globl _global_foo
|
||||
.type _global_foo,@function
|
||||
.ent _global_foo
|
||||
_global_foo:
|
||||
.frame $fp,16,$ra
|
||||
.mask 0x10101010,-4
|
||||
.fmask 0x01010101,-8
|
||||
.end _global_foo
|
||||
.size global_foo,.-_global_foo
|
Loading…
Reference in New Issue
Block a user