forked from OSchip/llvm-project
[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
This commit is contained in:
parent
258d8dd76a
commit
f00be8da62
|
@ -9,4 +9,5 @@ add_llvm_component_library(LLVMPowerPCDesc
|
|||
PPCMachObjectWriter.cpp
|
||||
PPCELFObjectWriter.cpp
|
||||
PPCXCOFFObjectWriter.cpp
|
||||
PPCELFStreamer.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
//===-------- 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));
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//===- 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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
@ -97,6 +101,15 @@ static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI,
|
|||
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 {
|
||||
|
@ -313,6 +326,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);
|
||||
|
|
|
@ -189,6 +189,10 @@ public:
|
|||
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,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# 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
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# 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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue