[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:
Daniel Sanders 2014-08-11 15:28:56 +00:00
parent 47a35d9c2a
commit 2d3d6ee5ce
5 changed files with 369 additions and 22 deletions

View File

@ -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;
}

View File

@ -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() {

View File

@ -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;
};

View 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
View 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