File: cir-translate.cpp

package info (click to toggle)
llvm-toolchain-21 1%3A21.1.6-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,245,028 kB
  • sloc: cpp: 7,619,726; ansic: 1,434,018; asm: 1,058,748; python: 252,740; f90: 94,671; objc: 70,685; lisp: 42,813; pascal: 18,401; sh: 8,601; ml: 5,111; perl: 4,720; makefile: 3,675; awk: 3,523; javascript: 2,409; xml: 892; fortran: 770
file content (176 lines) | stat: -rw-r--r-- 7,078 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Converts CIR directly to LLVM IR, similar to mlir-translate or LLVM llc.
//
//===----------------------------------------------------------------------===//

#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/InitAllTranslations.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Target/LLVMIR/Dialect/All.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
#include "mlir/Tools/mlir-translate/Translation.h"

#include "llvm/IR/Module.h"
#include "llvm/TargetParser/Host.h"

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/LowerToLLVM.h"
#include "clang/CIR/MissingFeatures.h"

namespace cir {
namespace direct {
extern void registerCIRDialectTranslation(mlir::DialectRegistry &registry);
} // namespace direct

namespace {

/// The goal of this option is to ensure that the triple and data layout specs
/// are always available in the ClangIR module. With this requirement met, the
/// behavior of this option is designed to be as intuitive as possible, as shown
/// in the table below:
///
/// +--------+--------+-------------+-----------------+-----------------------+
/// | Option | Triple | Data Layout | Behavior Triple | Behavior Data Layout  |
/// +========+========+=============+=================+=======================+
/// | T      | T      | T           | Overwrite       | Derive from triple    |
/// | T      | T      | F           | Overwrite       | Derive from triple    |
/// | T      | F      | T           | Overwrite       | Derive from triple    |
/// | T      | F      | F           | Overwrite       | Derive from triple    |
/// | F      | T      | T           |                 |                       |
/// | F      | T      | F           |                 | Derive from triple    |
/// | F      | F      | T           | Set default     | Derive from triple    |
/// | F      | F      | F           | Set default     | Derive from triple    |
/// +--------+--------+-------------+-----------------+-----------------------+
llvm::cl::opt<std::string>
    targetTripleOption("target",
                       llvm::cl::desc("Specify a default target triple when "
                                      "it's not available in the module"),
                       llvm::cl::init(""));

std::string prepareCIRModuleTriple(mlir::ModuleOp mod) {
  std::string triple = targetTripleOption;

  // Treat "" as the default target machine.
  if (triple.empty()) {
    triple = llvm::sys::getDefaultTargetTriple();

    mod.emitWarning() << "no target triple provided, assuming " << triple;
  }

  mod->setAttr(cir::CIRDialect::getTripleAttrName(),
               mlir::StringAttr::get(mod.getContext(), triple));
  return triple;
}

llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod,
                                               llvm::StringRef rawTriple) {
  auto *context = mod.getContext();

  // Data layout is fully determined by the target triple. Here we only pass the
  // triple to get the data layout.
  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
      new clang::DiagnosticIDs);
  clang::DiagnosticOptions diagOpts;
  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics =
      new clang::DiagnosticsEngine(diagID, diagOpts,
                                   new clang::IgnoringDiagConsumer());
  llvm::Triple triple(rawTriple);
  // TODO: Need to set various target options later to populate
  // 'TargetInfo' properly.
  clang::TargetOptions targetOptions;
  targetOptions.Triple = rawTriple;
  llvm::IntrusiveRefCntPtr<clang::TargetInfo> targetInfo =
      clang::TargetInfo::CreateTargetInfo(*diagnostics, targetOptions);
  if (!targetInfo) {
    mod.emitError() << "error: invalid target triple '" << rawTriple << "'\n";
    return llvm::failure();
  }
  std::string layoutString = targetInfo->getDataLayoutString();

  // Registered dialects may not be loaded yet, ensure they are.
  context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect>();

  mlir::DataLayoutSpecInterface dlSpec =
      mlir::translateDataLayout(llvm::DataLayout(layoutString), context);
  mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);

  return llvm::success();
}

/// Prepare requirements like cir.triple and data layout.
llvm::LogicalResult prepareCIRModuleForTranslation(mlir::ModuleOp mod) {
  auto modTriple = mod->getAttrOfType<mlir::StringAttr>(
      cir::CIRDialect::getTripleAttrName());
  auto modDataLayout = mod->getAttr(mlir::DLTIDialect::kDataLayoutAttrName);
  bool hasTargetOption = targetTripleOption.getNumOccurrences() > 0;

  // Skip the situation where nothing should be done.
  if (!hasTargetOption && modTriple && modDataLayout)
    return llvm::success();

  std::string triple;

  if (!hasTargetOption && modTriple) {
    // Do nothing if it's already set.
    triple = modTriple.getValue();
  } else {
    // Otherwise, overwrite or set default.
    triple = prepareCIRModuleTriple(mod);
  }

  // If the data layout is not set, derive it from the triple.
  return prepareCIRModuleDataLayout(mod, triple);
}
} // namespace
} // namespace cir

void registerToLLVMTranslation() {
  static llvm::cl::opt<bool> disableCCLowering(
      "disable-cc-lowering",
      llvm::cl::desc("Disable calling convention lowering pass"),
      llvm::cl::init(false));

  mlir::TranslateFromMLIRRegistration registration(
      "cir-to-llvmir", "Translate CIR to LLVMIR",
      [](mlir::Operation *op, mlir::raw_ostream &output) {
        auto cirModule = llvm::dyn_cast<mlir::ModuleOp>(op);

        if (mlir::failed(cir::prepareCIRModuleForTranslation(cirModule)))
          return mlir::failure();

        llvm::LLVMContext llvmContext;
        std::unique_ptr<llvm::Module> llvmModule =
            cir::direct::lowerDirectlyFromCIRToLLVMIR(cirModule, llvmContext);
        if (!llvmModule)
          return mlir::failure();
        llvmModule->print(output, nullptr);
        return mlir::success();
      },
      [](mlir::DialectRegistry &registry) {
        registry.insert<mlir::DLTIDialect, mlir::func::FuncDialect>();
        mlir::registerAllToLLVMIRTranslations(registry);
        cir::direct::registerCIRDialectTranslation(registry);
      });
}

int main(int argc, char **argv) {
  registerToLLVMTranslation();
  return failed(mlir::mlirTranslateMain(argc, argv, "CIR Translation Tool"));
}