1 //===- LLVMToLLVMIRTranslation.cpp - Translate LLVM dialect to LLVM IR ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a translation between the MLIR LLVM dialect and LLVM IR.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
14 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15 #include "mlir/IR/Operation.h"
16 #include "mlir/Support/LLVM.h"
17 #include "mlir/Target/LLVMIR/ModuleTranslation.h"
18
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/IR/InlineAsm.h"
21 #include "llvm/IR/MDBuilder.h"
22 #include "llvm/IR/MatrixBuilder.h"
23 #include "llvm/IR/Operator.h"
24
25 using namespace mlir;
26 using namespace mlir::LLVM;
27 using mlir::LLVM::detail::getLLVMConstant;
28
29 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
30
31 /// Convert MLIR integer comparison predicate to LLVM IR comparison predicate.
getLLVMCmpPredicate(ICmpPredicate p)32 static llvm::CmpInst::Predicate getLLVMCmpPredicate(ICmpPredicate p) {
33 switch (p) {
34 case LLVM::ICmpPredicate::eq:
35 return llvm::CmpInst::Predicate::ICMP_EQ;
36 case LLVM::ICmpPredicate::ne:
37 return llvm::CmpInst::Predicate::ICMP_NE;
38 case LLVM::ICmpPredicate::slt:
39 return llvm::CmpInst::Predicate::ICMP_SLT;
40 case LLVM::ICmpPredicate::sle:
41 return llvm::CmpInst::Predicate::ICMP_SLE;
42 case LLVM::ICmpPredicate::sgt:
43 return llvm::CmpInst::Predicate::ICMP_SGT;
44 case LLVM::ICmpPredicate::sge:
45 return llvm::CmpInst::Predicate::ICMP_SGE;
46 case LLVM::ICmpPredicate::ult:
47 return llvm::CmpInst::Predicate::ICMP_ULT;
48 case LLVM::ICmpPredicate::ule:
49 return llvm::CmpInst::Predicate::ICMP_ULE;
50 case LLVM::ICmpPredicate::ugt:
51 return llvm::CmpInst::Predicate::ICMP_UGT;
52 case LLVM::ICmpPredicate::uge:
53 return llvm::CmpInst::Predicate::ICMP_UGE;
54 }
55 llvm_unreachable("incorrect comparison predicate");
56 }
57
getLLVMCmpPredicate(FCmpPredicate p)58 static llvm::CmpInst::Predicate getLLVMCmpPredicate(FCmpPredicate p) {
59 switch (p) {
60 case LLVM::FCmpPredicate::_false:
61 return llvm::CmpInst::Predicate::FCMP_FALSE;
62 case LLVM::FCmpPredicate::oeq:
63 return llvm::CmpInst::Predicate::FCMP_OEQ;
64 case LLVM::FCmpPredicate::ogt:
65 return llvm::CmpInst::Predicate::FCMP_OGT;
66 case LLVM::FCmpPredicate::oge:
67 return llvm::CmpInst::Predicate::FCMP_OGE;
68 case LLVM::FCmpPredicate::olt:
69 return llvm::CmpInst::Predicate::FCMP_OLT;
70 case LLVM::FCmpPredicate::ole:
71 return llvm::CmpInst::Predicate::FCMP_OLE;
72 case LLVM::FCmpPredicate::one:
73 return llvm::CmpInst::Predicate::FCMP_ONE;
74 case LLVM::FCmpPredicate::ord:
75 return llvm::CmpInst::Predicate::FCMP_ORD;
76 case LLVM::FCmpPredicate::ueq:
77 return llvm::CmpInst::Predicate::FCMP_UEQ;
78 case LLVM::FCmpPredicate::ugt:
79 return llvm::CmpInst::Predicate::FCMP_UGT;
80 case LLVM::FCmpPredicate::uge:
81 return llvm::CmpInst::Predicate::FCMP_UGE;
82 case LLVM::FCmpPredicate::ult:
83 return llvm::CmpInst::Predicate::FCMP_ULT;
84 case LLVM::FCmpPredicate::ule:
85 return llvm::CmpInst::Predicate::FCMP_ULE;
86 case LLVM::FCmpPredicate::une:
87 return llvm::CmpInst::Predicate::FCMP_UNE;
88 case LLVM::FCmpPredicate::uno:
89 return llvm::CmpInst::Predicate::FCMP_UNO;
90 case LLVM::FCmpPredicate::_true:
91 return llvm::CmpInst::Predicate::FCMP_TRUE;
92 }
93 llvm_unreachable("incorrect comparison predicate");
94 }
95
getLLVMAtomicBinOp(AtomicBinOp op)96 static llvm::AtomicRMWInst::BinOp getLLVMAtomicBinOp(AtomicBinOp op) {
97 switch (op) {
98 case LLVM::AtomicBinOp::xchg:
99 return llvm::AtomicRMWInst::BinOp::Xchg;
100 case LLVM::AtomicBinOp::add:
101 return llvm::AtomicRMWInst::BinOp::Add;
102 case LLVM::AtomicBinOp::sub:
103 return llvm::AtomicRMWInst::BinOp::Sub;
104 case LLVM::AtomicBinOp::_and:
105 return llvm::AtomicRMWInst::BinOp::And;
106 case LLVM::AtomicBinOp::nand:
107 return llvm::AtomicRMWInst::BinOp::Nand;
108 case LLVM::AtomicBinOp::_or:
109 return llvm::AtomicRMWInst::BinOp::Or;
110 case LLVM::AtomicBinOp::_xor:
111 return llvm::AtomicRMWInst::BinOp::Xor;
112 case LLVM::AtomicBinOp::max:
113 return llvm::AtomicRMWInst::BinOp::Max;
114 case LLVM::AtomicBinOp::min:
115 return llvm::AtomicRMWInst::BinOp::Min;
116 case LLVM::AtomicBinOp::umax:
117 return llvm::AtomicRMWInst::BinOp::UMax;
118 case LLVM::AtomicBinOp::umin:
119 return llvm::AtomicRMWInst::BinOp::UMin;
120 case LLVM::AtomicBinOp::fadd:
121 return llvm::AtomicRMWInst::BinOp::FAdd;
122 case LLVM::AtomicBinOp::fsub:
123 return llvm::AtomicRMWInst::BinOp::FSub;
124 }
125 llvm_unreachable("incorrect atomic binary operator");
126 }
127
getLLVMAtomicOrdering(AtomicOrdering ordering)128 static llvm::AtomicOrdering getLLVMAtomicOrdering(AtomicOrdering ordering) {
129 switch (ordering) {
130 case LLVM::AtomicOrdering::not_atomic:
131 return llvm::AtomicOrdering::NotAtomic;
132 case LLVM::AtomicOrdering::unordered:
133 return llvm::AtomicOrdering::Unordered;
134 case LLVM::AtomicOrdering::monotonic:
135 return llvm::AtomicOrdering::Monotonic;
136 case LLVM::AtomicOrdering::acquire:
137 return llvm::AtomicOrdering::Acquire;
138 case LLVM::AtomicOrdering::release:
139 return llvm::AtomicOrdering::Release;
140 case LLVM::AtomicOrdering::acq_rel:
141 return llvm::AtomicOrdering::AcquireRelease;
142 case LLVM::AtomicOrdering::seq_cst:
143 return llvm::AtomicOrdering::SequentiallyConsistent;
144 }
145 llvm_unreachable("incorrect atomic ordering");
146 }
147
getFastmathFlags(FastmathFlagsInterface & op)148 static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op) {
149 using llvmFMF = llvm::FastMathFlags;
150 using FuncT = void (llvmFMF::*)(bool);
151 const std::pair<FastmathFlags, FuncT> handlers[] = {
152 // clang-format off
153 {FastmathFlags::nnan, &llvmFMF::setNoNaNs},
154 {FastmathFlags::ninf, &llvmFMF::setNoInfs},
155 {FastmathFlags::nsz, &llvmFMF::setNoSignedZeros},
156 {FastmathFlags::arcp, &llvmFMF::setAllowReciprocal},
157 {FastmathFlags::contract, &llvmFMF::setAllowContract},
158 {FastmathFlags::afn, &llvmFMF::setApproxFunc},
159 {FastmathFlags::reassoc, &llvmFMF::setAllowReassoc},
160 // clang-format on
161 };
162 llvm::FastMathFlags ret;
163 auto fmf = op.getFastmathFlags();
164 for (auto it : handlers)
165 if (bitEnumContains(fmf, it.first))
166 (ret.*(it.second))(true);
167 return ret;
168 }
169
170 /// Returns an LLVM metadata node corresponding to a loop option. This metadata
171 /// is attached to an llvm.loop node.
getLoopOptionMetadata(llvm::LLVMContext & ctx,LoopOptionCase option,int64_t value)172 static llvm::MDNode *getLoopOptionMetadata(llvm::LLVMContext &ctx,
173 LoopOptionCase option,
174 int64_t value) {
175 StringRef name;
176 llvm::Constant *cstValue = nullptr;
177 switch (option) {
178 case LoopOptionCase::disable_licm:
179 name = "llvm.licm.disable";
180 cstValue = llvm::ConstantInt::getBool(ctx, value);
181 break;
182 case LoopOptionCase::disable_unroll:
183 name = "llvm.loop.unroll.disable";
184 cstValue = llvm::ConstantInt::getBool(ctx, value);
185 break;
186 case LoopOptionCase::interleave_count:
187 name = "llvm.loop.interleave.count";
188 cstValue = llvm::ConstantInt::get(
189 llvm::IntegerType::get(ctx, /*NumBits=*/32), value);
190 break;
191 case LoopOptionCase::disable_pipeline:
192 name = "llvm.loop.pipeline.disable";
193 cstValue = llvm::ConstantInt::getBool(ctx, value);
194 break;
195 case LoopOptionCase::pipeline_initiation_interval:
196 name = "llvm.loop.pipeline.initiationinterval";
197 cstValue = llvm::ConstantInt::get(
198 llvm::IntegerType::get(ctx, /*NumBits=*/32), value);
199 break;
200 }
201 return llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name),
202 llvm::ConstantAsMetadata::get(cstValue)});
203 }
204
setLoopMetadata(Operation & opInst,llvm::Instruction & llvmInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)205 static void setLoopMetadata(Operation &opInst, llvm::Instruction &llvmInst,
206 llvm::IRBuilderBase &builder,
207 LLVM::ModuleTranslation &moduleTranslation) {
208 if (Attribute attr = opInst.getAttr(LLVMDialect::getLoopAttrName())) {
209 llvm::Module *module = builder.GetInsertBlock()->getModule();
210 llvm::MDNode *loopMD = moduleTranslation.lookupLoopOptionsMetadata(attr);
211 if (!loopMD) {
212 llvm::LLVMContext &ctx = module->getContext();
213
214 SmallVector<llvm::Metadata *> loopOptions;
215 // Reserve operand 0 for loop id self reference.
216 auto dummy = llvm::MDNode::getTemporary(ctx, llvm::None);
217 loopOptions.push_back(dummy.get());
218
219 auto loopAttr = attr.cast<DictionaryAttr>();
220 auto parallelAccessGroup =
221 loopAttr.getNamed(LLVMDialect::getParallelAccessAttrName());
222 if (parallelAccessGroup) {
223 SmallVector<llvm::Metadata *> parallelAccess;
224 parallelAccess.push_back(
225 llvm::MDString::get(ctx, "llvm.loop.parallel_accesses"));
226 for (SymbolRefAttr accessGroupRef : parallelAccessGroup->getValue()
227 .cast<ArrayAttr>()
228 .getAsRange<SymbolRefAttr>())
229 parallelAccess.push_back(
230 moduleTranslation.getAccessGroup(opInst, accessGroupRef));
231 loopOptions.push_back(llvm::MDNode::get(ctx, parallelAccess));
232 }
233
234 if (auto loopOptionsAttr = loopAttr.getAs<LoopOptionsAttr>(
235 LLVMDialect::getLoopOptionsAttrName())) {
236 for (auto option : loopOptionsAttr.getOptions())
237 loopOptions.push_back(
238 getLoopOptionMetadata(ctx, option.first, option.second));
239 }
240
241 // Create loop options and set the first operand to itself.
242 loopMD = llvm::MDNode::get(ctx, loopOptions);
243 loopMD->replaceOperandWith(0, loopMD);
244
245 // Store a map from this Attribute to the LLVM metadata in case we
246 // encounter it again.
247 moduleTranslation.mapLoopOptionsMetadata(attr, loopMD);
248 }
249
250 llvmInst.setMetadata(module->getMDKindID("llvm.loop"), loopMD);
251 }
252 }
253
254 static LogicalResult
convertOperationImpl(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)255 convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
256 LLVM::ModuleTranslation &moduleTranslation) {
257 auto extractPosition = [](ArrayAttr attr) {
258 SmallVector<unsigned, 4> position;
259 position.reserve(attr.size());
260 for (Attribute v : attr)
261 position.push_back(v.cast<IntegerAttr>().getValue().getZExtValue());
262 return position;
263 };
264
265 llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
266 if (auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
267 builder.setFastMathFlags(getFastmathFlags(fmf));
268
269 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
270 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
271
272 // Emit function calls. If the "callee" attribute is present, this is a
273 // direct function call and we also need to look up the remapped function
274 // itself. Otherwise, this is an indirect call and the callee is the first
275 // operand, look it up as a normal value. Return the llvm::Value representing
276 // the function result, which may be of llvm::VoidTy type.
277 auto convertCall = [&](Operation &op) -> llvm::Value * {
278 auto operands = moduleTranslation.lookupValues(op.getOperands());
279 ArrayRef<llvm::Value *> operandsRef(operands);
280 if (auto attr = op.getAttrOfType<FlatSymbolRefAttr>("callee"))
281 return builder.CreateCall(
282 moduleTranslation.lookupFunction(attr.getValue()), operandsRef);
283 auto calleeType =
284 op.getOperands().front().getType().cast<LLVMPointerType>();
285 auto *calleeFunctionType = cast<llvm::FunctionType>(
286 moduleTranslation.convertType(calleeType.getElementType()));
287 return builder.CreateCall(calleeFunctionType, operandsRef.front(),
288 operandsRef.drop_front());
289 };
290
291 // Emit calls. If the called function has a result, remap the corresponding
292 // value. Note that LLVM IR dialect CallOp has either 0 or 1 result.
293 if (isa<LLVM::CallOp>(opInst)) {
294 llvm::Value *result = convertCall(opInst);
295 if (opInst.getNumResults() != 0) {
296 moduleTranslation.mapValue(opInst.getResult(0), result);
297 return success();
298 }
299 // Check that LLVM call returns void for 0-result functions.
300 return success(result->getType()->isVoidTy());
301 }
302
303 if (auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
304 // TODO: refactor function type creation which usually occurs in std-LLVM
305 // conversion.
306 SmallVector<Type, 8> operandTypes;
307 llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
308
309 Type resultType;
310 if (inlineAsmOp.getNumResults() == 0) {
311 resultType = LLVM::LLVMVoidType::get(&moduleTranslation.getContext());
312 } else {
313 assert(inlineAsmOp.getNumResults() == 1);
314 resultType = inlineAsmOp.getResultTypes()[0];
315 }
316 auto ft = LLVM::LLVMFunctionType::get(resultType, operandTypes);
317 llvm::InlineAsm *inlineAsmInst =
318 inlineAsmOp.getAsmDialect()
319 ? llvm::InlineAsm::get(
320 static_cast<llvm::FunctionType *>(
321 moduleTranslation.convertType(ft)),
322 inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
323 inlineAsmOp.getHasSideEffects(),
324 inlineAsmOp.getIsAlignStack(),
325 convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
326 : llvm::InlineAsm::get(static_cast<llvm::FunctionType *>(
327 moduleTranslation.convertType(ft)),
328 inlineAsmOp.getAsmString(),
329 inlineAsmOp.getConstraints(),
330 inlineAsmOp.getHasSideEffects(),
331 inlineAsmOp.getIsAlignStack());
332 llvm::CallInst *inst = builder.CreateCall(
333 inlineAsmInst,
334 moduleTranslation.lookupValues(inlineAsmOp.getOperands()));
335 if (auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
336 llvm::AttributeList attrList;
337 for (const auto &it : llvm::enumerate(*maybeOperandAttrs)) {
338 Attribute attr = it.value();
339 if (!attr)
340 continue;
341 DictionaryAttr dAttr = attr.cast<DictionaryAttr>();
342 TypeAttr tAttr =
343 dAttr.get(InlineAsmOp::getElementTypeAttrName()).cast<TypeAttr>();
344 llvm::AttrBuilder b(moduleTranslation.getLLVMContext());
345 llvm::Type *ty = moduleTranslation.convertType(tAttr.getValue());
346 b.addTypeAttr(llvm::Attribute::ElementType, ty);
347 // shift to account for the returned value (this is always 1 aggregate
348 // value in LLVM).
349 int shift = (opInst.getNumResults() > 0) ? 1 : 0;
350 attrList = attrList.addAttributesAtIndex(
351 moduleTranslation.getLLVMContext(), it.index() + shift, b);
352 }
353 inst->setAttributes(attrList);
354 }
355
356 if (opInst.getNumResults() != 0)
357 moduleTranslation.mapValue(opInst.getResult(0), inst);
358 return success();
359 }
360
361 if (auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
362 auto operands = moduleTranslation.lookupValues(invOp.getCalleeOperands());
363 ArrayRef<llvm::Value *> operandsRef(operands);
364 llvm::Instruction *result;
365 if (auto attr = opInst.getAttrOfType<FlatSymbolRefAttr>("callee")) {
366 result = builder.CreateInvoke(
367 moduleTranslation.lookupFunction(attr.getValue()),
368 moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
369 moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef);
370 } else {
371 auto calleeType =
372 invOp.getCalleeOperands().front().getType().cast<LLVMPointerType>();
373 auto *calleeFunctionType = cast<llvm::FunctionType>(
374 moduleTranslation.convertType(calleeType.getElementType()));
375 result = builder.CreateInvoke(
376 calleeFunctionType, operandsRef.front(),
377 moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
378 moduleTranslation.lookupBlock(invOp.getSuccessor(1)),
379 operandsRef.drop_front());
380 }
381 moduleTranslation.mapBranch(invOp, result);
382 // InvokeOp can only have 0 or 1 result
383 if (invOp->getNumResults() != 0) {
384 moduleTranslation.mapValue(opInst.getResult(0), result);
385 return success();
386 }
387 return success(result->getType()->isVoidTy());
388 }
389
390 if (auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
391 llvm::Type *ty = moduleTranslation.convertType(lpOp.getType());
392 llvm::LandingPadInst *lpi =
393 builder.CreateLandingPad(ty, lpOp.getNumOperands());
394 lpi->setCleanup(lpOp.getCleanup());
395
396 // Add clauses
397 for (llvm::Value *operand :
398 moduleTranslation.lookupValues(lpOp.getOperands())) {
399 // All operands should be constant - checked by verifier
400 if (auto *constOperand = dyn_cast<llvm::Constant>(operand))
401 lpi->addClause(constOperand);
402 }
403 moduleTranslation.mapValue(lpOp.getResult(), lpi);
404 return success();
405 }
406
407 // Emit branches. We need to look up the remapped blocks and ignore the block
408 // arguments that were transformed into PHI nodes.
409 if (auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
410 llvm::BranchInst *branch =
411 builder.CreateBr(moduleTranslation.lookupBlock(brOp.getSuccessor()));
412 moduleTranslation.mapBranch(&opInst, branch);
413 setLoopMetadata(opInst, *branch, builder, moduleTranslation);
414 return success();
415 }
416 if (auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
417 llvm::MDNode *branchWeights = nullptr;
418 if (auto weights = condbrOp.getBranchWeights()) {
419 // Map weight attributes to LLVM metadata.
420 auto weightValues = weights->getValues<APInt>();
421 auto trueWeight = weightValues[0].getSExtValue();
422 auto falseWeight = weightValues[1].getSExtValue();
423 branchWeights =
424 llvm::MDBuilder(moduleTranslation.getLLVMContext())
425 .createBranchWeights(static_cast<uint32_t>(trueWeight),
426 static_cast<uint32_t>(falseWeight));
427 }
428 llvm::BranchInst *branch = builder.CreateCondBr(
429 moduleTranslation.lookupValue(condbrOp.getOperand(0)),
430 moduleTranslation.lookupBlock(condbrOp.getSuccessor(0)),
431 moduleTranslation.lookupBlock(condbrOp.getSuccessor(1)), branchWeights);
432 moduleTranslation.mapBranch(&opInst, branch);
433 setLoopMetadata(opInst, *branch, builder, moduleTranslation);
434 return success();
435 }
436 if (auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
437 llvm::MDNode *branchWeights = nullptr;
438 if (auto weights = switchOp.getBranchWeights()) {
439 llvm::SmallVector<uint32_t> weightValues;
440 weightValues.reserve(weights->size());
441 for (llvm::APInt weight : weights->cast<DenseIntElementsAttr>())
442 weightValues.push_back(weight.getLimitedValue());
443 branchWeights = llvm::MDBuilder(moduleTranslation.getLLVMContext())
444 .createBranchWeights(weightValues);
445 }
446
447 llvm::SwitchInst *switchInst = builder.CreateSwitch(
448 moduleTranslation.lookupValue(switchOp.getValue()),
449 moduleTranslation.lookupBlock(switchOp.getDefaultDestination()),
450 switchOp.getCaseDestinations().size(), branchWeights);
451
452 auto *ty = llvm::cast<llvm::IntegerType>(
453 moduleTranslation.convertType(switchOp.getValue().getType()));
454 for (auto i :
455 llvm::zip(switchOp.getCaseValues()->cast<DenseIntElementsAttr>(),
456 switchOp.getCaseDestinations()))
457 switchInst->addCase(
458 llvm::ConstantInt::get(ty, std::get<0>(i).getLimitedValue()),
459 moduleTranslation.lookupBlock(std::get<1>(i)));
460
461 moduleTranslation.mapBranch(&opInst, switchInst);
462 return success();
463 }
464
465 // Emit addressof. We need to look up the global value referenced by the
466 // operation and store it in the MLIR-to-LLVM value mapping. This does not
467 // emit any LLVM instruction.
468 if (auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
469 LLVM::GlobalOp global = addressOfOp.getGlobal();
470 LLVM::LLVMFuncOp function = addressOfOp.getFunction();
471
472 // The verifier should not have allowed this.
473 assert((global || function) &&
474 "referencing an undefined global or function");
475
476 moduleTranslation.mapValue(
477 addressOfOp.getResult(),
478 global ? moduleTranslation.lookupGlobal(global)
479 : moduleTranslation.lookupFunction(function.getName()));
480 return success();
481 }
482
483 return failure();
484 }
485
486 namespace {
487 /// Implementation of the dialect interface that converts operations belonging
488 /// to the LLVM dialect to LLVM IR.
489 class LLVMDialectLLVMIRTranslationInterface
490 : public LLVMTranslationDialectInterface {
491 public:
492 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
493
494 /// Translates the given operation to LLVM IR using the provided IR builder
495 /// and saving the state in `moduleTranslation`.
496 LogicalResult
convertOperation(Operation * op,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation) const497 convertOperation(Operation *op, llvm::IRBuilderBase &builder,
498 LLVM::ModuleTranslation &moduleTranslation) const final {
499 return convertOperationImpl(*op, builder, moduleTranslation);
500 }
501 };
502 } // namespace
503
registerLLVMDialectTranslation(DialectRegistry & registry)504 void mlir::registerLLVMDialectTranslation(DialectRegistry ®istry) {
505 registry.insert<LLVM::LLVMDialect>();
506 registry.addExtension(+[](MLIRContext *ctx, LLVM::LLVMDialect *dialect) {
507 dialect->addInterfaces<LLVMDialectLLVMIRTranslationInterface>();
508 });
509 }
510
registerLLVMDialectTranslation(MLIRContext & context)511 void mlir::registerLLVMDialectTranslation(MLIRContext &context) {
512 DialectRegistry registry;
513 registerLLVMDialectTranslation(registry);
514 context.appendDialectRegistry(registry);
515 }
516