[llvm] [BOLT] Add generic VLIW bundle emission infrastructure (PR #200916)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 1 12:46:06 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: Brian Cain (androm3da)
<details>
<summary>Changes</summary>
Add an abstract BundleEmissionState interface to MCPlusBuilder and wire it into BinaryEmitter::emitFunctionBody(). This enables VLIW targets to accumulate instructions into bundles before emission without requiring any changes to per-instruction emitter paths.
* MCPlusBuilder::createBundleEmissionState() returns nullptr by default, making the new code paths zero-overhead no-ops for all existing non-VLIW targets.
* BundleEmissionState has four abstract methods: onBeginBasicBlock, canEmitInstructionLabel, processInstruction, and flush.
* BinaryEmitter tracks a PrevBB pointer to support cross-BB bundle carry detection in targets that split packets at branch boundaries.
* Mid-bundle labels are dropped when canEmitInstructionLabel() returns false, since addresses within an atomically-executing bundle are not meaningful.
---
Full diff: https://github.com/llvm/llvm-project/pull/200916.diff
2 Files Affected:
- (modified) bolt/include/bolt/Core/MCPlusBuilder.h (+51)
- (modified) bolt/lib/Core/BinaryEmitter.cpp (+29-2)
``````````diff
diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h
index 3a840615bec8f..79a020dbd6719 100644
--- a/bolt/include/bolt/Core/MCPlusBuilder.h
+++ b/bolt/include/bolt/Core/MCPlusBuilder.h
@@ -18,6 +18,7 @@
#include "bolt/Core/Relocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/MC/MCAsmBackend.h"
@@ -36,6 +37,7 @@
#include <cassert>
#include <cstdint>
#include <map>
+#include <memory>
#include <optional>
#include <system_error>
#include <unordered_map>
@@ -2516,6 +2518,55 @@ class MCPlusBuilder {
return 2;
}
+ /// State object for targets that emit instructions as bundles (e.g.
+ /// Hexagon VLIW packets). Created per-function by
+ /// createBundleEmissionState().
+ class BundleEmissionState {
+ public:
+ virtual ~BundleEmissionState() = default;
+
+ /// Called before emitting a BB label. Returns true if the pending
+ /// bundle was flushed (or was empty). Returns false if the bundle
+ /// is being carried across the BB boundary.
+ virtual bool
+ onBeginBasicBlock(const BinaryBasicBlock &BB,
+ const BinaryBasicBlock *PrevBB,
+ function_ref<void(const MCInst &)> EmitBundle) = 0;
+
+ /// Returns true if a label can be emitted at this point (i.e. we
+ /// are NOT mid-bundle).
+ virtual bool canEmitInstructionLabel() const = 0;
+
+ /// Process one instruction. Returns true if consumed (emitter
+ /// should not emit it individually).
+ virtual bool
+ processInstruction(MCInst &Inst,
+ function_ref<void(const MCInst &)> EmitBundle) = 0;
+
+ /// Flush remaining instructions at end of fragment.
+ virtual void flush(function_ref<void(const MCInst &)> EmitBundle) = 0;
+ };
+
+ /// Create a bundle emission state for VLIW targets. Returns nullptr
+ /// for targets that emit instructions individually.
+ virtual std::unique_ptr<BundleEmissionState>
+ createBundleEmissionState(MCContext &Ctx) const {
+ return nullptr;
+ }
+
+ /// Return true if the instruction is a .new value consumer that requires
+ /// its producer to be in the same VLIW packet (e.g. Hexagon .new value
+ /// stores and .new compare-and-jump instructions).
+ virtual bool isNewValueConsumer(const MCInst &Inst) const { return false; }
+
+ /// Create a BUNDLE MCInst from a sequence of individual instructions.
+ /// Used by targets that require bundle emission (e.g. Hexagon).
+ virtual MCInst createBundle(MCContext &Ctx, ArrayRef<MCInst> Instrs,
+ bool InnerLoop = false,
+ bool OuterLoop = false) const {
+ llvm_unreachable("not implemented");
+ }
+
// AliasMap caches a mapping of registers to the set of registers that
// alias (are sub or superregs of itself, including itself).
std::vector<BitVector> AliasMap;
diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp
index 6affddafd3bf5..989f4f1f32f20 100644
--- a/bolt/lib/Core/BinaryEmitter.cpp
+++ b/bolt/lib/Core/BinaryEmitter.cpp
@@ -454,18 +454,29 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
BF.duplicateConstantIslands();
}
+ auto BundleState = BC.MIB->createBundleEmissionState(Streamer.getContext());
+ auto EmitViaStreamer = [&](const MCInst &I) {
+ Streamer.emitInstruction(I, *BC.STI);
+ };
+
// Track the first emitted instruction with debug info.
bool FirstInstr = true;
+ BinaryBasicBlock *PrevBB = nullptr;
for (BinaryBasicBlock *const BB : FF) {
if ((opts::AlignBlocks || opts::PreserveBlocksAlignment) &&
BB->getAlignment() > 1)
Streamer.emitCodeAlignment(BB->getAlign(), &*BC.STI,
BB->getAlignmentMaxBytes());
+
+ if (BundleState)
+ BundleState->onBeginBasicBlock(*BB, PrevBB, EmitViaStreamer);
+
Streamer.emitLabel(BB->getLabel());
if (!EmitCodeOnly) {
if (MCSymbol *EntrySymbol = BF.getSecondaryEntryPointSymbol(*BB))
Streamer.emitLabel(EntrySymbol);
}
+ PrevBB = BB;
SMLoc LastLocSeen;
for (auto I = BB->begin(), E = BB->end(); I != E; ++I) {
@@ -499,8 +510,17 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
BB->getLocSyms().emplace_back(Offset, InstrLabel);
}
- if (InstrLabel)
- Streamer.emitLabel(InstrLabel);
+ if (InstrLabel) {
+ if (BundleState && !BundleState->canEmitInstructionLabel()) {
+ // Mid-bundle labels are dropped because VLIW packets execute
+ // atomically. Addresses within a bundle are not meaningful.
+ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: dropping mid-packet label "
+ << InstrLabel->getName() << " in "
+ << BF.getPrintName() << '\n');
+ } else {
+ Streamer.emitLabel(InstrLabel);
+ }
+ }
}
// Emit sized NOPs via MCAsmBackend::writeNopData() interface on x86.
@@ -515,10 +535,17 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
}
}
+ if (BundleState &&
+ BundleState->processInstruction(Instr, EmitViaStreamer))
+ continue;
+
Streamer.emitInstruction(Instr, *BC.STI);
}
}
+ if (BundleState)
+ BundleState->flush(EmitViaStreamer);
+
if (!EmitCodeOnly)
emitConstantIslands(BF, FF.isSplitFragment());
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/200916
More information about the llvm-commits
mailing list