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"
29 #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
32 using llvmFMF = llvm::FastMathFlags;
33 using FuncT = void (llvmFMF::*)(bool);
34 const std::pair<FastmathFlags, FuncT> handlers[] = {
36 {FastmathFlags::nnan, &llvmFMF::setNoNaNs},
37 {FastmathFlags::ninf, &llvmFMF::setNoInfs},
38 {FastmathFlags::nsz, &llvmFMF::setNoSignedZeros},
39 {FastmathFlags::arcp, &llvmFMF::setAllowReciprocal},
41 {FastmathFlags::afn, &llvmFMF::setApproxFunc},
42 {FastmathFlags::reassoc, &llvmFMF::setAllowReassoc},
45 llvm::FastMathFlags ret;
46 ::mlir::LLVM::FastmathFlags fmfMlir = op.getFastmathAttr().getValue();
47 for (
auto it : handlers)
48 if (bitEnumContainsAll(fmfMlir, it.first))
49 (ret.*(it.second))(
true);
56 llvm::append_range(position, indices);
61 static std::string
diagStr(
const llvm::Type *type) {
63 llvm::raw_string_ostream os(str);
71 static FailureOr<llvm::Function *>
76 for (
Type type : op->getOperandTypes())
77 allArgTys.push_back(moduleTranslation.
convertType(type));
80 if (op.getNumResults() == 0)
81 resTy = llvm::Type::getVoidTy(module->getContext());
83 resTy = moduleTranslation.
convertType(op.getResult(0).getType());
89 getIntrinsicInfoTableEntries(
id,
table);
93 if (llvm::Intrinsic::matchIntrinsicSignature(ft, tableRef,
95 llvm::Intrinsic::MatchIntrinsicTypesResult::MatchIntrinsicTypes_Match) {
97 <<
diagStr(ft) <<
" to overloaded intrinsic " << op.getIntrinAttr()
98 <<
" does not match any of the overloads";
102 return llvm::Intrinsic::getOrInsertDeclaration(module,
id,
103 overloadedArgTysRef);
106 static llvm::OperandBundleDef
109 std::vector<llvm::Value *> operands;
110 operands.reserve(bundleOperands.size());
111 for (
Value bundleArg : bundleOperands)
112 operands.push_back(moduleTranslation.
lookupValue(bundleArg));
113 return llvm::OperandBundleDef(bundleTag.str(), std::move(operands));
120 bundles.reserve(bundleOperands.size());
122 for (
auto [operands, tagAttr] : llvm::zip_equal(bundleOperands, bundleTags)) {
123 StringRef tag = cast<StringAttr>(tagAttr).getValue();
131 std::optional<ArrayAttr> bundleTags,
142 llvm::Module *module = builder.GetInsertBlock()->getModule();
144 llvm::Intrinsic::lookupIntrinsicID(op.getIntrinAttr());
147 << op.getIntrinAttr();
149 llvm::Function *fn =
nullptr;
150 if (llvm::Intrinsic::isOverloaded(
id)) {
153 if (failed(fnOrFailure))
157 fn = llvm::Intrinsic::getOrInsertDeclaration(module,
id, {});
161 const llvm::Type *intrinType =
162 op.getNumResults() == 0
163 ? llvm::Type::getVoidTy(module->getContext())
164 : moduleTranslation.
convertType(op.getResultTypes().front());
165 if (intrinType != fn->getReturnType()) {
167 <<
diagStr(intrinType) <<
" but " << op.getIntrinAttr()
168 <<
" actually returns " <<
diagStr(fn->getReturnType());
173 if (!fn->getFunctionType()->isVarArg() &&
174 op.getArgs().size() != fn->arg_size()) {
176 << op.getArgs().size() <<
" operands but " << op.getIntrinAttr()
177 <<
" expects " << fn->arg_size();
179 if (fn->getFunctionType()->isVarArg() &&
180 op.getArgs().size() < fn->arg_size()) {
182 << op.getArgs().size() <<
" operands but variadic "
183 << op.getIntrinAttr() <<
" expects at least " << fn->arg_size();
186 for (
unsigned i = 0, e = fn->arg_size(); i != e; ++i) {
187 const llvm::Type *expected = fn->getArg(i)->getType();
188 const llvm::Type *actual =
189 moduleTranslation.
convertType(op.getOperandTypes()[i]);
190 if (actual != expected) {
192 << i <<
" has type " <<
diagStr(actual) <<
" but "
193 << op.getIntrinAttr() <<
" expects " <<
diagStr(expected);
197 FastmathFlagsInterface itf = op;
200 auto *inst = builder.CreateCall(
204 if (op.getNumResults() == 1)
205 moduleTranslation.
mapValue(op->getResults().front()) = inst;
210 llvm::IRBuilderBase &builder,
212 llvm::Module *llvmModule = moduleTranslation.
getLLVMModule();
213 llvm::LLVMContext &context = llvmModule->getContext();
214 llvm::NamedMDNode *linkerMDNode =
215 llvmModule->getOrInsertNamedMetadata(
"llvm.linker.options");
217 MDNodes.reserve(
options.size());
218 for (
auto s :
options.getAsRange<StringAttr>()) {
220 MDNodes.push_back(MDNode);
224 linkerMDNode->addOperand(listMDNode);
231 llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
232 if (
auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
235 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
236 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
242 if (
auto callOp = dyn_cast<LLVM::CallOp>(opInst)) {
243 auto operands = moduleTranslation.
lookupValues(callOp.getCalleeOperands());
246 callOp.getOpBundleTags(), moduleTranslation);
248 llvm::CallInst *call;
249 if (
auto attr = callOp.getCalleeAttr()) {
251 builder.CreateCall(moduleTranslation.
lookupFunction(attr.getValue()),
252 operandsRef, opBundles);
254 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
255 moduleTranslation.
convertType(callOp.getCalleeFunctionType()));
256 call = builder.CreateCall(calleeType, operandsRef.front(),
257 operandsRef.drop_front(), opBundles);
259 call->setCallingConv(convertCConvToLLVM(callOp.getCConv()));
260 call->setTailCallKind(convertTailCallKindToLLVM(callOp.getTailCallKind()));
261 if (callOp.getConvergentAttr())
262 call->addFnAttr(llvm::Attribute::Convergent);
263 if (callOp.getNoUnwindAttr())
264 call->addFnAttr(llvm::Attribute::NoUnwind);
265 if (callOp.getWillReturnAttr())
266 call->addFnAttr(llvm::Attribute::WillReturn);
268 if (MemoryEffectsAttr memAttr = callOp.getMemoryEffectsAttr()) {
269 llvm::MemoryEffects memEffects =
270 llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
271 convertModRefInfoToLLVM(memAttr.getArgMem())) |
273 llvm::MemoryEffects::Location::InaccessibleMem,
274 convertModRefInfoToLLVM(memAttr.getInaccessibleMem())) |
275 llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
276 convertModRefInfoToLLVM(memAttr.getOther()));
277 call->setMemoryEffects(memEffects);
288 else if (!call->getType()->isVoidTy())
290 moduleTranslation.
mapCall(callOp, call);
294 if (
auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
298 llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
301 if (inlineAsmOp.getNumResults() == 0) {
304 assert(inlineAsmOp.getNumResults() == 1);
305 resultType = inlineAsmOp.getResultTypes()[0];
308 llvm::InlineAsm *inlineAsmInst =
309 inlineAsmOp.getAsmDialect()
311 static_cast<llvm::FunctionType *
>(
313 inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
314 inlineAsmOp.getHasSideEffects(),
315 inlineAsmOp.getIsAlignStack(),
316 convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
319 inlineAsmOp.getAsmString(),
320 inlineAsmOp.getConstraints(),
321 inlineAsmOp.getHasSideEffects(),
322 inlineAsmOp.getIsAlignStack());
323 llvm::CallInst *inst = builder.CreateCall(
325 moduleTranslation.
lookupValues(inlineAsmOp.getOperands()));
326 if (
auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
327 llvm::AttributeList attrList;
332 DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
334 cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
336 llvm::Type *ty = moduleTranslation.
convertType(tAttr.getValue());
337 b.addTypeAttr(llvm::Attribute::ElementType, ty);
341 attrList = attrList.addAttributesAtIndex(
344 inst->setAttributes(attrList);
352 if (
auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
353 auto operands = moduleTranslation.
lookupValues(invOp.getCalleeOperands());
356 invOp.getOpBundleTags(), moduleTranslation);
358 llvm::InvokeInst *result;
360 result = builder.CreateInvoke(
362 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
363 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)), operandsRef,
366 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
367 moduleTranslation.
convertType(invOp.getCalleeFunctionType()));
368 result = builder.CreateInvoke(
369 calleeType, operandsRef.front(),
370 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
371 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)),
372 operandsRef.drop_front(), opBundles);
374 result->setCallingConv(convertCConvToLLVM(invOp.getCConv()));
375 moduleTranslation.
mapBranch(invOp, result);
377 if (invOp->getNumResults() != 0) {
381 return success(result->getType()->isVoidTy());
384 if (
auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
385 llvm::Type *ty = moduleTranslation.
convertType(lpOp.getType());
386 llvm::LandingPadInst *lpi =
387 builder.CreateLandingPad(ty, lpOp.getNumOperands());
388 lpi->setCleanup(lpOp.getCleanup());
391 for (llvm::Value *operand :
394 if (
auto *constOperand = dyn_cast<llvm::Constant>(operand))
395 lpi->addClause(constOperand);
397 moduleTranslation.
mapValue(lpOp.getResult(), lpi);
403 if (
auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
404 llvm::BranchInst *branch =
405 builder.CreateBr(moduleTranslation.
lookupBlock(brOp.getSuccessor()));
406 moduleTranslation.
mapBranch(&opInst, branch);
410 if (
auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
411 llvm::BranchInst *branch = builder.CreateCondBr(
412 moduleTranslation.
lookupValue(condbrOp.getOperand(0)),
413 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(0)),
414 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(1)));
415 moduleTranslation.
mapBranch(&opInst, branch);
419 if (
auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
420 llvm::SwitchInst *switchInst = builder.CreateSwitch(
421 moduleTranslation.
lookupValue(switchOp.getValue()),
422 moduleTranslation.
lookupBlock(switchOp.getDefaultDestination()),
423 switchOp.getCaseDestinations().size());
426 if (!switchOp.getCaseValues())
429 auto *ty = llvm::cast<llvm::IntegerType>(
430 moduleTranslation.
convertType(switchOp.getValue().getType()));
432 llvm::zip(llvm::cast<DenseIntElementsAttr>(*switchOp.getCaseValues()),
433 switchOp.getCaseDestinations()))
438 moduleTranslation.
mapBranch(&opInst, switchInst);
445 if (
auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
446 LLVM::GlobalOp global =
447 addressOfOp.getGlobal(moduleTranslation.
symbolTable());
448 LLVM::LLVMFuncOp
function =
449 addressOfOp.getFunction(moduleTranslation.
symbolTable());
452 assert((global ||
function) &&
453 "referencing an undefined global or function");
456 addressOfOp.getResult(),
468 class LLVMDialectLLVMIRTranslationInterface
476 convertOperation(
Operation *op, llvm::IRBuilderBase &builder,
484 registry.
insert<LLVM::LLVMDialect>();
486 dialect->addInterfaces<LLVMDialectLLVMIRTranslationInterface>();
static SmallVector< unsigned > extractPosition(ArrayRef< int64_t > indices)
Convert the value of a DenseI64ArrayAttr to a vector of unsigned indices.
static std::string diagStr(const llvm::Type *type)
Convert an LLVM type to a string for printing in diagnostics.
static FailureOr< llvm::Function * > getOverloadedDeclaration(CallIntrinsicOp op, llvm::Intrinsic::ID id, llvm::Module *module, LLVM::ModuleTranslation &moduleTranslation)
Get the declaration of an overloaded llvm intrinsic.
static LogicalResult convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static SmallVector< llvm::OperandBundleDef > convertOperandBundles(OperandRangeRange bundleOperands, ArrayAttr bundleTags, LLVM::ModuleTranslation &moduleTranslation)
static LogicalResult convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Builder for LLVM_CallIntrinsicOp.
static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op)
static llvm::OperandBundleDef convertOperandBundle(OperandRange bundleOperands, StringRef bundleTag, LLVM::ModuleTranslation &moduleTranslation)
static void convertLinkerOptionsOp(ArrayAttr options, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static llvm::ManagedStatic< PassManagerOptions > options
static void contract(RootOrderingGraph &graph, ArrayRef< Value > cycle, const DenseMap< Value, unsigned > &parentDepths, DenseMap< Value, Value > &actualSource, DenseMap< Value, Value > &actualTarget)
Contracts the specified cycle in the given graph in-place.
Attributes are known-constant values of operations.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
A symbol reference with a reference path containing a single element.
Base class for dialect interfaces providing translation to LLVM IR.
LLVMTranslationDialectInterface(Dialect *dialect)
Implementation class for module translation.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
void mapCall(Operation *mlir, llvm::CallInst *llvm)
Stores a mapping between an MLIR call operation and a corresponding LLVM call instruction.
void mapBranch(Operation *mlir, llvm::Instruction *llvm)
Stores the mapping between an MLIR operation with successors and a corresponding LLVM IR instruction.
SmallVector< llvm::Value * > lookupValues(ValueRange values)
Looks up remapped a list of remapped values.
llvm::BasicBlock * lookupBlock(Block *block) const
Finds an LLVM IR basic block that corresponds to the given MLIR block.
SymbolTableCollection & symbolTable()
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
void setTBAAMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
Sets LLVM TBAA metadata for memory operations that have TBAA attributes.
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
llvm::GlobalValue * lookupGlobal(Operation *op)
Finds an LLVM IR global value that corresponds to the given MLIR operation defining a global value.
llvm::Module * getLLVMModule()
Returns the LLVM module in which the IR is being constructed.
llvm::Function * lookupFunction(StringRef name) const
Finds an LLVM IR function by its name.
void setAliasScopeMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst)
void setAccessGroupsMetadata(AccessGroupOpInterface op, llvm::Instruction *inst)
MLIRContext & getContext()
Returns the MLIR context of the module being translated.
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
void setLoopMetadata(Operation *op, llvm::Instruction *inst)
Sets LLVM loop metadata for branch operations that have a loop annotation attribute.
MLIRContext is the top-level object for a collection of MLIR operations.
void appendDialectRegistry(const DialectRegistry ®istry)
Append the contents of the given dialect registry to the registry associated with this context.
This class represents a contiguous range of operand ranges, e.g.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumResults()
Return the number of results held by this operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
llvm::Constant * getLLVMConstant(llvm::Type *llvmType, Attribute attr, Location loc, const ModuleTranslation &moduleTranslation)
Create an LLVM IR constant of llvmType from the MLIR attribute attr.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void registerLLVMDialectTranslation(DialectRegistry ®istry)
Register the LLVM dialect and the translation from it to the LLVM IR in the given registry;.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...