diff options
Diffstat (limited to 'llvm/lib/Target/PowerPC/MCTargetDesc')
17 files changed, 597 insertions, 522 deletions
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 8778e916f7e4d..dbaf221db9fc9 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -28,7 +28,6 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); - case FK_NONE: case FK_Data_1: case FK_Data_2: case FK_Data_4: @@ -40,11 +39,14 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { return Value & 0xfffc; case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: return Value & 0x3fffffc; case PPC::fixup_ppc_half16: return Value & 0xffff; case PPC::fixup_ppc_half16ds: return Value & 0xfffc; + case PPC::fixup_ppc_pcrel34: + return Value & 0x3ffffffff; } } @@ -52,8 +54,6 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); - case FK_NONE: - return 0; case FK_Data_1: return 1; case FK_Data_2: @@ -65,7 +65,9 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { case PPC::fixup_ppc_brcond14abs: case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: return 4; + case PPC::fixup_ppc_pcrel34: case FK_Data_8: return 8; case PPC::fixup_ppc_nofixup: @@ -91,24 +93,33 @@ public: const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = { // name offset bits flags { "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24_notoc", 6, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_br24abs", 6, 24, 0 }, { "fixup_ppc_brcond14abs", 16, 14, 0 }, { "fixup_ppc_half16", 0, 16, 0 }, { "fixup_ppc_half16ds", 0, 14, 0 }, + { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_nofixup", 0, 0, 0 } }; const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = { // name offset bits flags { "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24_notoc", 2, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_br24abs", 2, 24, 0 }, { "fixup_ppc_brcond14abs", 2, 14, 0 }, { "fixup_ppc_half16", 0, 16, 0 }, { "fixup_ppc_half16ds", 2, 14, 0 }, + { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_nofixup", 0, 0, 0 } }; + // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They + // do not require any extra processing. + if (Kind >= FirstLiteralRelocationKind) + return MCAsmBackend::getFixupKindInfo(FK_NONE); + if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); @@ -123,11 +134,14 @@ public: const MCValue &Target, MutableArrayRef<char> Data, uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const override { - Value = adjustFixupValue(Fixup.getKind(), Value); + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return; + Value = adjustFixupValue(Kind, Value); if (!Value) return; // Doesn't change encoding. unsigned Offset = Fixup.getOffset(); - unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); + unsigned NumBytes = getFixupKindNumBytes(Kind); // For each byte of the fragment that the fixup touches, mask in the bits // from the fixup value. The Value has been "split up" into the appropriate @@ -140,13 +154,13 @@ public: bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target) override { - switch ((unsigned)Fixup.getKind()) { + MCFixupKind Kind = Fixup.getKind(); + switch ((unsigned)Kind) { default: - return false; - case FK_NONE: - return true; + return Kind >= FirstLiteralRelocationKind; case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: // If the target symbol has a local entry point we must not attempt // to resolve the fixup directly. Emit a relocation and leave // resolution of the final target address to the linker. @@ -178,8 +192,8 @@ public: llvm_unreachable("relaxInstruction() unimplemented"); } - void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, - MCInst &Res) const override { + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override { // FIXME. llvm_unreachable("relaxInstruction() unimplemented"); } @@ -200,21 +214,6 @@ public: // FIXME: This should be in a separate file. namespace { -class DarwinPPCAsmBackend : public PPCAsmBackend { -public: - DarwinPPCAsmBackend(const Target &T, const Triple &TT) - : PPCAsmBackend(T, TT) {} - - std::unique_ptr<MCObjectTargetWriter> - createObjectTargetWriter() const override { - bool Is64 = TT.isPPC64(); - return createPPCMachObjectWriter( - /*Is64Bit=*/Is64, - (Is64 ? MachO::CPU_TYPE_POWERPC64 : MachO::CPU_TYPE_POWERPC), - MachO::CPU_SUBTYPE_POWERPC_ALL); - } -}; - class ELFPPCAsmBackend : public PPCAsmBackend { public: ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {} @@ -243,14 +242,25 @@ public: } // end anonymous namespace Optional<MCFixupKind> ELFPPCAsmBackend::getFixupKind(StringRef Name) const { - if (TT.isPPC64()) { - if (Name == "R_PPC64_NONE") - return FK_NONE; - } else { - if (Name == "R_PPC_NONE") - return FK_NONE; + if (TT.isOSBinFormatELF()) { + unsigned Type; + if (TT.isPPC64()) { + Type = llvm::StringSwitch<unsigned>(Name) +#define ELF_RELOC(X, Y) .Case(#X, Y) +#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def" +#undef ELF_RELOC + .Default(-1u); + } else { + Type = llvm::StringSwitch<unsigned>(Name) +#define ELF_RELOC(X, Y) .Case(#X, Y) +#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def" +#undef ELF_RELOC + .Default(-1u); + } + if (Type != -1u) + return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); } - return MCAsmBackend::getFixupKind(Name); + return None; } MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, @@ -258,9 +268,6 @@ MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, const MCRegisterInfo &MRI, const MCTargetOptions &Options) { const Triple &TT = STI.getTargetTriple(); - if (TT.isOSDarwin()) - return new DarwinPPCAsmBackend(T, TT); - if (TT.isOSBinFormatXCOFF()) return new XCOFFPPCAsmBackend(T, TT); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp index 20f752c3041ad..d8b3301e97f12 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -73,6 +73,9 @@ static MCSymbolRefExpr::VariantKind getAccessVariant(const MCValue &Target, unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return Kind - FirstLiteralRelocationKind; MCSymbolRefExpr::VariantKind Modifier = getAccessVariant(Target, Fixup); // determine the type of the relocation @@ -83,6 +86,7 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, llvm_unreachable("Unimplemented"); case PPC::fixup_ppc_br24: case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); case MCSymbolRefExpr::VK_None: @@ -94,6 +98,9 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, case MCSymbolRefExpr::VK_PPC_LOCAL: Type = ELF::R_PPC_LOCAL24PC; break; + case MCSymbolRefExpr::VK_PPC_NOTOC: + Type = ELF::R_PPC64_REL24_NOTOC; + break; } break; case PPC::fixup_ppc_brcond14: @@ -121,6 +128,18 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, Target.print(errs()); errs() << '\n'; report_fatal_error("Invalid PC-relative half16ds relocation"); + case PPC::fixup_ppc_pcrel34: + switch (Modifier) { + default: + llvm_unreachable("Unsupported Modifier for fixup_ppc_pcrel34"); + case MCSymbolRefExpr::VK_PCREL: + Type = ELF::R_PPC64_PCREL34; + break; + case MCSymbolRefExpr::VK_PPC_GOT_PCREL: + Type = ELF::R_PPC64_GOT_PCREL34; + break; + } + break; case FK_Data_4: case FK_PCRel_4: Type = ELF::R_PPC_REL32; @@ -133,9 +152,6 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, } else { switch (Fixup.getTargetKind()) { default: llvm_unreachable("invalid fixup kind!"); - case FK_NONE: - Type = ELF::R_PPC_NONE; - break; case PPC::fixup_ppc_br24abs: Type = ELF::R_PPC_ADDR24; break; @@ -431,6 +447,7 @@ bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, return false; case ELF::R_PPC_REL24: + case ELF::R_PPC64_REL24_NOTOC: // If the target symbol has a local entry point, we must keep the // target symbol to preserve that information for the linker. // The "other" values are stored in the last 6 bits of the second byte. diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp new file mode 100644 index 0000000000000..4373778cc96cc --- /dev/null +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp @@ -0,0 +1,112 @@ +//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a custom MCELFStreamer for PowerPC. +// +// The purpose of the custom ELF streamer is to allow us to intercept +// instructions as they are being emitted and align all 8 byte instructions +// to a 64 byte boundary if required (by adding a 4 byte nop). This is important +// because 8 byte instructions are not allowed to cross 64 byte boundaries +// and by aliging anything that is within 4 bytes of the boundary we can +// guarantee that the 8 byte instructions do not cross that boundary. +// +//===----------------------------------------------------------------------===// + + +#include "PPCELFStreamer.h" +#include "PPCInstrInfo.h" +#include "PPCMCCodeEmitter.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/SourceMgr.h" + +using namespace llvm; + +PPCELFStreamer::PPCELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) + : MCELFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)), LastLabel(NULL) { +} + +void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is + // before the boundary and the remaining 4-bytes are after the boundary). In + // order to achieve this, a nop is added prior to any such boundary-crossing + // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4 + // bytes when trying to do that. If alignment requires adding more than 4 + // bytes then the instruction won't be aligned. When emitting a code alignment + // a new fragment is created for this alignment. This fragment will contain + // all of the nops required as part of the alignment operation. In the cases + // when no nops are added then The fragment is still created but it remains + // empty. + emitCodeAlignment(64, 4); + + // Emit the instruction. + // Since the previous emit created a new fragment then adding this instruction + // also forces the addition of a new fragment. Inst is now the first + // instruction in that new fragment. + MCELFStreamer::emitInstruction(Inst, STI); + + // The above instruction is forced to start a new fragment because it + // comes after a code alignment fragment. Get that new fragment. + MCFragment *InstructionFragment = getCurrentFragment(); + SMLoc InstLoc = Inst.getLoc(); + // Check if there was a last label emitted. + if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() && + InstLoc.isValid()) { + const SourceMgr *SourceManager = getContext().getSourceManager(); + unsigned InstLine = SourceManager->FindLineNumber(InstLoc); + unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc); + // If the Label and the Instruction are on the same line then move the + // label to the top of the fragment containing the aligned instruction that + // was just added. + if (InstLine == LabelLine) { + AssignFragment(LastLabel, InstructionFragment); + LastLabel->setOffset(0); + } + } +} + +void PPCELFStreamer::emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + PPCMCCodeEmitter *Emitter = + static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr()); + + // Special handling is only for prefixed instructions. + if (!Emitter->isPrefixedInstruction(Inst)) { + MCELFStreamer::emitInstruction(Inst, STI); + return; + } + emitPrefixedInstruction(Inst, STI); +} + +void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { + LastLabel = Symbol; + LastLabelLoc = Loc; + MCELFStreamer::emitLabel(Symbol); +} + +MCELFStreamer *llvm::createPPCELFStreamer( + MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) { + return new PPCELFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h new file mode 100644 index 0000000000000..51863232d0719 --- /dev/null +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h @@ -0,0 +1,54 @@ +//===- PPCELFStreamer.h - ELF Object Output --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a custom MCELFStreamer for PowerPC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H +#define LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCELFStreamer.h" +#include <memory> + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCSubtargetInfo; + +class PPCELFStreamer : public MCELFStreamer { + // We need to keep track of the last label we emitted (only one) because + // depending on whether the label is on the same line as an aligned + // instruction or not, the label may refer to the instruction or the nop. + MCSymbol *LastLabel; + SMLoc LastLabelLoc; + +public: + PPCELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); + + void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + + // EmitLabel updates LastLabel and LastLabelLoc when a new label is emitted. + void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; +private: + void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); +}; + +MCELFStreamer *createPPCELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h index 845489788c86f..2fb8947fd4e0f 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -19,6 +19,10 @@ enum Fixups { // 24-bit PC relative relocation for direct branches like 'b' and 'bl'. fixup_ppc_br24 = FirstTargetFixupKind, + // 24-bit PC relative relocation for direct branches like 'b' and 'bl' where + // the caller does not use the TOC. + fixup_ppc_br24_notoc, + /// 14-bit PC relative relocation for conditional branches. fixup_ppc_brcond14, @@ -36,6 +40,9 @@ enum Fixups { /// instrs like 'std'. fixup_ppc_half16ds, + // A 34-bit fixup corresponding to PC-relative paddi. + fixup_ppc_pcrel34, + /// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the /// TLS general and local dynamic models, or inserts the thread-pointer /// register number. diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp index 9cc1c539e24a9..16da62a74b8cd 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -116,16 +116,6 @@ void PPCInstPrinter::printInst(const MCInst *MI, uint64_t Address, } } - if ((MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) && - MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) { - O << "\tmr "; - printOperand(MI, 0, O); - O << ", "; - printOperand(MI, 1, O); - printAnnotation(O, Annot); - return; - } - if (MI->getOpcode() == PPC::RLDICR || MI->getOpcode() == PPC::RLDICR_32) { unsigned char SH = MI->getOperand(2).getImm(); @@ -193,7 +183,7 @@ void PPCInstPrinter::printInst(const MCInst *MI, uint64_t Address, } } - if (!printAliasInstr(MI, O)) + if (!printAliasInstr(MI, Address, O)) printInstruction(MI, Address, O); printAnnotation(O, Annot); } @@ -339,6 +329,13 @@ void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo, O << (int)Value; } +void PPCInstPrinter::printImmZeroOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value == 0 && "Operand must be zero"); + O << (unsigned int)Value; +} + void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { unsigned int Value = MI->getOperand(OpNo).getImm(); @@ -391,6 +388,17 @@ void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo, printOperand(MI, OpNo, O); } +void PPCInstPrinter::printS34ImmOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + if (MI->getOperand(OpNo).isImm()) { + long long Value = MI->getOperand(OpNo).getImm(); + assert(isInt<34>(Value) && "Invalid s34imm argument!"); + O << (long long)Value; + } + else + printOperand(MI, OpNo, O); +} + void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { if (MI->getOperand(OpNo).isImm()) @@ -399,18 +407,29 @@ void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo, printOperand(MI, OpNo, O); } -void PPCInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) { +void PPCInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address, + unsigned OpNo, raw_ostream &O) { if (!MI->getOperand(OpNo).isImm()) return printOperand(MI, OpNo, O); - - // Branches can take an immediate operand. This is used by the branch - // selection pass to print .+8, an eight byte displacement from the PC. - O << "."; int32_t Imm = SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2); - if (Imm >= 0) - O << "+"; - O << Imm; + if (PrintBranchImmAsAddress) { + uint64_t Target = Address + Imm; + if (!TT.isPPC64()) + Target &= 0xffffffff; + O << formatHex(Target); + } else { + // Branches can take an immediate operand. This is used by the branch + // selection pass to print, for example `.+8` (for ELF) or `$+8` (for AIX) + // to express an eight byte displacement from the program counter. + if (!TT.isOSAIX()) + O << "."; + else + O << "$"; + + if (Imm >= 0) + O << "+"; + O << Imm; + } } void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo, @@ -451,6 +470,22 @@ void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo, O << ')'; } +void PPCInstPrinter::printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + printS34ImmOperand(MI, OpNo, O); + O << '('; + printImmZeroOperand(MI, OpNo + 1, O); + O << ')'; +} + +void PPCInstPrinter::printMemRegImm34(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + printS34ImmOperand(MI, OpNo, O); + O << '('; + printOperand(MI, OpNo + 1, O); + O << ')'; +} + void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo, raw_ostream &O) { // When used as the base register, r0 reads constant zero rather than diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h index a3ec41aa348d6..9763aeceef941 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h @@ -39,9 +39,9 @@ public: void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); static const char *getRegisterName(unsigned RegNo); - bool printAliasInstr(const MCInst *MI, raw_ostream &OS); - void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, - unsigned PrintMethodIdx, + bool printAliasInstr(const MCInst *MI, uint64_t Address, raw_ostream &OS); + void printCustomAliasOperand(const MCInst *MI, uint64_t Address, + unsigned OpIdx, unsigned PrintMethodIdx, raw_ostream &OS); void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); @@ -61,14 +61,19 @@ public: void printU10ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printU12ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printS16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printS34ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printU16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); - void printBranchOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printImmZeroOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printBranchOperand(const MCInst *MI, uint64_t Address, unsigned OpNo, + raw_ostream &O); void printAbsBranchOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printTLSCall(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printcrbitm(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printMemRegImm(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printMemRegImm34(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printMemRegReg(const MCInst *MI, unsigned OpNo, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp index dc2c216a3efd4..593dc2843c3d3 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -12,6 +12,7 @@ #include "PPCMCAsmInfo.h" #include "llvm/ADT/Triple.h" +#include <cassert> using namespace llvm; @@ -50,15 +51,15 @@ PPCELFMCAsmInfo::PPCELFMCAsmInfo(bool is64Bit, const Triple& T) { Data64bitsDirective = is64Bit ? "\t.quad\t" : nullptr; AssemblerDialect = 1; // New-Style mnemonics. LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment; - - UseIntegratedAssembler = true; } void PPCXCOFFMCAsmInfo::anchor() {} PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) { - assert(!IsLittleEndian && "Little-endian XCOFF not supported."); + if (T.getArch() == Triple::ppc64le) + report_fatal_error("XCOFF is not supported for little-endian targets"); CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4; - ZeroDirective = "\t.space\t"; - SymbolsHaveSMC = true; + + // A size of 8 is only supported by the assembler under 64-bit. + Data64bitsDirective = Is64Bit ? "\t.vbyte\t8, " : nullptr; } diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h index 8c52bbbd8a56a..27c687686641f 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h @@ -28,7 +28,7 @@ public: }; class PPCXCOFFMCAsmInfo : public MCAsmInfoXCOFF { - virtual void anchor(); + void anchor() override; public: explicit PPCXCOFFMCAsmInfo(bool is64Bit, const Triple &); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp index 676efc5004553..fb65e7320f2b0 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -48,7 +48,9 @@ getDirectBrEncoding(const MCInst &MI, unsigned OpNo, // Add a fixup for the branch target. Fixups.push_back(MCFixup::create(0, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_br24)); + ((MI.getOpcode() == PPC::BL8_NOTOC) + ? (MCFixupKind)PPC::fixup_ppc_br24_notoc + : (MCFixupKind)PPC::fixup_ppc_br24))); return 0; } @@ -102,6 +104,20 @@ unsigned PPCMCCodeEmitter::getImm16Encoding(const MCInst &MI, unsigned OpNo, return 0; } +uint64_t +PPCMCCodeEmitter::getImm34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the immediate field. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_pcrel34)); + return 0; +} + unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -159,6 +175,104 @@ unsigned PPCMCCodeEmitter::getMemRIX16Encoding(const MCInst &MI, unsigned OpNo, return RegBits; } +uint64_t +PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode the PCRelative version of memri34: imm34(r0). + // In the PC relative version the register for the address must be zero. + // The 34 bit immediate can fall into one of three cases: + // 1) It is a relocation to be filled in by the linker represented as: + // (MCExpr::SymbolRef) + // 2) It is a relocation + SignedOffset represented as: + // (MCExpr::Binary(MCExpr::SymbolRef + MCExpr::Constant)) + // 3) It is a known value at compile time. + + // Make sure that the register is a zero as expected. + assert(MI.getOperand(OpNo + 1).isImm() && "Expecting an immediate."); + uint64_t RegBits = + getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) << 34; + assert(RegBits == 0 && "Operand must be 0."); + + // If this is not a MCExpr then we are in case 3) and we are dealing with + // a value known at compile time, not a relocation. + const MCOperand &MO = MI.getOperand(OpNo); + if (!MO.isExpr()) + return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits; + + // At this point in the function it is known that MO is of type MCExpr. + // Therefore we are dealing with either case 1) a symbol ref or + // case 2) a symbol ref plus a constant. + const MCExpr *Expr = MO.getExpr(); + switch (Expr->getKind()) { + default: + llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding."); + case MCExpr::SymbolRef: { + // Relocation alone. + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr); + (void)SRE; + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + case MCExpr::Binary: { + // Relocation plus some offset. + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); + assert(BE->getOpcode() == MCBinaryExpr::Add && + "Binary expression opcode must be an add."); + + const MCExpr *LHS = BE->getLHS(); + const MCExpr *RHS = BE->getRHS(); + + // Need to check in both directions. Reloc+Offset and Offset+Reloc. + if (LHS->getKind() != MCExpr::SymbolRef) + std::swap(LHS, RHS); + + if (LHS->getKind() != MCExpr::SymbolRef || + RHS->getKind() != MCExpr::Constant) + llvm_unreachable("Expecting to have one constant and one relocation."); + + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(LHS); + (void)SRE; + assert(isInt<34>(cast<MCConstantExpr>(RHS)->getValue()) && + "Value must fit in 34 bits."); + + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + } +} + +uint64_t +PPCMCCodeEmitter::getMemRI34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode (imm, reg) as a memri34, which has the low 34-bits as the + // displacement and the next 5 bits as the register #. + assert(MI.getOperand(OpNo + 1).isReg() && "Expecting a register."); + uint64_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo + 1), Fixups, STI) + << 34; + const MCOperand &MO = MI.getOperand(OpNo); + return ((getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL) | RegBits; +} + unsigned PPCMCCodeEmitter::getSPE8DisEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) @@ -257,7 +371,7 @@ static unsigned getOpIdxForMO(const MCInst &MI, const MCOperand &MO) { return ~0U; // Silence any warnings about no return. } -unsigned PPCMCCodeEmitter:: +uint64_t PPCMCCodeEmitter:: getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { @@ -316,5 +430,11 @@ unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const { return Desc.getSize(); } +bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const { + unsigned Opcode = MI.getOpcode(); + const PPCInstrInfo *InstrInfo = static_cast<const PPCInstrInfo*>(&MCII); + return InstrInfo->isPrefixed(Opcode); +} + #define ENABLE_INSTR_PREDICATE_VERIFIER #include "PPCGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h index 1324faa125533..588aa76bd8064 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h @@ -50,6 +50,9 @@ public: unsigned getImm16Encoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; + uint64_t getImm34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; unsigned getMemRIEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; @@ -59,6 +62,12 @@ public: unsigned getMemRIX16Encoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; + uint64_t getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + uint64_t getMemRI34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; unsigned getSPE8DisEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; @@ -80,7 +89,7 @@ public: /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. - unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const; @@ -97,6 +106,9 @@ public: // Get the number of bytes used to encode the given MCInst. unsigned getInstSizeInBytes(const MCInst &MI) const; + // Is this instruction a prefixed instruction. + bool isPrefixedInstruction(const MCInst &MI) const; + private: FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; void diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp index fb9dd5d7aa758..abff444491313 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp @@ -17,39 +17,44 @@ using namespace llvm; #define DEBUG_TYPE "ppcmcexpr" -const PPCMCExpr* -PPCMCExpr::create(VariantKind Kind, const MCExpr *Expr, - bool IsDarwin, MCContext &Ctx) { - return new (Ctx) PPCMCExpr(Kind, Expr, IsDarwin); +const PPCMCExpr *PPCMCExpr::create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) PPCMCExpr(Kind, Expr); } void PPCMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { - if (isDarwinSyntax()) { - switch (Kind) { - default: llvm_unreachable("Invalid kind!"); - case VK_PPC_LO: OS << "lo16"; break; - case VK_PPC_HI: OS << "hi16"; break; - case VK_PPC_HA: OS << "ha16"; break; - } - - OS << '('; - getSubExpr()->print(OS, MAI); - OS << ')'; - } else { - getSubExpr()->print(OS, MAI); + getSubExpr()->print(OS, MAI); - switch (Kind) { - default: llvm_unreachable("Invalid kind!"); - case VK_PPC_LO: OS << "@l"; break; - case VK_PPC_HI: OS << "@h"; break; - case VK_PPC_HA: OS << "@ha"; break; - case VK_PPC_HIGH: OS << "@high"; break; - case VK_PPC_HIGHA: OS << "@higha"; break; - case VK_PPC_HIGHER: OS << "@higher"; break; - case VK_PPC_HIGHERA: OS << "@highera"; break; - case VK_PPC_HIGHEST: OS << "@highest"; break; - case VK_PPC_HIGHESTA: OS << "@highesta"; break; - } + switch (Kind) { + default: + llvm_unreachable("Invalid kind!"); + case VK_PPC_LO: + OS << "@l"; + break; + case VK_PPC_HI: + OS << "@h"; + break; + case VK_PPC_HA: + OS << "@ha"; + break; + case VK_PPC_HIGH: + OS << "@high"; + break; + case VK_PPC_HIGHA: + OS << "@higha"; + break; + case VK_PPC_HIGHER: + OS << "@higher"; + break; + case VK_PPC_HIGHERA: + OS << "@highera"; + break; + case VK_PPC_HIGHEST: + OS << "@highest"; + break; + case VK_PPC_HIGHESTA: + OS << "@highesta"; + break; } } diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h index ad1454566162a..1dbc7eae63c8a 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h @@ -33,33 +33,29 @@ public: private: const VariantKind Kind; const MCExpr *Expr; - bool IsDarwin; int64_t evaluateAsInt64(int64_t Value) const; - explicit PPCMCExpr(VariantKind Kind, const MCExpr *Expr, bool IsDarwin) - : Kind(Kind), Expr(Expr), IsDarwin(IsDarwin) {} + explicit PPCMCExpr(VariantKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} public: /// @name Construction /// @{ static const PPCMCExpr *create(VariantKind Kind, const MCExpr *Expr, - bool IsDarwin, MCContext &Ctx); + MCContext &Ctx); - static const PPCMCExpr *createLo(const MCExpr *Expr, - bool IsDarwin, MCContext &Ctx) { - return create(VK_PPC_LO, Expr, IsDarwin, Ctx); + static const PPCMCExpr *createLo(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_LO, Expr, Ctx); } - static const PPCMCExpr *createHi(const MCExpr *Expr, - bool IsDarwin, MCContext &Ctx) { - return create(VK_PPC_HI, Expr, IsDarwin, Ctx); + static const PPCMCExpr *createHi(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_HI, Expr, Ctx); } - static const PPCMCExpr *createHa(const MCExpr *Expr, - bool IsDarwin, MCContext &Ctx) { - return create(VK_PPC_HA, Expr, IsDarwin, Ctx); + static const PPCMCExpr *createHa(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_HA, Expr, Ctx); } /// @} @@ -72,10 +68,6 @@ public: /// getSubExpr - Get the child of this expression. const MCExpr *getSubExpr() const { return Expr; } - /// isDarwinSyntax - True if expression is to be printed using Darwin syntax. - bool isDarwinSyntax() const { return IsDarwin; } - - /// @} void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index cbfb8e2ff2825..3092d56da1c59 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -13,6 +13,7 @@ #include "MCTargetDesc/PPCMCTargetDesc.h" #include "MCTargetDesc/PPCInstPrinter.h" #include "MCTargetDesc/PPCMCAsmInfo.h" +#include "PPCELFStreamer.h" #include "PPCTargetStreamer.h" #include "TargetInfo/PowerPCTargetInfo.h" #include "llvm/ADT/SmallPtrSet.h" @@ -20,11 +21,14 @@ #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -91,12 +95,21 @@ static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI, // Initial state of the frame pointer is R1. unsigned Reg = isPPC64 ? PPC::X1 : PPC::R1; MCCFIInstruction Inst = - MCCFIInstruction::createDefCfa(nullptr, MRI.getDwarfRegNum(Reg, true), 0); + MCCFIInstruction::cfiDefCfa(nullptr, MRI.getDwarfRegNum(Reg, true), 0); MAI->addInitialFrameState(Inst); return MAI; } +static MCStreamer *createPPCMCStreamer(const Triple &T, MCContext &Context, + std::unique_ptr<MCAsmBackend> &&MAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, + bool RelaxAll) { + return createPPCELFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} + namespace { class PPCTargetAsmStreamer : public PPCTargetStreamer { @@ -107,14 +120,17 @@ public: : PPCTargetStreamer(S), OS(OS) {} void emitTCEntry(const MCSymbol &S) override { - const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); - OS << "\t.tc "; - OS << (MAI->getSymbolsHaveSMC() - ? cast<MCSymbolXCOFF>(S).getUnqualifiedName() - : S.getName()); - OS << "[TC],"; - OS << S.getName(); - OS << '\n'; + if (const MCSymbolXCOFF *XSym = dyn_cast<MCSymbolXCOFF>(&S)) { + MCSymbolXCOFF *TCSym = + cast<MCSymbolXCOFF>(Streamer.getContext().getOrCreateSymbol( + XSym->getSymbolTableName() + "[TC]")); + if (TCSym->hasRename()) + Streamer.emitXCOFFRenameDirective(TCSym, TCSym->getSymbolTableName()); + OS << "\t.tc " << TCSym->getName() << "," << XSym->getName() << '\n'; + return; + } + + OS << "\t.tc " << S.getName() << "[TC]," << S.getName() << '\n'; } void emitMachine(StringRef CPU) override { @@ -146,8 +162,8 @@ public: void emitTCEntry(const MCSymbol &S) override { // Creates a R_PPC64_TOC relocation - Streamer.EmitValueToAlignment(8); - Streamer.EmitSymbolValue(&S, 8); + Streamer.emitValueToAlignment(8); + Streamer.emitSymbolValue(&S, 8); } void emitMachine(StringRef CPU) override { @@ -166,13 +182,9 @@ public: void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { MCAssembler &MCA = getStreamer().getAssembler(); - int64_t Res; - if (!LocalOffset->evaluateAsAbsolute(Res, MCA)) - report_fatal_error(".localentry expression must be absolute."); - - unsigned Encoded = ELF::encodePPC64LocalEntryOffset(Res); - if (Res != ELF::decodePPC64LocalEntryOffset(Encoded)) - report_fatal_error(".localentry expression cannot be encoded."); + // encodePPC64LocalEntryOffset will report an error if it cannot + // encode LocalOffset. + unsigned Encoded = encodePPC64LocalEntryOffset(LocalOffset); unsigned Other = S->getOther(); Other &= ~ELF::STO_PPC64_LOCAL_MASK; @@ -201,6 +213,10 @@ public: for (auto *Sym : UpdateOther) if (Sym->isVariable()) copyLocalEntry(Sym, Sym->getVariableValue()); + + // Clear the set of symbols that needs to be updated so the streamer can + // be reused without issues. + UpdateOther.clear(); } private: @@ -217,6 +233,31 @@ private: D->setOther(Other); return true; } + + unsigned encodePPC64LocalEntryOffset(const MCExpr *LocalOffset) { + MCAssembler &MCA = getStreamer().getAssembler(); + int64_t Offset; + if (!LocalOffset->evaluateAsAbsolute(Offset, MCA)) + MCA.getContext().reportFatalError( + LocalOffset->getLoc(), ".localentry expression must be absolute."); + + switch (Offset) { + default: + MCA.getContext().reportFatalError( + LocalOffset->getLoc(), + ".localentry expression is not a valid power of 2."); + case 0: + return 0; + case 1: + return 1 << ELF::STO_PPC64_LOCAL_BIT; + case 4: + case 8: + case 16: + case 32: + case 64: + return (int)Log2(Offset) << (int)ELF::STO_PPC64_LOCAL_BIT; + } + } }; class PPCTargetMachOStreamer : public PPCTargetStreamer { @@ -248,8 +289,8 @@ public: void emitTCEntry(const MCSymbol &S) override { const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); const unsigned PointerSize = MAI->getCodePointerSize(); - Streamer.EmitValueToAlignment(PointerSize); - Streamer.EmitSymbolValue(&S, PointerSize); + Streamer.emitValueToAlignment(PointerSize); + Streamer.emitSymbolValue(&S, PointerSize); } void emitMachine(StringRef CPU) override { @@ -313,6 +354,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTargetMC() { // Register the asm backend. TargetRegistry::RegisterMCAsmBackend(*T, createPPCAsmBackend); + // Register the elf streamer. + TargetRegistry::RegisterELFStreamer(*T, createPPCMCStreamer); + // Register the object target streamer. TargetRegistry::RegisterObjectTargetStreamer(*T, createObjectTargetStreamer); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h index 49443679bb312..719e005d98135 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h @@ -32,9 +32,6 @@ class MCRegisterInfo; class MCSubtargetInfo; class MCTargetOptions; class Target; -class Triple; -class StringRef; -class raw_pwrite_stream; MCCodeEmitter *createPPCMCCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo &MRI, diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMachObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMachObjectWriter.cpp deleted file mode 100644 index 672f910ab086e..0000000000000 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMachObjectWriter.cpp +++ /dev/null @@ -1,380 +0,0 @@ -//===-- PPCMachObjectWriter.cpp - PPC Mach-O Writer -----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "MCTargetDesc/PPCFixupKinds.h" -#include "MCTargetDesc/PPCMCTargetDesc.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/MC/MCAsmLayout.h" -#include "llvm/MC/MCAssembler.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCMachObjectWriter.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" - -using namespace llvm; - -namespace { -class PPCMachObjectWriter : public MCMachObjectTargetWriter { - bool recordScatteredRelocation(MachObjectWriter *Writer, - const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - unsigned Log2Size, uint64_t &FixedValue); - - void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue); - -public: - PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype) - : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {} - - void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, - const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) override { - if (Writer->is64Bit()) { - report_fatal_error("Relocation emission for MachO/PPC64 unimplemented."); - } else - RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, - FixedValue); - } -}; -} - -/// computes the log2 of the size of the relocation, -/// used for relocation_info::r_length. -static unsigned getFixupKindLog2Size(unsigned Kind) { - switch (Kind) { - default: - report_fatal_error("log2size(FixupKind): Unhandled fixup kind!"); - case FK_PCRel_1: - case FK_Data_1: - return 0; - case FK_PCRel_2: - case FK_Data_2: - return 1; - case FK_PCRel_4: - case PPC::fixup_ppc_brcond14: - case PPC::fixup_ppc_half16: - case PPC::fixup_ppc_br24: - case FK_Data_4: - return 2; - case FK_PCRel_8: - case FK_Data_8: - return 3; - } - return 0; -} - -/// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum. -/// Outline based on PPCELFObjectWriter::getRelocType(). -static unsigned getRelocType(const MCValue &Target, - const MCFixupKind FixupKind, // from - // Fixup.getKind() - const bool IsPCRel) { - const MCSymbolRefExpr::VariantKind Modifier = - Target.isAbsolute() ? MCSymbolRefExpr::VK_None - : Target.getSymA()->getKind(); - // determine the type of the relocation - unsigned Type = MachO::GENERIC_RELOC_VANILLA; - if (IsPCRel) { // relative to PC - switch ((unsigned)FixupKind) { - default: - report_fatal_error("Unimplemented fixup kind (relative)"); - case PPC::fixup_ppc_br24: - Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24 - break; - case PPC::fixup_ppc_brcond14: - Type = MachO::PPC_RELOC_BR14; - break; - case PPC::fixup_ppc_half16: - switch (Modifier) { - default: - llvm_unreachable("Unsupported modifier for half16 fixup"); - case MCSymbolRefExpr::VK_PPC_HA: - Type = MachO::PPC_RELOC_HA16; - break; - case MCSymbolRefExpr::VK_PPC_LO: - Type = MachO::PPC_RELOC_LO16; - break; - case MCSymbolRefExpr::VK_PPC_HI: - Type = MachO::PPC_RELOC_HI16; - break; - } - break; - } - } else { - switch ((unsigned)FixupKind) { - default: - report_fatal_error("Unimplemented fixup kind (absolute)!"); - case PPC::fixup_ppc_half16: - switch (Modifier) { - default: - llvm_unreachable("Unsupported modifier for half16 fixup"); - case MCSymbolRefExpr::VK_PPC_HA: - Type = MachO::PPC_RELOC_HA16_SECTDIFF; - break; - case MCSymbolRefExpr::VK_PPC_LO: - Type = MachO::PPC_RELOC_LO16_SECTDIFF; - break; - case MCSymbolRefExpr::VK_PPC_HI: - Type = MachO::PPC_RELOC_HI16_SECTDIFF; - break; - } - break; - case FK_Data_4: - break; - case FK_Data_2: - break; - } - } - return Type; -} - -static void makeRelocationInfo(MachO::any_relocation_info &MRE, - const uint32_t FixupOffset, const uint32_t Index, - const unsigned IsPCRel, const unsigned Log2Size, - const unsigned IsExtern, const unsigned Type) { - MRE.r_word0 = FixupOffset; - // The bitfield offsets that work (as determined by trial-and-error) - // are different than what is documented in the mach-o manuals. - // This appears to be an endianness issue; reversing the order of the - // documented bitfields in <llvm/BinaryFormat/MachO.h> fixes this (but - // breaks x86/ARM assembly). - MRE.r_word1 = ((Index << 8) | // was << 0 - (IsPCRel << 7) | // was << 24 - (Log2Size << 5) | // was << 25 - (IsExtern << 4) | // was << 27 - (Type << 0)); // was << 28 -} - -static void -makeScatteredRelocationInfo(MachO::any_relocation_info &MRE, - const uint32_t Addr, const unsigned Type, - const unsigned Log2Size, const unsigned IsPCRel, - const uint32_t Value2) { - // For notes on bitfield positions and endianness, see: - // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry - MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) | - (IsPCRel << 30) | MachO::R_SCATTERED); - MRE.r_word1 = Value2; -} - -/// Compute fixup offset (address). -static uint32_t getFixupOffset(const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup) { - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - // On Mach-O, ppc_fixup_half16 relocations must refer to the - // start of the instruction, not the second halfword, as ELF does - if (Fixup.getTargetKind() == PPC::fixup_ppc_half16) - FixupOffset &= ~uint32_t(3); - return FixupOffset; -} - -/// \return false if falling back to using non-scattered relocation, -/// otherwise true for normal scattered relocation. -/// based on X86MachObjectWriter::recordScatteredRelocation -/// and ARMMachObjectWriter::recordScatteredRelocation -bool PPCMachObjectWriter::recordScatteredRelocation( - MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, - unsigned Log2Size, uint64_t &FixedValue) { - // caller already computes these, can we just pass and reuse? - const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); - const MCFixupKind FK = Fixup.getKind(); - const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK); - const unsigned Type = getRelocType(Target, FK, IsPCRel); - - // Is this a local or SECTDIFF relocation entry? - // SECTDIFF relocation entries have symbol subtractions, - // and require two entries, the first for the add-symbol value, - // the second for the subtract-symbol value. - - // See <reloc.h>. - const MCSymbol *A = &Target.getSymA()->getSymbol(); - - if (!A->getFragment()) - report_fatal_error("symbol '" + A->getName() + - "' can not be undefined in a subtraction expression"); - - uint32_t Value = Writer->getSymbolAddress(*A, Layout); - uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent()); - FixedValue += SecAddr; - uint32_t Value2 = 0; - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - const MCSymbol *SB = &B->getSymbol(); - - if (!SB->getFragment()) - report_fatal_error("symbol '" + SB->getName() + - "' can not be undefined in a subtraction expression"); - - // FIXME: is Type correct? see include/llvm/BinaryFormat/MachO.h - Value2 = Writer->getSymbolAddress(*SB, Layout); - FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent()); - } - // FIXME: does FixedValue get used?? - - // Relocations are written out in reverse order, so the PAIR comes first. - if (Type == MachO::PPC_RELOC_SECTDIFF || - Type == MachO::PPC_RELOC_HI16_SECTDIFF || - Type == MachO::PPC_RELOC_LO16_SECTDIFF || - Type == MachO::PPC_RELOC_HA16_SECTDIFF || - Type == MachO::PPC_RELOC_LO14_SECTDIFF || - Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) { - // X86 had this piece, but ARM does not - // If the offset is too large to fit in a scattered relocation, - // we're hosed. It's an unfortunate limitation of the MachO format. - if (FixupOffset > 0xffffff) { - char Buffer[32]; - format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer)); - Asm.getContext().reportError(Fixup.getLoc(), - Twine("Section too large, can't encode " - "r_address (") + - Buffer + ") into 24 bits of scattered " - "relocation entry."); - return false; - } - - // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()? - // see PPCMCExpr::evaluateAsRelocatableImpl() - uint32_t other_half = 0; - switch (Type) { - case MachO::PPC_RELOC_LO16_SECTDIFF: - other_half = (FixedValue >> 16) & 0xffff; - // applyFixupOffset longer extracts the high part because it now assumes - // this was already done. - // It looks like this is not true for the FixedValue needed with Mach-O - // relocs. - // So we need to adjust FixedValue again here. - FixedValue &= 0xffff; - break; - case MachO::PPC_RELOC_HA16_SECTDIFF: - other_half = FixedValue & 0xffff; - FixedValue = - ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff; - break; - case MachO::PPC_RELOC_HI16_SECTDIFF: - other_half = FixedValue & 0xffff; - FixedValue = (FixedValue >> 16) & 0xffff; - break; - default: - llvm_unreachable("Invalid PPC scattered relocation type."); - break; - } - - MachO::any_relocation_info MRE; - makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR, - Log2Size, IsPCRel, Value2); - Writer->addRelocation(nullptr, Fragment->getParent(), MRE); - } else { - // If the offset is more than 24-bits, it won't fit in a scattered - // relocation offset field, so we fall back to using a non-scattered - // relocation. This is a bit risky, as if the offset reaches out of - // the block and the linker is doing scattered loading on this - // symbol, things can go badly. - // - // Required for 'as' compatibility. - if (FixupOffset > 0xffffff) - return false; - } - MachO::any_relocation_info MRE; - makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value); - Writer->addRelocation(nullptr, Fragment->getParent(), MRE); - return true; -} - -// see PPCELFObjectWriter for a general outline of cases -void PPCMachObjectWriter::RecordPPCRelocation( - MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - const MCFixupKind FK = Fixup.getKind(); // unsigned - const unsigned Log2Size = getFixupKindLog2Size(FK); - const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK); - const unsigned RelocType = getRelocType(Target, FK, IsPCRel); - - // If this is a difference or a defined symbol plus an offset, then we need a - // scattered relocation entry. Differences always require scattered - // relocations. - if (Target.getSymB() && - // Q: are branch targets ever scattered? - RelocType != MachO::PPC_RELOC_BR24 && - RelocType != MachO::PPC_RELOC_BR14) { - recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target, - Log2Size, FixedValue); - return; - } - - // this doesn't seem right for RIT_PPC_BR24 - // Get the symbol data, if any. - const MCSymbol *A = nullptr; - if (Target.getSymA()) - A = &Target.getSymA()->getSymbol(); - - // See <reloc.h>. - const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup); - unsigned Index = 0; - unsigned Type = RelocType; - - const MCSymbol *RelSymbol = nullptr; - if (Target.isAbsolute()) { // constant - // SymbolNum of 0 indicates the absolute section. - // - // FIXME: Currently, these are never generated (see code below). I cannot - // find a case where they are actually emitted. - report_fatal_error("FIXME: relocations to absolute targets " - "not yet implemented"); - // the above line stolen from ARM, not sure - } else { - // Resolve constant variables. - if (A->isVariable()) { - int64_t Res; - if (A->getVariableValue()->evaluateAsAbsolute( - Res, Layout, Writer->getSectionAddressMap())) { - FixedValue = Res; - return; - } - } - - // Check whether we need an external or internal relocation. - if (Writer->doesSymbolRequireExternRelocation(*A)) { - RelSymbol = A; - // For external relocations, make sure to offset the fixup value to - // compensate for the addend of the symbol address, if it was - // undefined. This occurs with weak definitions, for example. - if (!A->isUndefined()) - FixedValue -= Layout.getSymbolOffset(*A); - } else { - // The index is the section ordinal (1-based). - const MCSection &Sec = A->getSection(); - Index = Sec.getOrdinal() + 1; - FixedValue += Writer->getSectionAddress(&Sec); - } - if (IsPCRel) - FixedValue -= Writer->getSectionAddress(Fragment->getParent()); - } - - // struct relocation_info (8 bytes) - MachO::any_relocation_info MRE; - makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, false, Type); - Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); -} - -std::unique_ptr<MCObjectTargetWriter> -llvm::createPPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, - uint32_t CPUSubtype) { - return std::make_unique<PPCMachObjectWriter>(Is64Bit, CPUType, CPUSubtype); -} diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp index 7fdbb8990b553..d672d54772e0a 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -7,16 +7,26 @@ // //===----------------------------------------------------------------------===// -#include "PPCMCTargetDesc.h" +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" using namespace llvm; namespace { class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { + static constexpr uint8_t SignBitMask = 0x80; public: PPCXCOFFObjectWriter(bool Is64Bit); + + std::pair<uint8_t, uint8_t> + getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel) const override; }; } // end anonymous namespace @@ -27,3 +37,40 @@ std::unique_ptr<MCObjectTargetWriter> llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit); } + +std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( + const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + const MCSymbolRefExpr::VariantKind Modifier = + Target.isAbsolute() ? MCSymbolRefExpr::VK_None + : Target.getSymA()->getKind(); + // People from AIX OS team says AIX link editor does not care about + // the sign bit in the relocation entry "most" of the time. + // The system assembler seems to set the sign bit on relocation entry + // based on similar property of IsPCRel. So we will do the same here. + // TODO: More investigation on how assembler decides to set the sign + // bit, and we might want to match that. + const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u; + + // The magic number we use in SignAndSize has a strong relationship with + // the corresponding MCFixupKind. In most cases, it's the MCFixupKind + // number - 1, because SignAndSize encodes the bit length being + // relocated minus 1. + switch ((unsigned)Fixup.getKind()) { + default: + report_fatal_error("Unimplemented fixup kind."); + case PPC::fixup_ppc_half16: + switch (Modifier) { + default: + report_fatal_error("Unsupported modifier for half16 fixup."); + case MCSymbolRefExpr::VK_None: + return {XCOFF::RelocationType::R_TOC, EncodedSignednessIndicator | 15}; + } + break; + case PPC::fixup_ppc_br24: + // Branches are 4 byte aligned, so the 24 bits we encode in + // the instruction actually represents a 26 bit offset. + return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; + case FK_Data_4: + return {XCOFF::RelocationType::R_POS, EncodedSignednessIndicator | 31}; + } +} |