[llvm] IR2Builder tool for converting LLVM IR files into C++ IRBuilder API (PR #117129)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 5 22:05:04 PST 2025
================
@@ -0,0 +1,1673 @@
+//===-- ir2builder.cpp - Transpiler from IR to builder API ------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a pass, which converts LLVM IR into llvm::IRBuilder
+// API in textual form.
+//
+// This tool can be used to simplify IR construction using IRBuilder by
+// writing the IR by hand and then converting it using this pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cctype>
+#include <cmath>
+#include <cstdint>
+#include <sstream>
+
+using namespace llvm;
+
+cl::OptionCategory Ir2BCat("ir2builder Options");
+
+/// LLVM IR to convert.
+static cl::opt<std::string>
+ InputFilename(cl::Positional, cl::desc("<input .ll file>"), cl::init("-"));
+
+/// Output file for the generated C++ code.
+/// If not set then stdout will be used.
+static cl::opt<std::string> OutputFilename("o",
+ cl::desc("Override output filename"),
+ cl::value_desc("filename"),
+ cl::cat(Ir2BCat));
+
+/// Set this when you don't use `using namespace llvm` (don't forget :: at the
+/// end).
+static cl::opt<std::string> ScopePrefix(
+ "scope-prefix",
+ cl::desc(
+ "All generated calls to LLVM API will be prefixed with this scope. The "
+ "scope has to end with '::' (e.g.: '-scope-prefix=llvm::')"),
+ cl::cat(Ir2BCat), cl::init(""));
+
+/// Set this to your variable name for IRBuilder instance.
+static cl::opt<std::string> BuilderName(
+ "builder-name",
+ cl::desc("IRBuilder variable name that will be used in generated code"),
+ cl::cat(Ir2BCat), cl::init("Builder"));
+
+/// Set this to your LLVMContext variable name.
+static cl::opt<std::string> ContextName(
+ "context-name",
+ cl::desc("Context variable name that will be used in generated code"),
+ cl::cat(Ir2BCat), cl::init("Ctx"));
+
+/// Set this to your llvm::Module * name.
+static cl::opt<std::string> ModuleName(
+ "module-name",
+ cl::desc("Module variable name that will be used in generated code"),
+ cl::cat(Ir2BCat), cl::init("Mod"));
+
+/// Set this if you want custom data layout.
+static cl::opt<std::string> ClDataLayout("data-layout",
+ cl::desc("data layout string to use"),
+ cl::value_desc("layout-string"),
+ cl::init(""), cl::cat(Ir2BCat));
+
+/// This will generate fully compilable C++ program with main, which will
+/// use generated calls to create the original LLVM IR.
+/// Main purpose of this is to use it for testing and verification that
+/// generated program is correct and compilable.
+/// For example you can generate the code, run this program and then use
+/// llvm-diff to see if it matches the original:
+/// ```
+/// ./ir2builder code.ll --runnable > main.cpp &&
+/// g++ main.cpp `./llvm-conf --cxxflags --ldflags --system-libs --libs core`
+/// -I /llvm/include/ -o main &&
+/// ./main > generated.ll &&
+/// ./llvm-diff code.ll generated.ll
+/// ```
+static cl::opt<bool> GenerateRunnable(
+ "runnable", cl::desc("Generates whole cpp compilable program with main"),
+ cl::init(false), cl::cat(Ir2BCat));
+
+/// Disables verification of loaded llvm IR.
+/// Keep in mind that this will most likely result in C++ error as it probably
+/// won't be possible to create Builder calls for this.
+static cl::opt<bool>
+ DisableVerify("disable-verify", cl::Hidden,
+ cl::desc("Do not run verifier on input LLVM (dangerous!)"),
+ cl::cat(Ir2BCat));
+
+/// Sets the order of traversal for the LLVM IR.
+/// When enabled the traversal will be in reverse post order, which can handle
+/// when values are defined after (text-wise) their use.
+/// On the other hand using just linear traversal will also include parts that
+/// are outside of the graph (dead blocks).
+static cl::opt<bool>
+ UseRPO("use-rpo",
+ cl::desc("Traverses IR in reverse post order. This can help with "
+ "\"was not declared\" errors"),
+ cl::init(true), cl::cat(Ir2BCat));
+
+/// \brief Transpiler from LLVM IR into IRBuilder API calls.
+/// The main purpose for this class is to hold variable counter and variable
+/// names for needed resources, such as LLVMContext.
+class IR2Builder {
+private:
+ unsigned long VarI = 0;
+ std::string LLVMPrefix;
+ std::string Builder;
+ std::string Ctx;
+ std::string ModName;
+
+ std::vector<std::string> PhiIncomings;
+
+ inline bool hasName(const Value *Op) {
+ return !isa<Constant>(Op) && !isa<InlineAsm>(Op);
+ }
+
+ void outputAttr(Attribute Att, raw_ostream &OS);
+
+ std::string getNextVar();
+
+ std::string asStr(GlobalValue::LinkageTypes Linkage);
+ std::string asStr(GlobalValue::ThreadLocalMode TLM);
+ std::string asStr(CmpInst::Predicate P);
+ std::string asStr(AtomicRMWInst::BinOp Op);
+ std::string asStr(AtomicOrdering AO);
+ std::string asStr(SyncScope::ID Sys);
+ std::string asStr(CallingConv::ID CC);
+ std::string asStr(ConstantRange &CR);
+
+ std::string asStr(const Value *Op);
+ std::string asStr(const Constant *Op);
+ std::string asStr(const Type *T);
+ std::string asStr(const InlineAsm *Op);
+ std::string asStr(const Metadata *Op);
+
+public:
+ IR2Builder()
+ : LLVMPrefix(ScopePrefix), Builder(BuilderName), Ctx(ContextName),
+ ModName(ModuleName) {}
+
+ /// Calls convert for all the functions in passed in module.
+ /// \param M Module to call convert over.
+ /// \param OS Stream to which output the builder calls.
+ void convert(Module &M, raw_ostream &OS);
+
+ /// Converts a function into IRBuilder API calls.
+ /// \param F Function to convert.
+ /// \param OS Stream to which output the builder calls.
+ void convert(Function &F, raw_ostream &OS);
+
+ /// Converts an instruction into IRBuilder API calls.
+ /// \param I Instruction to convert.
+ /// \param OS Stream to which output the builder calls.
+ /// \note Unsupported instructions or their operands should result
+ /// in a TODO comment.
+ void convert(const Instruction *I, raw_ostream &OS);
+};
+
+std::string IR2Builder::getNextVar() { return "v0" + std::to_string(VarI++); }
+
+static std::string toStr(bool B) { return B ? "true" : "false"; }
+
+static std::string escape(std::string S) {
+ std::string Tmp;
+ raw_string_ostream OS(Tmp);
+ printEscapedString(S, OS);
+ return Tmp;
+}
+
+static std::string sanitize(std::string S) {
+ std::stringstream SS;
+ for (size_t I = 0; I < S.size(); ++I) {
+ if (!std::isalnum(S[I]))
+ SS << "_" << static_cast<unsigned>(S[I]) << "_";
+ else
+ SS << S[I];
+ }
+ return SS.str();
+}
+
+std::string IR2Builder::asStr(GlobalValue::LinkageTypes Linkage) {
+ std::string Link = LLVMPrefix + "GlobalValue::";
+
+ switch (Linkage) {
+ case GlobalValue::WeakODRLinkage:
+ return Link + "WeakODRLinkage";
+ case GlobalValue::LinkOnceODRLinkage:
+ return Link + "LinkOnceODRLinkage";
+ case GlobalValue::AvailableExternallyLinkage:
+ return Link + "AvailableExternallyLinkage";
+ case GlobalValue::WeakAnyLinkage:
+ return Link + "WeakAnyLinkage";
+ case GlobalValue::LinkOnceAnyLinkage:
+ return Link + "LinkOnceAnyLinkage";
+ case GlobalValue::CommonLinkage:
+ return Link + "CommonLinkage";
+ case GlobalValue::ExternalWeakLinkage:
+ return Link + "ExternalWeakLinkage";
+ case GlobalValue::ExternalLinkage:
+ return Link + "ExternalLinkage";
+ case GlobalValue::AppendingLinkage:
+ return Link + "AppendingLinkage";
+ case GlobalValue::InternalLinkage:
+ return Link + "InternalLinkage";
+ case GlobalValue::PrivateLinkage:
+ return Link + "PrivateLinkage";
+ default:
+ return "/* Unknown LinkageTypes (using value) */" + std::to_string(Linkage);
+ }
+}
+
+std::string IR2Builder::asStr(AtomicRMWInst::BinOp Op) {
+ switch (Op) {
+ case AtomicRMWInst::BinOp::Xchg:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Xchg";
+ case AtomicRMWInst::BinOp::Add:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Add";
+ case AtomicRMWInst::BinOp::Sub:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Sub";
+ case AtomicRMWInst::BinOp::And:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::And";
+ case AtomicRMWInst::BinOp::Nand:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Nand";
+ case AtomicRMWInst::BinOp::Or:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Or";
+ case AtomicRMWInst::BinOp::Xor:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Xor";
+ case AtomicRMWInst::BinOp::Max:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Max";
+ case AtomicRMWInst::BinOp::Min:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::Min";
+ case AtomicRMWInst::BinOp::UMax:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::UMax";
+ case AtomicRMWInst::BinOp::UMin:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::UMin";
+ case AtomicRMWInst::BinOp::FAdd:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::FAdd";
+ case AtomicRMWInst::BinOp::FSub:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::FSub";
+ case AtomicRMWInst::BinOp::FMax:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::FMax";
+ case AtomicRMWInst::BinOp::FMin:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::FMin";
+ case AtomicRMWInst::BinOp::UIncWrap:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::UIncWrap";
+ case AtomicRMWInst::BinOp::UDecWrap:
+ return LLVMPrefix + "AtomicRMWInst::BinOp::UDecWrap";
+ default:
+ return "/* TODO: Unknown AtomicRMW operator (using value) */ " +
+ std::to_string(Op);
+ }
+}
+
+std::string IR2Builder::asStr(AtomicOrdering AO) {
+ switch (AO) {
+ case AtomicOrdering::NotAtomic:
+ return LLVMPrefix + "AtomicOrdering::NotAtomic";
+ case AtomicOrdering::Unordered:
+ return LLVMPrefix + "AtomicOrdering::Unordered";
+ case AtomicOrdering::Monotonic:
+ return LLVMPrefix + "AtomicOrdering::Monotonic";
+ case AtomicOrdering::Acquire:
+ return LLVMPrefix + "AtomicOrdering::Acquire";
+ case AtomicOrdering::Release:
+ return LLVMPrefix + "AtomicOrdering::Release";
+ case AtomicOrdering::AcquireRelease:
+ return LLVMPrefix + "AtomicOrdering::AcquireRelease";
+ case AtomicOrdering::SequentiallyConsistent:
+ return LLVMPrefix + "AtomicOrdering::SequentiallyConsistent";
+ default:
+ return "/* TODO: Unknown atomic ordering */";
+ }
+}
+
+std::string IR2Builder::asStr(CmpInst::Predicate P) {
+ switch (P) {
+ case CmpInst::Predicate::FCMP_FALSE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_FALSE";
+ case CmpInst::Predicate::FCMP_OEQ:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_OEQ";
+ case CmpInst::Predicate::FCMP_OGT:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_OGT";
+ case CmpInst::Predicate::FCMP_OGE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_OGE";
+ case CmpInst::Predicate::FCMP_OLT:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_OLT";
+ case CmpInst::Predicate::FCMP_OLE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_OLE";
+ case CmpInst::Predicate::FCMP_ONE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_ONE";
+ case CmpInst::Predicate::FCMP_ORD:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_ORD";
+ case CmpInst::Predicate::FCMP_UNO:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_UNO";
+ case CmpInst::Predicate::FCMP_UEQ:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_UEQ";
+ case CmpInst::Predicate::FCMP_UGT:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_UGT";
+ case CmpInst::Predicate::FCMP_UGE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_UGE";
+ case CmpInst::Predicate::FCMP_ULT:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_ULT";
+ case CmpInst::Predicate::FCMP_ULE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_ULE";
+ case CmpInst::Predicate::FCMP_UNE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_UNE";
+ case CmpInst::Predicate::FCMP_TRUE:
+ return LLVMPrefix + "CmpInst::Predicate::FCMP_TRUE";
+ case CmpInst::Predicate::ICMP_EQ:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_EQ";
+ case CmpInst::Predicate::ICMP_NE:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_NE";
+ case CmpInst::Predicate::ICMP_UGT:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_UGT";
+ case CmpInst::Predicate::ICMP_UGE:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_UGE";
+ case CmpInst::Predicate::ICMP_ULT:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_ULT";
+ case CmpInst::Predicate::ICMP_ULE:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_ULE";
+ case CmpInst::Predicate::ICMP_SGT:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_SGT";
+ case CmpInst::Predicate::ICMP_SGE:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_SGE";
+ case CmpInst::Predicate::ICMP_SLT:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_SLT";
+ case CmpInst::Predicate::ICMP_SLE:
+ return LLVMPrefix + "CmpInst::Predicate::ICMP_SLE";
+ default:
+ return "/* TODO: Unknown CMP predicate (using value) */ " +
+ std::to_string(P);
+ }
+}
+
+std::string IR2Builder::asStr(SyncScope::ID Sys) {
+ if (Sys == SyncScope::System)
+ return LLVMPrefix + "SyncScope::System";
+ if (Sys == SyncScope::SingleThread)
+ return LLVMPrefix + "SyncScope::SingleThread";
+
+ return "/* TODO: Unknown SyncScope ID (using value) */ " +
+ std::to_string(Sys);
+}
+
+std::string IR2Builder::asStr(GlobalValue::ThreadLocalMode TLM) {
+ switch (TLM) {
+ case GlobalValue::ThreadLocalMode::NotThreadLocal:
+ return LLVMPrefix + "GlobalValue::ThreadLocalMode::NotThreadLocal";
+ case GlobalValue::ThreadLocalMode::GeneralDynamicTLSModel:
+ return LLVMPrefix + "GlobalValue::ThreadLocalMode::GeneralDynamicTLSModel";
+ case GlobalValue::ThreadLocalMode::LocalDynamicTLSModel:
+ return LLVMPrefix + "GlobalValue::ThreadLocalMode::LocalDynamicTLSModel";
+ case GlobalValue::ThreadLocalMode::InitialExecTLSModel:
+ return LLVMPrefix + "GlobalValue::ThreadLocalMode::InitialExecTLSModel";
+ case GlobalValue::ThreadLocalMode::LocalExecTLSModel:
+ return LLVMPrefix + "GlobalValue::ThreadLocalMode::LocalExecTLSModel";
+ default:
+ return "/* TODO: Unknown ThreadLocalMode (using value) */ " +
+ std::to_string(TLM);
+ }
+}
+
+std::string IR2Builder::asStr(CallingConv::ID CC) {
+ switch (CC) {
+ case CallingConv::C:
+ return LLVMPrefix + "CallingConv::C";
+ case CallingConv::Fast:
+ return LLVMPrefix + "CallingConv::Fast";
+ case CallingConv::Cold:
+ return LLVMPrefix + "CallingConv::Cold";
+ case CallingConv::GHC:
+ return LLVMPrefix + "CallingConv::GHC";
+ case CallingConv::HiPE:
+ return LLVMPrefix + "CallingConv::HiPE";
+ case CallingConv::AnyReg:
+ return LLVMPrefix + "CallingConv::AnyReg";
+ case CallingConv::PreserveMost:
+ return LLVMPrefix + "CallingConv::PreserveMost";
+ case CallingConv::PreserveAll:
+ return LLVMPrefix + "CallingConv::PreserveAll";
+ case CallingConv::Swift:
+ return LLVMPrefix + "CallingConv::Swift";
+ case CallingConv::CXX_FAST_TLS:
+ return LLVMPrefix + "CallingConv::CXX_FAST_TLS";
+ case CallingConv::Tail:
+ return LLVMPrefix + "CallingConv::Tail";
+ case CallingConv::CFGuard_Check:
+ return LLVMPrefix + "CallingConv::CFGuard_Check";
+ case CallingConv::SwiftTail:
+ return LLVMPrefix + "CallingConv::SwiftTail";
+ case CallingConv::PreserveNone:
+ return LLVMPrefix + "CallingConv::PreserveNone";
+ case CallingConv::FirstTargetCC:
+ return LLVMPrefix + "CallingConv::FirstTargetCC";
+ // CallingConv::X86_StdCall is the same as FirstTargetCC.
+ case CallingConv::X86_FastCall:
+ return LLVMPrefix + "CallingConv::X86_FastCall";
+ case CallingConv::ARM_APCS:
+ return LLVMPrefix + "CallingConv::ARM_APCS";
+ case CallingConv::ARM_AAPCS:
+ return LLVMPrefix + "CallingConv::ARM_AAPCS";
+ case CallingConv::ARM_AAPCS_VFP:
+ return LLVMPrefix + "CallingConv::ARM_AAPCS_VFP";
+ case CallingConv::MSP430_INTR:
+ return LLVMPrefix + "CallingConv::MSP430_INTR";
+ case CallingConv::X86_ThisCall:
+ return LLVMPrefix + "CallingConv::X86_ThisCall";
+ case CallingConv::PTX_Kernel:
+ return LLVMPrefix + "CallingConv::PTX_Kernel";
+ case CallingConv::PTX_Device:
+ return LLVMPrefix + "CallingConv::PTX_Device";
+ case CallingConv::SPIR_FUNC:
+ return LLVMPrefix + "CallingConv::SPIR_FUNC";
+ case CallingConv::SPIR_KERNEL:
+ return LLVMPrefix + "CallingConv::SPIR_KERNEL";
+ case CallingConv::Intel_OCL_BI:
+ return LLVMPrefix + "CallingConv::Intel_OCL_BI";
+ case CallingConv::X86_64_SysV:
+ return LLVMPrefix + "CallingConv::X86_64_SysV";
+ case CallingConv::Win64:
+ return LLVMPrefix + "CallingConv::Win64";
+ case CallingConv::X86_VectorCall:
+ return LLVMPrefix + "CallingConv::X86_VectorCall";
+ case CallingConv::DUMMY_HHVM:
+ return LLVMPrefix + "CallingConv::DUMMY_HHVM";
+ case CallingConv::DUMMY_HHVM_C:
+ return LLVMPrefix + "CallingConv::DUMMY_HHVM_C";
+ case CallingConv::X86_INTR:
+ return LLVMPrefix + "CallingConv::X86_INTR";
+ case CallingConv::AVR_INTR:
+ return LLVMPrefix + "CallingConv::AVR_INTR";
+ case CallingConv::AVR_SIGNAL:
+ return LLVMPrefix + "CallingConv::AVR_SIGNAL";
+ case CallingConv::AVR_BUILTIN:
+ return LLVMPrefix + "CallingConv::AVR_BUILTIN";
+ case CallingConv::AMDGPU_VS:
+ return LLVMPrefix + "CallingConv::AMDGPU_VS";
+ case CallingConv::AMDGPU_GS:
+ return LLVMPrefix + "CallingConv::AMDGPU_GS";
+ case CallingConv::AMDGPU_PS:
+ return LLVMPrefix + "CallingConv::AMDGPU_PS";
+ case CallingConv::AMDGPU_CS:
+ return LLVMPrefix + "CallingConv::AMDGPU_CS";
+ case CallingConv::AMDGPU_KERNEL:
+ return LLVMPrefix + "CallingConv::AMDGPU_KERNEL";
+ case CallingConv::X86_RegCall:
+ return LLVMPrefix + "CallingConv::X86_RegCall";
+ case CallingConv::AMDGPU_HS:
+ return LLVMPrefix + "CallingConv::AMDGPU_HS";
+ case CallingConv::MSP430_BUILTIN:
+ return LLVMPrefix + "CallingConv::MSP430_BUILTIN";
+ case CallingConv::AMDGPU_LS:
+ return LLVMPrefix + "CallingConv::AMDGPU_LS";
+ case CallingConv::AMDGPU_ES:
+ return LLVMPrefix + "CallingConv::AMDGPU_ES";
+ case CallingConv::AArch64_VectorCall:
+ return LLVMPrefix + "CallingConv::AArch64_VectorCall";
+ case CallingConv::AArch64_SVE_VectorCall:
+ return LLVMPrefix + "CallingConv::AArch64_SVE_VectorCall";
+ case CallingConv::WASM_EmscriptenInvoke:
+ return LLVMPrefix + "CallingConv::WASM_EmscriptenInvoke";
+ case CallingConv::AMDGPU_Gfx:
+ return LLVMPrefix + "CallingConv::AMDGPU_Gfx";
+ case CallingConv::M68k_INTR:
+ return LLVMPrefix + "CallingConv::M68k_INTR";
+ case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0:
+ return LLVMPrefix +
+ "CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0";
+ case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2:
+ return LLVMPrefix +
+ "CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2";
+ case CallingConv::AMDGPU_CS_Chain:
+ return LLVMPrefix + "CallingConv::AMDGPU_CS_Chain";
+ case CallingConv::AMDGPU_CS_ChainPreserve:
+ return LLVMPrefix + "CallingConv::AMDGPU_CS_ChainPreserve";
+ case CallingConv::M68k_RTD:
+ return LLVMPrefix + "CallingConv::M68k_RTD";
+ case CallingConv::GRAAL:
+ return LLVMPrefix + "CallingConv::GRAAL";
+ case CallingConv::ARM64EC_Thunk_X64:
+ return LLVMPrefix + "CallingConv::ARM64EC_Thunk_X64";
+ case CallingConv::ARM64EC_Thunk_Native:
+ return LLVMPrefix + "CallingConv::ARM64EC_Thunk_Native";
+ default:
+ return "/* Custom CC */" + std::to_string(CC);
+ }
+}
+
+std::string IR2Builder::asStr(const Type *T) {
+ std::string TCall;
+ if (auto IT = dyn_cast<IntegerType>(T)) {
+ switch (IT->getBitWidth()) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ TCall = formatv("getInt{0}Ty()", IT->getBitWidth());
+ break;
+ default:
+ TCall = formatv("getIntNTy({0})", IT->getBitWidth());
+ break;
+ }
+ } else if (T->isVoidTy())
+ TCall = "getVoidTy()";
+ else if (T->isFloatTy())
+ TCall = "getFloatTy()";
+ else if (T->isDoubleTy())
+ TCall = "getDoubleTy()";
+ else if (auto ST = dyn_cast<StructType>(T)) {
+ std::string Elements = LLVMPrefix + "ArrayRef<Type *>(";
+ if (ST->getNumElements() > 1)
+ Elements += "{";
+ bool First = true;
+ for (auto E : ST->elements()) {
+ if (!First)
+ Elements += ", ";
+ Elements += asStr(E);
+ First = false;
+ }
+ if (ST->getNumElements() > 1)
+ Elements += "}";
+ Elements += ")";
+ return formatv("{0}StructType::create({1}, {2})", LLVMPrefix, Ctx,
+ Elements);
+ } else if (auto AT = dyn_cast<ArrayType>(T)) {
+ return formatv("{0}ArrayType::get({1}, {2})", LLVMPrefix,
+ asStr(AT->getElementType()), AT->getArrayNumElements());
+ } else if (T->isBFloatTy())
+ TCall = "getBFloatTy()";
+ else if (auto VT = dyn_cast<VectorType>(T)) {
+ return formatv("{0}VectorType::get({1}, {0}ElementCount::get({2}, {3}))",
+ LLVMPrefix, asStr(VT->getElementType()),
+ VT->getElementCount().getKnownMinValue(),
+ toStr(VT->getElementCount().isScalable()));
+ } else if (auto FT = dyn_cast<FunctionType>(T)) {
+ TCall = formatv("{0}FunctionType::get({1}, {{", LLVMPrefix,
+ asStr(FT->getReturnType()));
+
+ bool IsFirst = true;
+ for (auto A : FT->params()) {
+ if (!IsFirst)
+ TCall += ", ";
+ TCall += asStr(A);
+ IsFirst = false;
+ }
+ TCall += "}, " + toStr(FT->isVarArg()) + ")";
+ return TCall;
+ } else if (T->isPointerTy())
+ TCall = "getPtrTy()";
+ else if (T->isHalfTy())
+ return formatv("{0}Type::getHalfTy({1})", LLVMPrefix, Ctx);
+ else if (T->isBFloatTy())
+ return formatv("{0}Type::getBFloatTy({1})", LLVMPrefix, Ctx);
+ else if (T->isX86_FP80Ty())
+ return formatv("{0}Type::getX86_FP80Ty({1})", LLVMPrefix, Ctx);
+ else if (T->isFP128Ty())
+ return formatv("{0}Type::getFP128Ty({1})", LLVMPrefix, Ctx);
+ else if (T->isPPC_FP128Ty())
+ return formatv("{0}Type::getPPC_FP128Ty({1})", LLVMPrefix, Ctx);
+ else if (T->isX86_AMXTy())
+ return formatv("{0}Type::getX86_AMXTy({1})", LLVMPrefix, Ctx);
+ else if (T->isLabelTy())
+ return formatv("{0}Type::getLabelTy({1})", LLVMPrefix, Ctx);
+ else if (T->isMetadataTy())
+ return formatv("{0}Type::getMetadataTy({1})", LLVMPrefix, Ctx);
+ else if (T->isTokenTy())
+ return formatv("{0}Type::getTokenTy({1})", LLVMPrefix, Ctx);
+ else
+ return "/* TODO: Unknown type */";
+
+ return Builder + "." + TCall;
+}
+
+std::string IR2Builder::asStr(const Constant *C) {
+ if (auto CI = dyn_cast<ConstantInt>(C)) {
+ // TODO: Sign has to be determined.
+ auto CVal = CI->getValue();
+ return formatv("{0}ConstantInt::get({1}, {2})", LLVMPrefix,
+ asStr(C->getType()), CVal.getSExtValue());
+ }
+ if (auto CF = dyn_cast<ConstantFP>(C)) {
+ auto CVal = CF->getValue();
+ double DVal = CVal.convertToDouble();
+ std::string Val = std::to_string(DVal);
+ if (std::isnan(DVal) || std::isinf(DVal))
+ Val = "\"" + Val + "\"";
+ // TODO: Handle double to string conversion to include all digits.
+ return formatv("{0}ConstantFP::get({1}, {2})", LLVMPrefix,
+ asStr(C->getType()), Val);
+ }
+ if (auto AT = dyn_cast<ConstantAggregate>(C)) {
+ std::string Values;
+ bool First = true;
+ for (unsigned I = 0; I < AT->getNumOperands(); ++I) {
+ if (!First)
+ Values += ", ";
+ Values += asStr(AT->getOperand(I));
+ First = false;
+ }
+
+ std::string ClassName;
+ if (isa<ConstantArray>(C)) {
+ ClassName = "ConstantArray";
+ Values = formatv(
+ "{0}ArrayRef<{0}Constant *>({1}{2}{3})", LLVMPrefix,
+ (AT->getNumOperands() > 1 ? std::string("{") : std::string("")),
+ Values,
+ (AT->getNumOperands() > 1 ? std::string("}") : std::string("")));
+ } else if (isa<ConstantStruct>(C))
+ ClassName = "ConstantStruct";
+ else if (isa<ConstantVector>(C)) {
+ Values = "{" + Values + "}";
+ // ConstantVector does not take type as 1st arg.
+ return formatv("{0}ConstantVector::get({1})", LLVMPrefix, Values);
+ } else
+ return "/* TODO: Unknown aggregate constant */";
+
+ assert(!ClassName.empty() && "Class name not set");
+ return formatv("{0}{1}::get({2}, {3})", LLVMPrefix, ClassName,
+ asStr(C->getType()), Values);
+ }
+ if (auto CDS = dyn_cast<ConstantDataSequential>(C)) {
+ std::string Values;
+ std::string ClassName;
+ std::string ElemTy = "/* TODO */";
+ if (isa<ConstantDataArray>(C))
+ ClassName = "ConstantDataArray";
+ else if (isa<ConstantDataVector>(C))
+ ClassName = "ConstantDataVector";
+ else
+ return "/* TODO: Unknown data sequential constant */";
+ if (CDS->isString()) {
+ Values = "";
+ bool First = true;
+ for (auto a : CDS->getAsString().str()) {
+ if (First) {
+ Values += std::to_string(static_cast<uint8_t>(a));
+ First = false;
+ } else {
+ Values += ", " + std::to_string(static_cast<uint8_t>(a));
+ }
+ }
+ assert(!ClassName.empty() && "Class name not set");
+ return formatv("{0}{1}::get({2}, {0}ArrayRef<uint8_t>({3}{4}{5}))",
+ LLVMPrefix, ClassName, Ctx, "{", Values, "}");
+ }
+ if (CDS->isCString()) {
+ Values = "";
+ bool First = true;
+ for (auto A : CDS->getAsCString().str()) {
+ if (First) {
+ Values += std::to_string(static_cast<uint8_t>(A));
+ First = false;
+ } else {
+ Values += ", " + std::to_string(static_cast<uint8_t>(A));
+ }
+ }
+ assert(!ClassName.empty() && "Class name not set");
+ return formatv("{0}{1}::get({2}, {0}ArrayRef<uint8_t>({3}{4}{5}))",
+ LLVMPrefix, ClassName, Ctx, "{", Values, "}");
+ } else {
+ Type *ElemT = CDS->getElementType();
+ if (ElemT->isIntegerTy()) {
+ // There can be only 8, 16, 32 or 64 ints in ConstantDataVector.
+ ElemTy = "uint" + std::to_string(ElemT->getIntegerBitWidth()) + "_t";
+ } else if (ElemT->isDoubleTy()) {
+ ElemTy = "double";
+ } else if (ElemT->isFloatTy()) {
+ ElemTy = "float";
+ }
+ Values = formatv("{0}ArrayRef<{1}>(", LLVMPrefix, ElemTy);
+ if (CDS->getNumElements() > 1)
+ Values += "{";
+ bool First = true;
+ for (unsigned I = 0; I < CDS->getNumElements(); ++I) {
+ if (!First)
+ Values += ", ";
+ if (ElemT->isIntegerTy())
+ Values += std::to_string(CDS->getElementAsInteger(I));
+ else if (ElemT->isDoubleTy())
+ Values += std::to_string(CDS->getElementAsDouble(I));
+ else if (ElemT->isFloatTy())
+ Values += std::to_string(CDS->getElementAsFloat(I));
+ else
+ return "/* Unknown type in data sequential constant */";
+ First = false;
+ }
+ if (CDS->getNumElements() > 1)
+ Values += "}";
+ Values += ")";
+ }
+
+ return formatv("{0}{1}::get({2}, {3})", LLVMPrefix, ClassName, Ctx, Values);
+ }
+ if (isa<ConstantAggregateZero>(C))
+ return formatv("{0}ConstantAggregateZero::get({1})", LLVMPrefix,
+ asStr(C->getType()));
+ if (isa<PoisonValue>(C))
+ return formatv("{0}PoisonValue::get({1})", LLVMPrefix, asStr(C->getType()));
+ if (isa<UndefValue>(C))
+ return formatv("{0}UndefValue::get({1})", LLVMPrefix, asStr(C->getType()));
+ if (auto ba = dyn_cast<BlockAddress>(C))
+ return formatv("{0}BlockAddress::get({1}, {2})", LLVMPrefix,
+ asStr(ba->getFunction()), asStr(ba->getBasicBlock()));
+ if (isa<ConstantPointerNull>(C))
+ return formatv("{0}ConstantPointerNull::get({1})", LLVMPrefix,
+ asStr(C->getType()));
+ if (auto CTN = dyn_cast<ConstantTargetNone>(C)) {
+ auto CTNType = CTN->getType();
+
+ std::string TypeStr = "{";
+ bool First = true;
+ for (unsigned I = 0; I < CTNType->getNumTypeParameters(); ++I) {
+ if (!First)
+ TypeStr += ", ";
+ TypeStr += asStr(CTNType->getTypeParameter(I));
+ First = false;
+ }
+ TypeStr += "}";
+
+ std::string IntsStr = "{";
+ First = true;
+ for (unsigned I = 0; I < CTNType->getNumIntParameters(); ++I) {
+ if (!First)
+ IntsStr += ", ";
+ IntsStr += std::to_string(CTNType->getIntParameter(I));
+ First = false;
+ }
+ IntsStr += "}";
+
+ return formatv("{0}ConstantTargetNone::get({0}TargetExtType::get({1}, "
+ "\"{2}\", {3}, {4}))",
+ LLVMPrefix, Ctx, escape(CTNType->getName().str()), TypeStr,
+ IntsStr);
+ }
+ if (isa<ConstantTokenNone>(C)) {
+ return formatv("{0}ConstantTokenNone::get({1})", LLVMPrefix, Ctx);
+ }
+ if (auto CE = dyn_cast<ConstantExpr>(C)) {
+ (void)CE;
+ return "/* TODO: ConstantExpr creation */";
+ // TODO: Dunno how to create this... Fails either on out of range or
+ // even on incorrect opcode.
+ // return LLVMPrefix + "ConstantExpr::get(" +
+ // std::to_string(CE->getOpcode()) + ", " +
+ // asStr(CE->getOperand(0)) + ", " + asStr(CE->getOperand(1)) + ")";
+ }
+ if (auto CE = dyn_cast<ConstantPtrAuth>(C)) {
+ (void)CE;
+ return "/* TODO: ConstantPtrAuth value creation */";
+ }
+ if (auto CE = dyn_cast<DSOLocalEquivalent>(C)) {
+ (void)CE;
+ return "/* TODO: DSOLocalEquivalent value creation */";
+ }
+ if (auto CE = dyn_cast<NoCFIValue>(C)) {
+ (void)CE;
+ return "/* TODO: NoCFIValue value creation */";
+ }
+ if (auto CE = dyn_cast<GlobalValue>(C)) {
+ // This should not really happen as asStr for Value should be always called.
+ return asStr(dyn_cast<Value>(CE));
----------------
topperc wrote:
Is this dyn_cast needed? If a cast is needed it should only be static_cast since Value is a base class of GlobalValue.
https://github.com/llvm/llvm-project/pull/117129
More information about the llvm-commits
mailing list