[AIX][Power10] Restrict prefixed instructions from crossing the 64byte boundary

This patch adds the support to restrict prefixed instruction from
crossing the 64 byte boundary:
- Add the infrastructure to register a custom XCOFF streamer
- Add a custom XCOFF streamer for PowerPC 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.

Reviewed By: stefanp

Differential Revision: https://reviews.llvm.org/D101107
This commit is contained in:
Victor Huang 2021-04-22 11:00:28 -05:00
parent 21da04f701
commit 241c2da406
6 changed files with 227 additions and 8 deletions

View File

@ -183,6 +183,12 @@ public:
std::unique_ptr<MCAsmBackend> &&TAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using XCOFFStreamerCtorTy =
MCStreamer *(*)(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S);
using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)(
MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint,
@ -270,6 +276,7 @@ private:
MachOStreamerCtorTy MachOStreamerCtorFn = nullptr;
ELFStreamerCtorTy ELFStreamerCtorFn = nullptr;
WasmStreamerCtorTy WasmStreamerCtorFn = nullptr;
XCOFFStreamerCtorTy XCOFFStreamerCtorFn = nullptr;
/// Construction function for this target's null TargetStreamer, if
/// registered (default = nullptr).
@ -513,6 +520,10 @@ public:
case Triple::GOFF:
report_fatal_error("GOFF MCObjectStreamer not implemented yet");
case Triple::XCOFF:
if (XCOFFStreamerCtorFn)
S = XCOFFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
std::move(Emitter), RelaxAll);
else
S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW),
std::move(Emitter), RelaxAll);
break;
@ -868,6 +879,10 @@ struct TargetRegistry {
T.WasmStreamerCtorFn = Fn;
}
static void RegisterXCOFFStreamer(Target &T, Target::XCOFFStreamerCtorTy Fn) {
T.XCOFFStreamerCtorFn = Fn;
}
static void RegisterNullTargetStreamer(Target &T,
Target::NullTargetStreamerCtorTy Fn) {
T.NullTargetStreamerCtorFn = Fn;

View File

@ -9,6 +9,7 @@ add_llvm_component_library(LLVMPowerPCDesc
PPCELFObjectWriter.cpp
PPCXCOFFObjectWriter.cpp
PPCELFStreamer.cpp
PPCXCOFFStreamer.cpp
LINK_COMPONENTS
MC

View File

@ -15,6 +15,7 @@
#include "MCTargetDesc/PPCMCAsmInfo.h"
#include "PPCELFStreamer.h"
#include "PPCTargetStreamer.h"
#include "PPCXCOFFStreamer.h"
#include "TargetInfo/PowerPCTargetInfo.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
@ -112,15 +113,23 @@ static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI,
return MAI;
}
static MCStreamer *createPPCMCStreamer(const Triple &T, MCContext &Context,
static MCStreamer *
createPPCELFStreamer(const Triple &T, MCContext &Context,
std::unique_ptr<MCAsmBackend> &&MAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter,
bool RelaxAll) {
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll) {
return createPPCELFStreamer(Context, std::move(MAB), std::move(OW),
std::move(Emitter));
}
static MCStreamer *createPPCXCOFFStreamer(
const Triple &T, MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll) {
return createPPCXCOFFStreamer(Context, std::move(MAB), std::move(OW),
std::move(Emitter));
}
namespace {
class PPCTargetAsmStreamer : public PPCTargetStreamer {
@ -377,7 +386,10 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTargetMC() {
TargetRegistry::RegisterMCAsmBackend(*T, createPPCAsmBackend);
// Register the elf streamer.
TargetRegistry::RegisterELFStreamer(*T, createPPCMCStreamer);
TargetRegistry::RegisterELFStreamer(*T, createPPCELFStreamer);
// Register the XCOFF streamer.
TargetRegistry::RegisterXCOFFStreamer(*T, createPPCXCOFFStreamer);
// Register the object target streamer.
TargetRegistry::RegisterObjectTargetStreamer(*T,

View File

@ -0,0 +1,78 @@
//===-------- PPCXCOFFStreamer.cpp - XCOFF 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 MCXCOFFStreamer for PowerPC.
//
// The purpose of the custom XCOFF 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 aligning anything that is within 4 bytes of the boundary we can
// guarantee that the 8 byte instructions do not cross that boundary.
//
//===----------------------------------------------------------------------===//
#include "PPCXCOFFStreamer.h"
#include "PPCMCCodeEmitter.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionXCOFF.h"
#include "llvm/MC/MCSymbolXCOFF.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
PPCXCOFFStreamer::PPCXCOFFStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> MAB,
std::unique_ptr<MCObjectWriter> OW,
std::unique_ptr<MCCodeEmitter> Emitter)
: MCXCOFFStreamer(Context, std::move(MAB), std::move(OW),
std::move(Emitter)) {}
void PPCXCOFFStreamer::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.
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.
MCXCOFFStreamer::emitInstruction(Inst, STI);
}
void PPCXCOFFStreamer::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)) {
MCXCOFFStreamer::emitInstruction(Inst, STI);
return;
}
emitPrefixedInstruction(Inst, STI);
}
MCXCOFFStreamer *
llvm::createPPCXCOFFStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> MAB,
std::unique_ptr<MCObjectWriter> OW,
std::unique_ptr<MCCodeEmitter> Emitter) {
return new PPCXCOFFStreamer(Context, std::move(MAB), std::move(OW),
std::move(Emitter));
}

View File

@ -0,0 +1,39 @@
//===- PPCXCOFFStreamer.h - XCOFF 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 MCXCOFFStreamer for PowerPC.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_PPC_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H
#define LLVM_LIB_TARGET_PPC_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H
#include "llvm/MC/MCXCOFFStreamer.h"
namespace llvm {
class PPCXCOFFStreamer : public MCXCOFFStreamer {
public:
PPCXCOFFStreamer(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;
private:
void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI);
};
MCXCOFFStreamer *createPPCXCOFFStreamer(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_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H

View File

@ -0,0 +1,74 @@
# RUN: llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc-ibm-aix-xcoff -x mir -verify-machineinstrs \
# RUN: -xcoff-traceback-table=false -start-before=ppc-branch-select -filetype=obj -o %t.o < %s
# RUN: llvm-objdump -D -r --mcpu=pwr10 %t.o | FileCheck --check-prefix=DIS %s
---
name: aix-prefixed-instruction-boundary
alignment: 16
tracksRegLiveness: true
liveins:
- { reg: '$x3', virtual-reg: '' }
body: |
bb.0.entry:
liveins: $x3
renamable $x3 = LI8 2
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = PADDI8 $x3, 13
renamable $x3 = LI8 2
renamable $x3 = PADDI8 $x3, 13
BLR8 implicit $lr8, implicit $rm, implicit killed $x3
...
# DIS: Disassembly of section .text:
# DIS: 00000000 <.text>:
# DIS-NEXT: 0: 38 60 00 02 li 3, 2
# DIS-NEXT: 4: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: c: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 14: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 1c: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 24: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 2c: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 34: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 3c: 60 00 00 00 nop
# DIS-NEXT: 40: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 48: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 50: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 58: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 60: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 68: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 70: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 78: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 80: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 88: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 90: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: 98: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: a0: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: a8: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: b0: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: b8: 38 60 00 02 li 3, 2
# DIS-NEXT: bc: 60 00 00 00 nop
# DIS-NEXT: c0: 06 00 00 00 38 63 00 0d paddi 3, 3, 13, 0
# DIS-NEXT: c8: 4e 80 00 20 blr