diff --git a/llvm/include/llvm/CodeGen/MachineSsaContext.h b/llvm/include/llvm/CodeGen/MachineSsaContext.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/CodeGen/MachineSsaContext.h @@ -0,0 +1,98 @@ +//===- MachineSsaContext.h - SsaContext for Machine IR ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the MachineSsaContext to allow generic algorithms to +/// operate on MachineIR in SSA form. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINESSACONTEXT_H +#define LLVM_CODEGEN_MACHINESSACONTEXT_H + +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Handle.h" +#include "llvm/Support/SsaContext.h" + +namespace llvm { + +namespace handle_detail { + +/// Specialization of \ref WrapperImpl for values (llvm::Register). +template <> +class WrapperImpl + : public WrapperImplBase { +public: + static SsaValueHandle wrapRef(Register value) { + // Physical registers are unsupported by design. + assert(!value.isValid() || value.isVirtual()); + uintptr_t wrapped = value.id(); + assert((wrapped != 0) == value.isValid()); + + // Guard against producing values reserved for DenseMap markers. This is de + // facto impossible, because it'd require 2^31 virtual registers to be in + // use on a 32-bit architecture. + assert(wrapped != (uintptr_t)-1 && wrapped != (uintptr_t)-2); + + return make(reinterpret_cast(wrapped)); + } + + static Register unwrapRef(SsaValueHandle value) { + uintptr_t wrapped = reinterpret_cast(get(value)); + return Register(wrapped); + } +}; + +} // namespace handle_detail + +/// \brief SsaContext for Machine IR in SSA form. +class MachineSsaContext { +public: + using BlockRef = MachineBasicBlock *; + using InstructionRef = MachineInstr *; + using ValueRef = Register; + using Wrapper = HandleWrapper; + + explicit MachineSsaContext(MachineBasicBlock *block) + : m_regInfo(&block->getParent()->getRegInfo()) {} + explicit MachineSsaContext(MachineInstr *instr) + : m_regInfo(&instr->getParent()->getParent()->getRegInfo()) {} + + /// Get the defining block of a value. + MachineBasicBlock *getDefBlock(ValueRef value) const { + if (!value) + return nullptr; + return m_regInfo->getVRegDef(value)->getParent(); + } + + Printable printableName(MachineBasicBlock *block) const; + Printable printable(MachineInstr *instruction) const; + Printable printable(Register value) const; + +private: + MachineRegisterInfo *m_regInfo; +}; + +template <> struct SsaContextForImpl { + using Context = MachineSsaContext; +}; +template <> struct SsaContextForImpl { + using Context = MachineSsaContext; +}; +template <> struct SsaContextForImpl { + using Context = MachineSsaContext; +}; + +} // namespace llvm + +#endif // LLVM_CODEGEN_MACHINESSACONTEXT_H diff --git a/llvm/include/llvm/IR/CFG.h b/llvm/include/llvm/IR/CFG.h --- a/llvm/include/llvm/IR/CFG.h +++ b/llvm/include/llvm/IR/CFG.h @@ -25,6 +25,8 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Handle.h" +#include "llvm/Support/SsaContext.h" #include #include #include @@ -398,6 +400,49 @@ } }; +//===----------------------------------------------------------------------===// +// LLVM IR SsaContext +//===----------------------------------------------------------------------===// + +/// \brief SsaContext for LLVM IR. +class IrSsaContext { +public: + using BlockRef = BasicBlock *; + using InstructionRef = Instruction *; + using ValueRef = Value *; + using Wrapper = HandleWrapper; + + explicit IrSsaContext(BasicBlock *); + explicit IrSsaContext(Instruction *); + ~IrSsaContext(); + + BasicBlock *getDefBlock(Value *value) const { + if (auto *instruction = dyn_cast(value)) + return instruction->getParent(); + if (auto *argument = dyn_cast(value)) + return &argument->getParent()->getEntryBlock(); + return nullptr; + } + + Printable printableName(BasicBlock *block) const; + Printable printable(Value *value) const; + +private: + mutable std::unique_ptr m_moduleSlotTracker; + + void ensureModuleSlotTracker(const Function &function) const; +}; + +template <> struct SsaContextForImpl { + using Context = IrSsaContext; +}; +template <> struct SsaContextForImpl { + using Context = IrSsaContext; +}; +template <> struct SsaContextForImpl { using Context = IrSsaContext; }; + } // end namespace llvm #endif // LLVM_IR_CFG_H diff --git a/llvm/include/llvm/Support/SsaContext.h b/llvm/include/llvm/Support/SsaContext.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/SsaContext.h @@ -0,0 +1,78 @@ +//===- SsaContext.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines a set of classes around the SsaContext concept that allows +/// code to abstract over some of the differences between SSA-form IRs beyond +/// what is possible from templates via context-free functions like +/// \ref llvm::GraphTraits::child_begin()/child_end(). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SSACONTEXT_H +#define LLVM_SUPPORT_SSACONTEXT_H + +#include "llvm/Support/Printable.h" + +namespace llvm { + +class Printable; + +/// Users of SsaContext should use \ref SsaContextFor instead. +/// +/// This template is specialized by every supported IR. The specialization +/// should exist for: +/// - block "references", e.g. `llvm::BasicBlock *` +/// - instruction "references", e.g. `llvm::MachineInstr *` +/// - value "references", e.g. `mlir::Value` +template struct SsaContextForImpl { + // Context is the type implementing the SsaContext concept. It must be the + // same for every RefType of an IR. + + // If you get a compiler error on the following line, it is because you're + // (indirectly?) using SsaContextFor where T is not a supported IR object + // reference type, or the necessary specialization of this template is not + // in scope (probably due to a missing #include). + using Context = typename RefType::MissingSpecializationOfSsaContextForImpl; +}; + +/// \brief Discover the SsaContext implementation for an IR. +/// +/// The template parameter must be an IR object reference type, e.g. +/// llvm::BasicBlock* (for LLVM IR basic block) or mlir::Value (for MLIR +/// values). +/// +/// The context class must provide the following: +/// +/// class TheSsaContext { +/// public: +/// using BlockRef = ...; // e.g., llvm::BasicBlock * +/// using InstructionRef = ...; // e.g., llvm::Instruction * +/// using ValueRef = ...; // e.g., llvm::Value * +/// using Wrapper = ...; // suitable llvm::HandleWrapper +/// +/// explicit TheSsaContext(BlockRef block); +/// explicit TheSsaContext(InstructionRef instruction); +/// +/// // Get the block in which a given value is defined. Returns a null-like +/// // BlockRef if the value is not defined in a block (e.g. it is a +/// // constant). Function arguments are defined in the function entry +/// // block. +/// BlockRef getDefBlock(ValueRef value) const; +/// +/// Printable printableName(BlockRef ref) const; +/// Printable printable(InstructionRef ref) const; +/// Printable printable(ValueRef ref) const; +/// }; +/// +template +using SsaContextFor = typename SsaContextForImpl::Context; + +} // namespace llvm + +#endif // LLVM_SUPPORT_SSACONTEXT_H diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -101,6 +101,7 @@ MachineSink.cpp MachineSizeOpts.cpp MachineSSAUpdater.cpp + MachineSsaContext.cpp MachineStripDebug.cpp MachineTraceMetrics.cpp MachineVerifier.cpp diff --git a/llvm/lib/CodeGen/MachineSsaContext.cpp b/llvm/lib/CodeGen/MachineSsaContext.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/MachineSsaContext.cpp @@ -0,0 +1,36 @@ +//===- MachineSsaContext.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineSsaContext.h" + +#include "llvm/IR/BasicBlock.h" + +using namespace llvm; + +Printable MachineSsaContext::printableName(MachineBasicBlock *block) const { + return Printable([block](raw_ostream &out) { block->printName(out); }); +} + +Printable MachineSsaContext::printable(MachineInstr *instruction) const { + return Printable( + [instruction](raw_ostream &out) { instruction->print(out); }); +} + +Printable MachineSsaContext::printable(Register value) const { + MachineRegisterInfo *mri = m_regInfo; + return Printable([mri, value](raw_ostream &out) { + out << printReg(value, mri->getTargetRegisterInfo(), 0, mri); + + if (value) { + out << ": "; + + MachineInstr *instr = mri->getUniqueVRegDef(value); + instr->print(out); + } + }); +} diff --git a/llvm/lib/IR/CFG.cpp b/llvm/lib/IR/CFG.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/IR/CFG.cpp @@ -0,0 +1,59 @@ +//===- CFG.cpp --------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/CFG.h" + +#include "llvm/IR/ModuleSlotTracker.h" + +using namespace llvm; + +IrSsaContext::IrSsaContext(BasicBlock *) {} +IrSsaContext::IrSsaContext(Instruction *) {} +IrSsaContext::~IrSsaContext() {} + +Printable IrSsaContext::printable(Value *value) const { + if (!m_moduleSlotTracker) { + const Function *function = nullptr; + + if (auto *instruction = dyn_cast(value)) { + function = instruction->getParent()->getParent(); + } else if (auto *argument = dyn_cast(value)) { + function = argument->getParent(); + } + + if (function) + ensureModuleSlotTracker(*function); + } + + if (m_moduleSlotTracker) { + return Printable([&mst = *m_moduleSlotTracker, value](raw_ostream &out) { + value->print(out, mst, true); + }); + } else { + return Printable([value](raw_ostream &out) { value->print(out, true); }); + } +} + +Printable IrSsaContext::printableName(BasicBlock *block) const { + if (block->hasName()) { + return Printable([block](raw_ostream &out) { out << block->getName(); }); + } else { + ensureModuleSlotTracker(*block->getParent()); + return Printable([&mst = *m_moduleSlotTracker, block](raw_ostream &out) { + out << mst.getLocalSlot(block); + }); + } +} + +void IrSsaContext::ensureModuleSlotTracker(const Function &function) const { + if (!m_moduleSlotTracker) { + m_moduleSlotTracker = + std::make_unique(function.getParent(), false); + m_moduleSlotTracker->incorporateFunction(function); + } +} diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -4,6 +4,7 @@ Attributes.cpp AutoUpgrade.cpp BasicBlock.cpp + CFG.cpp Comdat.cpp ConstantFold.cpp ConstantRange.cpp