Commit f00be8da authored by Stefan Pintilie's avatar Stefan Pintilie
Browse files

[PowerPC][Future] Prefixed Instructions 64 Byte Boundary Support

A known limitation for Future CPU is that the new prefixed instructions may
not cross 64 Byte boundaries.

All instructions are already 4 byte aligned so the only situation where this
can occur is when the prefix is in one 64 byte block and the instruction that
is prefixed is at the top of the next 64 byte block. To fix this case
PPCELFStreamer was added to intercept EmitInstruction. When a prefixed
instruction is emitted we try to align it to 64 Bytes by adding a maximum of
4 bytes. If the prefixed instruction crosses the 64 Byte boundary then the
alignment would trigger and a 4 byte nop would be added to push the
instruction into the next 64 byte block.

Differential Revision: https://reviews.llvm.org/D72570
parent 258d8dd7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,4 +9,5 @@ add_llvm_component_library(LLVMPowerPCDesc
  PPCMachObjectWriter.cpp
  PPCELFObjectWriter.cpp
  PPCXCOFFObjectWriter.cpp
  PPCELFStreamer.cpp
  )
+108 −0
Original line number Diff line number Diff line
//===-------- 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));
}
+52 −0
Original line number Diff line number Diff line
//===- 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
+6 −0
Original line number Diff line number Diff line
@@ -347,5 +347,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"
+3 −0
Original line number Diff line number Diff line
@@ -103,6 +103,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
Loading