diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index b8f80a3bcbc..b8ab048a4b3 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -496,6 +496,15 @@ enum { R_PPC_REL16_HA = 252 }; +// Specific e_flags for PPC64 +enum { + // e_flags bits specifying ABI: + // 1 for original ABI using function descriptors, + // 2 for revised ABI without function descriptors, + // 0 for unspecified or not using any features affected by the differences. + EF_PPC64_ABI = 3 +}; + // ELF Relocation types for PPC64 enum { R_PPC64_NONE = 0, diff --git a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index 2f562ca7891..7560a7a1831 100644 --- a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -244,6 +244,7 @@ class PPCAsmParser : public MCTargetAsmParser { bool ParseDirectiveTC(unsigned Size, SMLoc L); bool ParseDirectiveMachine(SMLoc L); bool ParseDarwinDirectiveMachine(SMLoc L); + bool ParseDirectiveAbiVersion(SMLoc L); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -1412,6 +1413,8 @@ bool PPCAsmParser::ParseDirective(AsmToken DirectiveID) { return ParseDirectiveTC(isPPC64()? 8 : 4, DirectiveID.getLoc()); if (IDVal == ".machine") return ParseDirectiveMachine(DirectiveID.getLoc()); + if (IDVal == ".abiversion") + return ParseDirectiveAbiVersion(DirectiveID.getLoc()); } else { if (IDVal == ".machine") return ParseDarwinDirectiveMachine(DirectiveID.getLoc()); @@ -1534,6 +1537,27 @@ bool PPCAsmParser::ParseDarwinDirectiveMachine(SMLoc L) { return false; } +/// ParseDirectiveAbiVersion +/// ::= .abiversion constant-expression +bool PPCAsmParser::ParseDirectiveAbiVersion(SMLoc L) { + int64_t AbiVersion; + if (getParser().parseAbsoluteExpression(AbiVersion)){ + Error(L, "expected constant expression"); + return false; + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(L, "unexpected token in directive"); + return false; + } + + PPCTargetStreamer &TStreamer = + *static_cast( + getParser().getStreamer().getTargetStreamer()); + TStreamer.emitAbiVersion(AbiVersion); + + return false; +} + /// Force static initialization. extern "C" void LLVMInitializePowerPCAsmParser() { RegisterMCAsmParser A(ThePPC32Target); diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index 7057797cf8c..fa0e78ab3a7 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -16,12 +16,14 @@ #include "PPCMCAsmInfo.h" #include "PPCTargetStreamer.h" #include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" @@ -125,12 +127,18 @@ public: void emitMachine(StringRef CPU) override { OS << "\t.machine " << CPU << '\n'; } + virtual void emitAbiVersion(int AbiVersion) override { + OS << "\t.abiversion " << AbiVersion << '\n'; + } }; class PPCTargetELFStreamer : public PPCTargetStreamer { public: PPCTargetELFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {} - void emitTCEntry(const MCSymbol &S) override { + MCELFStreamer &getStreamer() { + return static_cast(Streamer); + } + virtual void emitTCEntry(const MCSymbol &S) override { // Creates a R_PPC64_TOC relocation Streamer.EmitSymbolValue(&S, 8); } @@ -138,6 +146,13 @@ public: // FIXME: Is there anything to do in here or does this directive only // limit the parser? } + virtual void emitAbiVersion(int AbiVersion) override { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_PPC64_ABI; + Flags |= (AbiVersion & ELF::EF_PPC64_ABI); + MCA.setELFHeaderEFlags(Flags); + } }; class PPCTargetMachOStreamer : public PPCTargetStreamer { @@ -150,6 +165,9 @@ public: // FIXME: We should update the CPUType, CPUSubType in the Object file if // the new values are different from the defaults. } + virtual void emitAbiVersion(int AbiVersion) override { + llvm_unreachable("Unknown pseudo-op: .abiversion"); + } }; } diff --git a/lib/Target/PowerPC/PPCTargetStreamer.h b/lib/Target/PowerPC/PPCTargetStreamer.h index 74b5f458452..9baf57d4c72 100644 --- a/lib/Target/PowerPC/PPCTargetStreamer.h +++ b/lib/Target/PowerPC/PPCTargetStreamer.h @@ -19,6 +19,7 @@ public: virtual ~PPCTargetStreamer(); virtual void emitTCEntry(const MCSymbol &S) = 0; virtual void emitMachine(StringRef CPU) = 0; + virtual void emitAbiVersion(int AbiVersion) = 0; }; } diff --git a/test/MC/PowerPC/ppc64-abiversion.s b/test/MC/PowerPC/ppc64-abiversion.s new file mode 100644 index 00000000000..d2970f8c905 --- /dev/null +++ b/test/MC/PowerPC/ppc64-abiversion.s @@ -0,0 +1,9 @@ + +# RUN: llvm-mc -triple powerpc64-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -h | FileCheck %s +# RUN: llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -h | FileCheck %s + + .abiversion 2 +# CHECK: Flags [ (0x2) +