Skip to content

Commit f00be8d

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
1 parent 258d8dd commit f00be8d

File tree

9 files changed

+324
-0
lines changed

9 files changed

+324
-0
lines changed

llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ add_llvm_component_library(LLVMPowerPCDesc
99
PPCMachObjectWriter.cpp
1010
PPCELFObjectWriter.cpp
1111
PPCXCOFFObjectWriter.cpp
12+
PPCELFStreamer.cpp
1213
)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This is a custom MCELFStreamer for PowerPC.
11+
//
12+
// The purpose of the custom ELF streamer is to allow us to intercept
13+
// instructions as they are being emitted and align all 8 byte instructions
14+
// to a 64 byte boundary if required (by adding a 4 byte nop). This is important
15+
// because 8 byte instructions are not allowed to cross 64 byte boundaries
16+
// and by aliging anything that is within 4 bytes of the boundary we can
17+
// guarantee that the 8 byte instructions do not cross that boundary.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
22+
#include "PPCELFStreamer.h"
23+
#include "PPCInstrInfo.h"
24+
#include "PPCMCCodeEmitter.h"
25+
#include "llvm/BinaryFormat/ELF.h"
26+
#include "llvm/MC/MCAsmBackend.h"
27+
#include "llvm/MC/MCAssembler.h"
28+
#include "llvm/MC/MCCodeEmitter.h"
29+
#include "llvm/MC/MCContext.h"
30+
#include "llvm/MC/MCInst.h"
31+
#include "llvm/MC/MCInstrDesc.h"
32+
#include "llvm/MC/MCObjectWriter.h"
33+
#include "llvm/MC/MCSymbolELF.h"
34+
#include "llvm/Support/Casting.h"
35+
#include "llvm/Support/SourceMgr.h"
36+
37+
using namespace llvm;
38+
39+
PPCELFStreamer::PPCELFStreamer(MCContext &Context,
40+
std::unique_ptr<MCAsmBackend> MAB,
41+
std::unique_ptr<MCObjectWriter> OW,
42+
std::unique_ptr<MCCodeEmitter> Emitter)
43+
: MCELFStreamer(Context, std::move(MAB), std::move(OW),
44+
std::move(Emitter)), LastLabel(NULL) {
45+
}
46+
47+
void PPCELFStreamer::EmitInstruction(const MCInst &Inst,
48+
const MCSubtargetInfo &STI) {
49+
PPCMCCodeEmitter *Emitter =
50+
static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr());
51+
52+
// Special handling is only for prefixed instructions.
53+
if (!Emitter->isPrefixedInstruction(Inst)) {
54+
MCELFStreamer::EmitInstruction(Inst, STI);
55+
return;
56+
}
57+
58+
// Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is
59+
// before the boundary and the remaining 4-bytes are after the boundary). In
60+
// order to achieve this, a nop is added prior to any such boundary-crossing
61+
// prefixed instruction. Align to 64 bytes if possible but add a maximum of 4
62+
// bytes when trying to do that. If alignment requires adding more than 4
63+
// bytes then the instruction won't be aligned. When emitting a code alignment
64+
// a new fragment is created for this alignment. This fragment will contain
65+
// all of the nops required as part of the alignment operation. In the cases
66+
// when no nops are added then The fragment is still created but it remains
67+
// empty.
68+
EmitCodeAlignment(64, 4);
69+
70+
// Emit the instruction.
71+
// Since the previous emit created a new fragment then adding this instruction
72+
// also forces the addition of a new fragment. Inst is now the first
73+
// instruction in that new fragment.
74+
MCELFStreamer::EmitInstruction(Inst, STI);
75+
76+
// The above instruction is forced to start a new fragment because it
77+
// comes after a code alignment fragment. Get that new fragment.
78+
MCFragment *InstructionFragment = getCurrentFragment();
79+
SMLoc InstLoc = Inst.getLoc();
80+
// Check if there was a last label emitted.
81+
if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() &&
82+
InstLoc.isValid()) {
83+
const SourceMgr *SourceManager = getContext().getSourceManager();
84+
unsigned InstLine = SourceManager->FindLineNumber(InstLoc);
85+
unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc);
86+
// If the Label and the Instruction are on the same line then move the
87+
// label to the top of the fragment containing the aligned instruction that
88+
// was just added.
89+
if (InstLine == LabelLine) {
90+
AssignFragment(LastLabel, InstructionFragment);
91+
LastLabel->setOffset(0);
92+
}
93+
}
94+
}
95+
96+
void PPCELFStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
97+
LastLabel = Symbol;
98+
LastLabelLoc = Loc;
99+
MCELFStreamer::EmitLabel(Symbol);
100+
}
101+
102+
MCELFStreamer *llvm::createPPCELFStreamer(
103+
MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
104+
std::unique_ptr<MCObjectWriter> OW,
105+
std::unique_ptr<MCCodeEmitter> Emitter) {
106+
return new PPCELFStreamer(Context, std::move(MAB), std::move(OW),
107+
std::move(Emitter));
108+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===- PPCELFStreamer.h - ELF Object Output --------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This is a custom MCELFStreamer for PowerPC.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H
15+
#define LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H
16+
17+
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/MC/MCELFStreamer.h"
19+
#include <memory>
20+
21+
namespace llvm {
22+
23+
class MCAsmBackend;
24+
class MCCodeEmitter;
25+
class MCContext;
26+
class MCSubtargetInfo;
27+
28+
class PPCELFStreamer : public MCELFStreamer {
29+
// We need to keep track of the last label we emitted (only one) because
30+
// depending on whether the label is on the same line as an aligned
31+
// instruction or not, the label may refer to the instruction or the nop.
32+
MCSymbol *LastLabel;
33+
SMLoc LastLabelLoc;
34+
35+
public:
36+
PPCELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
37+
std::unique_ptr<MCObjectWriter> OW,
38+
std::unique_ptr<MCCodeEmitter> Emitter);
39+
40+
void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
41+
42+
// EmitLabel updates LastLabel and LastLabelLoc when a new label is emitted.
43+
void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
44+
};
45+
46+
MCELFStreamer *createPPCELFStreamer(MCContext &Context,
47+
std::unique_ptr<MCAsmBackend> MAB,
48+
std::unique_ptr<MCObjectWriter> OW,
49+
std::unique_ptr<MCCodeEmitter> Emitter);
50+
} // end namespace llvm
51+
52+
#endif // LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H

llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,5 +347,11 @@ unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const {
347347
return Desc.getSize();
348348
}
349349

350+
bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const {
351+
unsigned Opcode = MI.getOpcode();
352+
const PPCInstrInfo *InstrInfo = static_cast<const PPCInstrInfo*>(&MCII);
353+
return InstrInfo->isPrefixed(Opcode);
354+
}
355+
350356
#define ENABLE_INSTR_PREDICATE_VERIFIER
351357
#include "PPCGenMCCodeEmitter.inc"

llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
103103
// Get the number of bytes used to encode the given MCInst.
104104
unsigned getInstSizeInBytes(const MCInst &MI) const;
105105

106+
// Is this instruction a prefixed instruction.
107+
bool isPrefixedInstruction(const MCInst &MI) const;
108+
106109
private:
107110
FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const;
108111
void

llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,22 @@
1313
#include "MCTargetDesc/PPCMCTargetDesc.h"
1414
#include "MCTargetDesc/PPCInstPrinter.h"
1515
#include "MCTargetDesc/PPCMCAsmInfo.h"
16+
#include "PPCELFStreamer.h"
1617
#include "PPCTargetStreamer.h"
1718
#include "TargetInfo/PowerPCTargetInfo.h"
1819
#include "llvm/ADT/SmallPtrSet.h"
1920
#include "llvm/ADT/StringRef.h"
2021
#include "llvm/ADT/Triple.h"
2122
#include "llvm/BinaryFormat/ELF.h"
2223
#include "llvm/MC/MCAssembler.h"
24+
#include "llvm/MC/MCAsmBackend.h"
25+
#include "llvm/MC/MCCodeEmitter.h"
2326
#include "llvm/MC/MCContext.h"
2427
#include "llvm/MC/MCDwarf.h"
2528
#include "llvm/MC/MCELFStreamer.h"
2629
#include "llvm/MC/MCExpr.h"
2730
#include "llvm/MC/MCInstrInfo.h"
31+
#include "llvm/MC/MCObjectWriter.h"
2832
#include "llvm/MC/MCRegisterInfo.h"
2933
#include "llvm/MC/MCStreamer.h"
3034
#include "llvm/MC/MCSubtargetInfo.h"
@@ -97,6 +101,15 @@ static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI,
97101
return MAI;
98102
}
99103

104+
static MCStreamer *createPPCMCStreamer(const Triple &T, MCContext &Context,
105+
std::unique_ptr<MCAsmBackend> &&MAB,
106+
std::unique_ptr<MCObjectWriter> &&OW,
107+
std::unique_ptr<MCCodeEmitter> &&Emitter,
108+
bool RelaxAll) {
109+
return createPPCELFStreamer(Context, std::move(MAB), std::move(OW),
110+
std::move(Emitter));
111+
}
112+
100113
namespace {
101114

102115
class PPCTargetAsmStreamer : public PPCTargetStreamer {
@@ -313,6 +326,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTargetMC() {
313326
// Register the asm backend.
314327
TargetRegistry::RegisterMCAsmBackend(*T, createPPCAsmBackend);
315328

329+
// Register the elf streamer.
330+
TargetRegistry::RegisterELFStreamer(*T, createPPCMCStreamer);
331+
316332
// Register the object target streamer.
317333
TargetRegistry::RegisterObjectTargetStreamer(*T,
318334
createObjectTargetStreamer);

llvm/lib/Target/PowerPC/PPCInstrInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ class PPCInstrInfo : public PPCGenInstrInfo {
189189
bool isXFormMemOp(unsigned Opcode) const {
190190
return get(Opcode).TSFlags & PPCII::XFormMemOp;
191191
}
192+
bool isPrefixed(unsigned Opcode) const {
193+
return get(Opcode).TSFlags & PPCII::Prefixed;
194+
}
195+
192196
static bool isSameClassPhysRegCopy(unsigned Opcode) {
193197
unsigned CopyOpcodes[] =
194198
{ PPC::OR, PPC::OR8, PPC::FMR, PPC::VOR, PPC::XXLOR, PPC::XXLORf,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# RUN: llvm-mc -triple powerpc64-unknown-linux-gnu --filetype=obj -o - %s | \
2+
# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-BE %s
3+
# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu --filetype=obj -o - %s | \
4+
# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-LE %s
5+
6+
# The purpose of this test is to check that when an alignment nop is added
7+
# it is added correctly with resepect to the labels in the .s file.
8+
# The test contains 3 labels at the end (1:, 2:, 3:). The label 2: is on the
9+
# same line as an unaligned 8 byte instruction. The desired behaviour is to have
10+
# the alignment nop inserted after the 1: label but before the 2: label. The
11+
# branch to 1: should jump to 3c: and the branch to 2: should jump to 40:.
12+
13+
.text
14+
_start:
15+
b 1f;
16+
b 2f;
17+
b 3f;
18+
# CHECK-BE: 0: 48 00 00 3c
19+
# CHECK-BE-NEXT: 4: 48 00 00 3c
20+
# CHECK-BE-NEXT: 8: 48 00 00 40
21+
# CHECK-LE: 0: 3c 00 00 48
22+
# CHECK-LE-NEXT: 4: 3c 00 00 48
23+
# CHECK-LE-NEXT: 8: 40 00 00 48
24+
trap
25+
trap
26+
trap
27+
trap
28+
trap
29+
trap
30+
trap
31+
trap
32+
trap
33+
trap
34+
trap
35+
trap
36+
1:
37+
2: paddi 1, 2, 8589934576, 0 # 8 Byte Instruction
38+
3:
39+
blr
40+
# CHECK-BE: 3c: 60 00 00 00 nop
41+
# CHECK-BE-NEXT: 40: 06 01 ff ff
42+
# CHECK-BE-NEXT: 44: 38 22 ff f0
43+
# CHECK-BE-NEXT: 48: 4e 80 00 20
44+
# CHECK-LE: 3c: 00 00 00 60 nop
45+
# CHECK-LE-NEXT: 40: ff ff 01 06
46+
# CHECK-LE-NEXT: 44: f0 ff 22 38
47+
# CHECK-LE-NEXT: 48: 20 00 80 4e
48+
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# RUN: llvm-mc -triple powerpc64-unknown-linux-gnu --filetype=obj -o - %s | \
2+
# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-BE %s
3+
# RUN: llvm-mc -triple powerpc64le-unknown-linux-gnu --filetype=obj -o - %s | \
4+
# RUN: llvm-objdump -D -r - | FileCheck -check-prefix=CHECK-LE %s
5+
6+
# The purpose of this test is to make sure that 8 byte instructions do not
7+
# cross 64 byte boundaries. If an 8 byte instruction is about to cross such
8+
# a boundary then a nop should be added so that the 8 byte instruction starts
9+
# 4 bytes later and does not cross the boundary.
10+
# This instruction is 8 bytes: paddi 1, 2, 8589934576, 0
11+
# This instruction is 4 bytes: addi 2, 3, 15
12+
# The branches are also 4 bytes each: beq 0, LAB1 (or LAB2)
13+
14+
beq 0, LAB1 # 4
15+
beq 1, LAB2 # 8
16+
# CHECK-BE: 0: 41 82 00 c0 bt 2, .+192
17+
# CHECK-BE-NEXT: 4: 41 86 00 f8 bt 6, .+248
18+
# CHECK-LE: 0: c0 00 82 41 bt 2, .+192
19+
# CHECK-LE-NEXT: 4: f8 00 86 41 bt 6, .+248
20+
paddi 1, 2, 8589934576, 0 # 16
21+
paddi 1, 2, 8589934576, 0 # 24
22+
paddi 1, 2, 8589934576, 0 # 32
23+
paddi 1, 2, 8589934576, 0 # 40
24+
paddi 1, 2, 8589934576, 0 # 48
25+
paddi 1, 2, 8589934576, 0 # 56
26+
addi 2, 3, 15 # 60
27+
# Below the lines 40: and 44: contain the 8 byte instruction.
28+
# We check to make sure that the nop is added at 3c: so that the 8 byte
29+
# instruction can start at 40: which is 64 bytes aligned.
30+
# CHECK-BE: 38: 38 43 00 0f
31+
# CHECK-BE-NEXT: 3c: 60 00 00 00 nop
32+
# CHECK-BE-NEXT: 40: 06 01 ff ff
33+
# CHECK-BE-NEXT: 44: 38 22 ff f0
34+
# CHECK-LE: 38: 0f 00 43 38
35+
# CHECK-LE-NEXT: 3c: 00 00 00 60 nop
36+
# CHECK-LE-NEXT: 40: ff ff 01 06
37+
# CHECK-LE-NEXT: 44: f0 ff 22 38
38+
paddi 1, 2, 8589934576, 0
39+
paddi 1, 2, 8589934576, 0
40+
paddi 1, 2, 8589934576, 0
41+
paddi 1, 2, 8589934576, 0
42+
paddi 1, 2, 8589934576, 0
43+
paddi 1, 2, 8589934576, 0
44+
paddi 1, 2, 8589934576, 0
45+
paddi 1, 2, 8589934576, 0 # 64
46+
paddi 1, 2, 8589934576, 0
47+
paddi 1, 2, 8589934576, 0
48+
paddi 1, 2, 8589934576, 0
49+
paddi 1, 2, 8589934576, 0
50+
paddi 1, 2, 8589934576, 0
51+
paddi 1, 2, 8589934576, 0
52+
paddi 1, 2, 8589934576, 0
53+
addi 2, 3, 15 # 60
54+
# CHECK-BE: b8: 38 43 00 0f
55+
# CHECK-BE-NEXT: bc: 60 00 00 00 nop
56+
# CHECK-BE: LAB1:
57+
# CHECK-BE-NEXT: c0: 06 01 ff ff
58+
# CHECK-BE-NEXT: c4: 38 22 ff f0
59+
# CHECK-LE: b8: 0f 00 43 38
60+
# CHECK-LE-NEXT: bc: 00 00 00 60 nop
61+
# CHECK-LE: LAB1:
62+
# CHECK-LE-NEXT: c0: ff ff 01 06
63+
# CHECK-LE-NEXT: c4: f0 ff 22 38
64+
LAB1: paddi 1, 2, 8589934576, 0
65+
paddi 1, 2, 8589934576, 0
66+
paddi 1, 2, 8589934576, 0
67+
paddi 1, 2, 8589934576, 0
68+
paddi 1, 2, 8589934576, 0
69+
paddi 1, 2, 8589934576, 0
70+
paddi 1, 2, 8589934576, 0
71+
addi 2, 3, 15 # 60
72+
# CHECK-BE: f8: 38 43 00 0f
73+
# CHECK-BE: LAB2:
74+
# CHECK-BE-NEXT: fc: 60 00 00 00 nop
75+
# CHECK-BE-NEXT: 100: 06 01 ff ff
76+
# CHECK-BE-NEXT: 104: 38 22 ff f0
77+
# CHECK-LE: f8: 0f 00 43 38
78+
# CHECK-LE: LAB2:
79+
# CHECK-LE-NEXT: fc: 00 00 00 60 nop
80+
# CHECK-LE-NEXT: 100: ff ff 01 06
81+
# CHECK-LE-NEXT: 104: f0 ff 22 38
82+
LAB2:
83+
paddi 1, 2, 8589934576, 0
84+
85+
86+

0 commit comments

Comments
 (0)