[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:17 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";
+  }
----------------
nvjle wrote:

CS nit: https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements

Likewise for all other occurrences.

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


More information about the llvm-commits mailing list