[llvm] IR2Builder tool for converting LLVM IR files into C++ IRBuilder API (PR #117129)
Jason Eckhardt via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 21 08:04:19 PST 2024
================
@@ -0,0 +1,1702 @@
+//===-- 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/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 getLinkage(GlobalValue &gv);
+ std::string getThreadLocalMode(GlobalValue::ThreadLocalMode tlm);
+ std::string getCmpPredicate(CmpInst::Predicate p);
+ std::string getAtomicRMWOp(AtomicRMWInst::BinOp op);
+ std::string getAtomicOrdering(AtomicOrdering ao);
+ std::string getSyncScopeID(SyncScope::ID sys);
+ std::string getCallingConv(CallingConv::ID cc);
+ std::string getConstantRange(ConstantRange &cr);
+
+ std::string getVal(const Value *op);
+ std::string getConst(const Constant *op);
+ std::string getType(const Type *t);
+ std::string getInlineAsm(const InlineAsm *op);
+ std::string getMetadata(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 to_str(bool b) { return b ? "true" : "false"; }
+
+static std::string escape(std::string str) {
+ std::stringstream ss;
+ for (unsigned char C : str) {
+ if (C == '\\')
+ ss << '\\' << C;
+ else if (isPrint(C) && C != '"')
+ ss << C;
+ else
+ ss << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+ }
+ return ss.str();
+}
+
+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::getLinkage(llvm::GlobalValue &gv) {
+ std::string link = llvmPrefix + "GlobalValue::";
+
+ if (gv.hasExternalLinkage()) {
+ return link + "ExternalLinkage";
+ }
+ if (gv.hasAvailableExternallyLinkage()) {
+ return link + "AvailableExternallyLinkage";
+ }
+ if (gv.hasLinkOnceAnyLinkage()) {
+ return link + "LinkOnceAnyLinkage";
+ }
+ if (gv.hasLinkOnceODRLinkage()) {
+ return link + "LinkOnceODRLinkage";
+ }
+ if (gv.hasWeakAnyLinkage()) {
+ return link + "WeakAnyLinkage";
+ }
+ if (gv.hasWeakODRLinkage()) {
+ return link + "WeakODRLinkage";
+ }
+ if (gv.hasAppendingLinkage()) {
+ return link + "AppendingLinkage";
+ }
+ if (gv.hasInternalLinkage()) {
+ return link + "InternalLinkage";
+ }
+ if (gv.hasPrivateLinkage()) {
+ return link + "PrivateLinkage";
+ }
+ if (gv.hasExternalWeakLinkage()) {
+ return link + "ExternalWeakLinkage";
+ }
+ if (gv.hasCommonLinkage()) {
+ return link + "CommonLinkage";
+ }
+
+ return "/* Unknown linkage */";
+}
+
+std::string IR2Builder::getAtomicRMWOp(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::getAtomicOrdering(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::getCmpPredicate(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::getSyncScopeID(SyncScope::ID sys) {
+ if (sys == SyncScope::System)
+ return llvmPrefix + "SyncScope::System";
+ else if (sys == SyncScope::SingleThread)
+ return llvmPrefix + "SyncScope::SingleThread";
+ else
+ return "/* TODO: Unknown SyncScope ID (using value) */ " +
+ std::to_string(sys);
+}
+
+std::string IR2Builder::getThreadLocalMode(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::getCallingConv(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::getType(const Type *t) {
+ std::string tcall;
+ if (auto tt = dyn_cast<IntegerType>(t)) {
+ switch (tt->getBitWidth()) {
+ case 8:
+ tcall = "getInt8Ty()";
+ break;
+ case 16:
+ tcall = "getInt16Ty()";
+ break;
+ case 32:
+ tcall = "getInt32Ty()";
+ break;
+ case 64:
+ tcall = "getInt64Ty()";
+ break;
+ default:
+ tcall = "getIntNTy(" + std::to_string(tt->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 += getType(e);
+ first = false;
+ }
+ if (st->getNumElements() > 1)
+ elements += "}";
+ elements += ")";
+ return llvmPrefix + "StructType::create(" + ctx + ", " + elements + ")";
+ } else if (auto at = dyn_cast<ArrayType>(t)) {
+ return llvmPrefix + "ArrayType::get(" + getType(at->getElementType()) +
+ ", " + std::to_string(at->getArrayNumElements()) + ")";
+ } else if (t->isBFloatTy())
+ tcall = "getBFloatTy()";
+ else if (auto vt = dyn_cast<VectorType>(t)) {
+ std::string elemCount =
+ llvmPrefix + "ElementCount::get(" +
+ std::to_string(vt->getElementCount().getKnownMinValue()) + ", " +
+ to_str(vt->getElementCount().isScalable()) + ")";
+ return llvmPrefix + "VectorType::get(" + getType(vt->getElementType()) +
+ ", " + elemCount + ")";
+ } else if (auto ft = dyn_cast<FunctionType>(t)) {
+ tcall = llvmPrefix + "FunctionType::get(" + getType(ft->getReturnType()) +
+ ", {";
+
+ bool isFirst = true;
+ for (auto a : ft->params()) {
+ if (!isFirst)
+ tcall += ", ";
+ tcall += getType(a);
+ isFirst = false;
+ }
+ tcall += "}, " + to_str(ft->isVarArg()) + ")";
+ return tcall;
+ } else if (t->isPointerTy())
+ tcall = "getPtrTy()";
+ else if (t->isHalfTy()) {
+ return llvmPrefix + "Type::getHalfTy(" + ctx + ")";
+ } else if (t->isBFloatTy()) {
+ return llvmPrefix + "Type::getBFloatTy(" + ctx + ")";
+ } else if (t->isX86_FP80Ty()) {
+ return llvmPrefix + "Type::getX86_FP80Ty(" + ctx + ")";
+ } else if (t->isFP128Ty()) {
+ return llvmPrefix + "Type::getFP128Ty(" + ctx + ")";
+ } else if (t->isPPC_FP128Ty()) {
+ return llvmPrefix + "Type::getPPC_FP128Ty(" + ctx + ")";
+ } else if (t->isX86_AMXTy()) {
+ return llvmPrefix + "Type::getX86_AMXTy(" + ctx + ")";
+ } else if (t->isLabelTy()) {
+ return llvmPrefix + "Type::getLabelTy(" + ctx + ")";
+ } else if (t->isMetadataTy()) {
+ return llvmPrefix + "Type::getMetadataTy(" + ctx + ")";
+ } else if (t->isTokenTy()) {
+ return llvmPrefix + "Type::getTokenTy(" + ctx + ")";
+ } else {
+ return "/* TODO: Unknown type */";
+ }
+
+ return builder + "." + tcall;
+}
+
+std::string IR2Builder::getConst(const Constant *c) {
+ if (auto ci = dyn_cast<ConstantInt>(c)) {
+ // TODO: Sign has to be determined
+ auto cval = ci->getValue();
+ return llvmPrefix + "ConstantInt::get(" + getType(c->getType()) + ", " +
+ std::to_string(cval.getSExtValue()) + ")";
+ } else 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 llvmPrefix + "ConstantFP::get(" + getType(c->getType()) + ", " +
+ val + ")";
+ } else 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 += getVal(at->getOperand(i));
+ first = false;
+ }
+
+ std::string className;
+ if (isa<ConstantArray>(c)) {
+ className = "ConstantArray";
+ values = llvmPrefix + "ArrayRef<" + llvmPrefix + "Constant *>(" +
+ (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 llvmPrefix + "ConstantVector::get(" + values + ")";
+ } else
+ return "/* TODO: Unknown aggregate constant */";
+
+ return llvmPrefix + className + "::get(" + getType(c->getType()) + ", " +
+ values + ")";
+ } else 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));
+ }
+ }
+ return llvmPrefix + className + "::get(" + ctx + ", " + llvmPrefix +
+ "ArrayRef<uint8_t>({" + values + "}))";
+ } else 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));
+ }
+ }
+ return llvmPrefix + className + "::get(" + ctx + ", " + llvmPrefix +
+ "ArrayRef<uint8_t>({" + 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 = llvmPrefix + "ArrayRef<" + 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 llvmPrefix + className + "::get(" + ctx + ", " + values + ")";
+ } else if (isa<ConstantAggregateZero>(c)) {
+ return llvmPrefix + "ConstantAggregateZero::get(" + getType(c->getType()) +
+ ")";
+ } else if (isa<PoisonValue>(c)) {
+ return llvmPrefix + "PoisonValue::get(" + getType(c->getType()) + ")";
+ } else if (isa<UndefValue>(c)) {
+ return llvmPrefix + "UndefValue::get(" + getType(c->getType()) + ")";
+ } else if (auto ba = dyn_cast<BlockAddress>(c)) {
+ return llvmPrefix + "BlockAddress::get(" + getVal(ba->getFunction()) +
+ ", " + getVal(ba->getBasicBlock()) + ")";
+ } else if (isa<ConstantPointerNull>(c)) {
+ return llvmPrefix + "ConstantPointerNull::get(" + getType(c->getType()) +
+ ")";
+ } else if (auto ctn = dyn_cast<ConstantTargetNone>(c)) {
+ auto tetType = ctn->getType();
+
+ std::string typeStr = "{";
+ bool first = true;
+ for (unsigned i = 0; i < tetType->getNumTypeParameters(); ++i) {
+ if (!first)
+ typeStr += ", ";
+ typeStr += getType(tetType->getTypeParameter(i));
+ first = false;
+ }
+ typeStr += "}";
+
+ std::string intsStr = "{";
+ first = true;
+ for (unsigned i = 0; i < tetType->getNumIntParameters(); ++i) {
+ if (!first)
+ intsStr += ", ";
+ intsStr += std::to_string(tetType->getIntParameter(i));
+ first = false;
+ }
+ intsStr += "}";
+
+ std::string tetName = "\"" + escape(tetType->getName().str()) + "\"";
+ std::string tet = llvmPrefix + "TargetExtType::get(" + ctx + ", " +
+ tetName + ", " + typeStr + ", " + intsStr + ")";
+
+ return llvmPrefix + "ConstantTargetNone::get(" + tet + ")";
+ } else if (isa<ConstantTokenNone>(c)) {
+ return llvmPrefix + "ConstantTokenNone::get(" + ctx + ")";
+ } else 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()) + ", " +
+ // getVal(ce->getOperand(0)) + ", " + getVal(ce->getOperand(1)) + ")";
+ } else if (auto ce = dyn_cast<ConstantPtrAuth>(c)) {
+ (void)ce;
+ return "/* TODO: ConstantPtrAuth value creation */";
----------------
nvjle wrote:
CS nit: This recommendation (https://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return) might apply to the whole `if` block.
https://github.com/llvm/llvm-project/pull/117129
More information about the llvm-commits
mailing list