diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index cae3999c12b..8bbfcd9c32a 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -196,6 +196,7 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseDirectiveSet(); bool parseDirectiveMipsHackStocg(); bool parseDirectiveMipsHackELFFlags(); + bool parseDirectiveOption(); bool parseSetAtDirective(); bool parseSetNoAtDirective(); @@ -2468,6 +2469,35 @@ bool MipsAsmParser::parseDirectiveGpWord() { return false; } +bool MipsAsmParser::parseDirectiveOption() { + // Get the option token. + AsmToken Tok = Parser.getTok(); + // At the moment only identifiers are supported. + if (Tok.isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "unexpected token in .option directive"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Option = Tok.getIdentifier(); + + if (Option == "pic0") { + getTargetStreamer().emitDirectiveOptionPic0(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token in .option pic0 directive"); + Parser.eatToEndOfStatement(); + } + return false; + } + + // Unknown option. + Warning(Parser.getTok().getLoc(), "unknown option in .option directive"); + Parser.eatToEndOfStatement(); + return false; +} + bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); @@ -2523,6 +2553,19 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".mips_hack_elf_flags") return parseDirectiveMipsHackELFFlags(); + if (IDVal == ".option") + return parseDirectiveOption(); + + if (IDVal == ".abicalls") { + getTargetStreamer().emitDirectiveAbiCalls(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + // Clear line + Parser.eatToEndOfStatement(); + } + return false; + } + return true; } diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index 5548aaa9a6d..add6e4b751b 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -16,7 +16,6 @@ #include "MipsMCAsmInfo.h" #include "MipsTargetStreamer.h" #include "llvm/MC/MCCodeGenInfo.h" -#include "llvm/MC/MCELF.h" #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" diff --git a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index 5e90bbc635a..6fe39640d87 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -17,13 +17,14 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/ELF.h" using namespace llvm; static cl::opt PrintHackDirectives("print-hack-directives", cl::init(false), cl::Hidden); -// pin vtable to this file +// Pin vtable to this file. void MipsTargetStreamer::anchor() {} MipsTargetAsmStreamer::MipsTargetAsmStreamer(formatted_raw_ostream &OS) @@ -47,6 +48,13 @@ void MipsTargetAsmStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { OS << Val; OS << '\n'; } +void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; } +void MipsTargetAsmStreamer::emitDirectiveOptionPic0() { + OS << "\t.option\tpic0\n"; +} + +// This part is for ELF object output. +MipsTargetELFStreamer::MipsTargetELFStreamer() {} MCELFStreamer &MipsTargetELFStreamer::getStreamer() { return static_cast(*Streamer); @@ -57,7 +65,7 @@ void MipsTargetELFStreamer::emitMipsHackELFFlags(unsigned Flags) { MCA.setELFHeaderEFlags(Flags); } -// Set a symbol's STO flags +// Set a symbol's STO flags. void MipsTargetELFStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Sym); // The "other" values are stored in the last 6 bits of the second byte @@ -65,3 +73,15 @@ void MipsTargetELFStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { // the shift to pack it. MCELF::setOther(Data, Val >> 2); } +void MipsTargetELFStreamer::emitDirectiveAbiCalls() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags |= ELF::EF_MIPS_CPIC; + MCA.setELFHeaderEFlags(Flags); +} +void MipsTargetELFStreamer::emitDirectiveOptionPic0() { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_MIPS_PIC; + MCA.setELFHeaderEFlags(Flags); +} diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 284e51c5978..d01aed49f9e 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -608,12 +608,10 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { // TODO: Need to add -mabicalls and -mno-abicalls flags. // Currently we assume that -mabicalls is the default. - if (OutStreamer.hasRawTextSupport()) { - OutStreamer.EmitRawText(StringRef("\t.abicalls")); - Reloc::Model RM = Subtarget->getRelocationModel(); - if (RM == Reloc::Static && !Subtarget->hasMips64()) - OutStreamer.EmitRawText(StringRef("\t.option\tpic0")); - } + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = Subtarget->getRelocationModel(); + if (RM == Reloc::Static && !Subtarget->hasMips64()) + getTargetStreamer().emitDirectiveOptionPic0(); // Tell the assembler which ABI we are using if (OutStreamer.hasRawTextSupport()) diff --git a/lib/Target/Mips/MipsTargetStreamer.h b/lib/Target/Mips/MipsTargetStreamer.h index 96966fd7cbc..8c53cb5bc2d 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -20,6 +20,8 @@ class MipsTargetStreamer : public MCTargetStreamer { public: virtual void emitMipsHackELFFlags(unsigned Flags) = 0; virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) = 0; + virtual void emitDirectiveAbiCalls() = 0; + virtual void emitDirectiveOptionPic0() = 0; }; // This part is for ascii assembly output @@ -30,15 +32,20 @@ public: MipsTargetAsmStreamer(formatted_raw_ostream &OS); virtual void emitMipsHackELFFlags(unsigned Flags); virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val); + virtual void emitDirectiveAbiCalls(); + virtual void emitDirectiveOptionPic0(); }; // This part is for ELF object output class MipsTargetELFStreamer : public MipsTargetStreamer { public: MCELFStreamer &getStreamer(); + MipsTargetELFStreamer(); + // FIXME: emitMipsHackELFFlags() will be removed from this class. virtual void emitMipsHackELFFlags(unsigned Flags); virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val); + virtual void emitDirectiveAbiCalls(); + virtual void emitDirectiveOptionPic0(); }; } - #endif diff --git a/test/MC/Mips/elf_eflags.ll b/test/MC/Mips/elf_eflags.ll index 9432dcf59c3..8216a90aa30 100644 --- a/test/MC/Mips/elf_eflags.ll +++ b/test/MC/Mips/elf_eflags.ll @@ -29,7 +29,7 @@ ; RUN: llc -mtriple mipsel-unknown-linux -mcpu=mips64r2 -print-hack-directives %s -o - | FileCheck -check-prefix=CHECK-BE64R2_PIC %s ; RUN: llc -mtriple mipsel-unknown-linux -mcpu=mips32r2 -mattr=+mips16 -relocation-model=pic -print-hack-directives %s -o - | FileCheck -check-prefix=CHECK-LE32R2-MIPS16 %s - + ; 32(R1) bit with NO_REORDER and static ; CHECK-BE32: .mips_hack_elf_flags 0x50001005 ; diff --git a/test/MC/Mips/elf_eflags.s b/test/MC/Mips/elf_eflags.s index c56596444ae..c05772970a7 100644 --- a/test/MC/Mips/elf_eflags.s +++ b/test/MC/Mips/elf_eflags.s @@ -1,5 +1,12 @@ // RUN: llvm-mc -filetype=obj -triple mipsel-unknown-linux %s -o -| llvm-readobj -h | FileCheck %s +// The initial value will be set at 0x50001003 and +// we will override that with the negation of 0x2 (option pic0 +// the addition of 0x4 (.abicalls) - .mips_hack_elf_flags 0x50001005 + .mips_hack_elf_flags 0x50001003 // CHECK: Flags [ (0x50001005) + + .abicalls + + .option pic0 diff --git a/test/MC/Mips/mips_directives.s b/test/MC/Mips/mips_directives.s index 7e4f937e907..0fb377edbc4 100644 --- a/test/MC/Mips/mips_directives.s +++ b/test/MC/Mips/mips_directives.s @@ -2,8 +2,10 @@ # # CHECK: .text # CHECK: $BB0_2: +# CHECK: .abicalls $BB0_2: .ent directives_test + .abicalls .frame $sp,0,$ra .mask 0x00000000,0 .fmask 0x00000000,0 diff --git a/test/MC/Mips/mips_directives_bad.s b/test/MC/Mips/mips_directives_bad.s new file mode 100644 index 00000000000..7705eee55b0 --- /dev/null +++ b/test/MC/Mips/mips_directives_bad.s @@ -0,0 +1,49 @@ +# Error checking for malformed directives +# RUN: not llvm-mc -triple mips-unknown-unknown %s 2>&1 | FileCheck %s + + .abicalls should have no operands +# CHECK: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in directive +# CHECK-NEXT: .abicalls should have no operands +# CHECK-NEXT: ^ + +# We don't know yet how to represent a list of options +# pic2 will eventually be legal so we will probably want +# to change it to something silly. + +# Blank option operand + .option +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option directive +# CHECK-NEXT: .option +# CHECK-NEXT: ^ + +# Numeric option operand + .option 2 +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option directive +# CHECK-NEXT: .option 2 +# CHECK-NEXT: ^ + +# Register option operand + .option $2 +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option directive +# CHECK-NEXT: .option $2 +# CHECK-NEXT: ^ + + .option WithBadOption +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: warning: unknown option in .option directive +# CHECK-NEXT: .option WithBadOption +# CHECK-NEXT: ^ + + .option pic0, +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option pic0 directive +# CHECK-NEXT: .option pic0, +# CHECK-NEXT: ^ + + .option pic0,pic2 +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option pic0 directive +# CHECK-NEXT: .option pic0,pic2 +# CHECK-NEXT: ^ + + .option pic0 pic2 +# CHECK-NEXT: :{{[0-9]+}}:{{[0-9]+}}: error: unexpected token in .option pic0 directive +# CHECK-NEXT: .option pic0 pic2 +# CHECK-NEXT: ^