PPCMachObjectWriter.cpp
PPCELFObjectWriter.cpp
PPCXCOFFObjectWriter.cpp
+ PPCELFStreamer.cpp
)
--- /dev/null
+//===-------- 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::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;
+ }
+
+ // 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::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));
+}
--- /dev/null
+//===- 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;
+};
+
+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
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"
// 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
#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"
#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"
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 {
// 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);
bool isXFormMemOp(unsigned Opcode) const {
return get(Opcode).TSFlags & PPCII::XFormMemOp;
}
+ bool isPrefixed(unsigned Opcode) const {
+ return get(Opcode).TSFlags & PPCII::Prefixed;
+ }
+
static bool isSameClassPhysRegCopy(unsigned Opcode) {
unsigned CopyOpcodes[] =
{ PPC::OR, PPC::OR8, PPC::FMR, PPC::VOR, PPC::XXLOR, PPC::XXLORf,
--- /dev/null
+# RUN: llvm-mc -triple powerpc64-unknown-linux-gnu --filetype=obj -o - %s | \
+# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-BE %s
+# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu --filetype=obj -o - %s | \
+# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-LE %s
+
+# The purpose of this test is to check that when an alignment nop is added
+# it is added correctly with resepect to the labels in the .s file.
+# The test contains 3 labels at the end (1:, 2:, 3:). The label 2: is on the
+# same line as an unaligned 8 byte instruction. The desired behaviour is to have
+# the alignment nop inserted after the 1: label but before the 2: label. The
+# branch to 1: should jump to 3c: and the branch to 2: should jump to 40:.
+
+ .text
+_start:
+ b 1f;
+ b 2f;
+ b 3f;
+# CHECK-BE: 0: 48 00 00 3c
+# CHECK-BE-NEXT: 4: 48 00 00 3c
+# CHECK-BE-NEXT: 8: 48 00 00 40
+# CHECK-LE: 0: 3c 00 00 48
+# CHECK-LE-NEXT: 4: 3c 00 00 48
+# CHECK-LE-NEXT: 8: 40 00 00 48
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+ trap
+1:
+2: paddi 1, 2, 8589934576, 0 # 8 Byte Instruction
+3:
+ blr
+# CHECK-BE: 3c: 60 00 00 00 nop
+# CHECK-BE-NEXT: 40: 06 01 ff ff
+# CHECK-BE-NEXT: 44: 38 22 ff f0
+# CHECK-BE-NEXT: 48: 4e 80 00 20
+# CHECK-LE: 3c: 00 00 00 60 nop
+# CHECK-LE-NEXT: 40: ff ff 01 06
+# CHECK-LE-NEXT: 44: f0 ff 22 38
+# CHECK-LE-NEXT: 48: 20 00 80 4e
+
--- /dev/null
+# RUN: llvm-mc -triple powerpc64-unknown-linux-gnu --filetype=obj -o - %s | \
+# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-BE %s
+# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu --filetype=obj -o - %s | \
+# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-LE %s
+
+# The purpose of this test is to make sure that 8 byte instructions do not
+# cross 64 byte boundaries. If an 8 byte instruction is about to cross such
+# a boundary then a nop should be added so that the 8 byte instruction starts
+# 4 bytes later and does not cross the boundary.
+# This instruction is 8 bytes: paddi 1, 2, 8589934576, 0
+# This instruction is 4 bytes: addi 2, 3, 15
+# The branches are also 4 bytes each: beq 0, LAB1 (or LAB2)
+
+beq 0, LAB1 # 4
+beq 1, LAB2 # 8
+# CHECK-BE: 0: 41 82 00 c0 bt 2, .+192
+# CHECK-BE-NEXT: 4: 41 86 00 f8 bt 6, .+248
+# CHECK-LE: 0: c0 00 82 41 bt 2, .+192
+# CHECK-LE-NEXT: 4: f8 00 86 41 bt 6, .+248
+paddi 1, 2, 8589934576, 0 # 16
+paddi 1, 2, 8589934576, 0 # 24
+paddi 1, 2, 8589934576, 0 # 32
+paddi 1, 2, 8589934576, 0 # 40
+paddi 1, 2, 8589934576, 0 # 48
+paddi 1, 2, 8589934576, 0 # 56
+addi 2, 3, 15 # 60
+# Below the lines 40: and 44: contain the 8 byte instruction.
+# We check to make sure that the nop is added at 3c: so that the 8 byte
+# instruction can start at 40: which is 64 bytes aligned.
+# CHECK-BE: 38: 38 43 00 0f
+# CHECK-BE-NEXT: 3c: 60 00 00 00 nop
+# CHECK-BE-NEXT: 40: 06 01 ff ff
+# CHECK-BE-NEXT: 44: 38 22 ff f0
+# CHECK-LE: 38: 0f 00 43 38
+# CHECK-LE-NEXT: 3c: 00 00 00 60 nop
+# CHECK-LE-NEXT: 40: ff ff 01 06
+# CHECK-LE-NEXT: 44: f0 ff 22 38
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0 # 64
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+addi 2, 3, 15 # 60
+# CHECK-BE: b8: 38 43 00 0f
+# CHECK-BE-NEXT: bc: 60 00 00 00 nop
+# CHECK-BE: LAB1:
+# CHECK-BE-NEXT: c0: 06 01 ff ff
+# CHECK-BE-NEXT: c4: 38 22 ff f0
+# CHECK-LE: b8: 0f 00 43 38
+# CHECK-LE-NEXT: bc: 00 00 00 60 nop
+# CHECK-LE: LAB1:
+# CHECK-LE-NEXT: c0: ff ff 01 06
+# CHECK-LE-NEXT: c4: f0 ff 22 38
+LAB1: paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+paddi 1, 2, 8589934576, 0
+addi 2, 3, 15 # 60
+# CHECK-BE: f8: 38 43 00 0f
+# CHECK-BE: LAB2:
+# CHECK-BE-NEXT: fc: 60 00 00 00 nop
+# CHECK-BE-NEXT: 100: 06 01 ff ff
+# CHECK-BE-NEXT: 104: 38 22 ff f0
+# CHECK-LE: f8: 0f 00 43 38
+# CHECK-LE: LAB2:
+# CHECK-LE-NEXT: fc: 00 00 00 60 nop
+# CHECK-LE-NEXT: 100: ff ff 01 06
+# CHECK-LE-NEXT: 104: f0 ff 22 38
+LAB2:
+ paddi 1, 2, 8589934576, 0
+
+
+