[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
Thu Mar 6 13:44:47 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();
----------------
topperc wrote:

> @topperc what about ConstantFP::get(Type *Ty, StringRef Str) method or will it potentially lose bits too?

I think that would work. Hopefully APFloat can print something that ConstantFP:get can parse.

https://github.com/llvm/llvm-project/pull/117129


More information about the llvm-commits mailing list