[llvm] f00be8d - [PowerPC][Future] Prefixed Instructions 64 Byte Boundary Support

Stefan Pintilie via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 30 04:56:16 PST 2020


Author: Stefan Pintilie
Date: 2020-01-30T06:52:30-06:00
New Revision: f00be8da62b8169c6548f32834f307bb520e8754

URL: https://github.com/llvm/llvm-project/commit/f00be8da62b8169c6548f32834f307bb520e8754
DIFF: https://github.com/llvm/llvm-project/commit/f00be8da62b8169c6548f32834f307bb520e8754.diff

LOG: [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

Added: 
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h
    llvm/test/MC/PowerPC/ppc64-prefix-align-labels.s
    llvm/test/MC/PowerPC/ppc64-prefix-align.s

Modified: 
    llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
    llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
    llvm/lib/Target/PowerPC/PPCInstrInfo.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
index 4bc9f2a41fde..c5f5e02b772e 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
@@ -9,4 +9,5 @@ add_llvm_component_library(LLVMPowerPCDesc
   PPCMachObjectWriter.cpp
   PPCELFObjectWriter.cpp
   PPCXCOFFObjectWriter.cpp
+  PPCELFStreamer.cpp
   )

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp
new file mode 100644
index 000000000000..8290b0655b9b
--- /dev/null
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/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));
+}

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h
new file mode 100644
index 000000000000..723d1538a637
--- /dev/null
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h
@@ -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

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
index b9b705d52306..86c93ab60f3e 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
@@ -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"

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
index 9acdd941178b..a7950be9812c 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
@@ -103,6 +103,9 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
   // 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

diff  --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
index cbfb8e2ff282..a1717e3973b8 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
@@ -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);

diff  --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h
index 0e417e486608..8c904025d6a7 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h
@@ -189,6 +189,10 @@ class PPCInstrInfo : public PPCGenInstrInfo {
   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,

diff  --git a/llvm/test/MC/PowerPC/ppc64-prefix-align-labels.s b/llvm/test/MC/PowerPC/ppc64-prefix-align-labels.s
new file mode 100644
index 000000000000..e58418f761fb
--- /dev/null
+++ b/llvm/test/MC/PowerPC/ppc64-prefix-align-labels.s
@@ -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
+

diff  --git a/llvm/test/MC/PowerPC/ppc64-prefix-align.s b/llvm/test/MC/PowerPC/ppc64-prefix-align.s
new file mode 100644
index 000000000000..5dd62482567f
--- /dev/null
+++ b/llvm/test/MC/PowerPC/ppc64-prefix-align.s
@@ -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
+
+
+


        


More information about the llvm-commits mailing list