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 *>
77 allArgTys.push_back(moduleTranslation.
convertType(type));
81 resTy = llvm::Type::getVoidTy(module->getContext());
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::getDeclaration(module,
id, overloadedArgTysRef);
105 static llvm::OperandBundleDef
108 std::vector<llvm::Value *> operands;
109 operands.reserve(bundleOperands.size());
110 for (
Value bundleArg : bundleOperands)
111 operands.push_back(moduleTranslation.
lookupValue(bundleArg));
112 return llvm::OperandBundleDef(bundleTag.str(), std::move(operands));
120 bundles.reserve(bundleOperands.size());
122 for (
auto [operands, tag] : llvm::zip_equal(bundleOperands, bundleTags))
131 llvm::Module *module = builder.GetInsertBlock()->getModule();
133 llvm::Intrinsic::lookupIntrinsicID(op.getIntrinAttr());
136 << op.getIntrinAttr();
138 llvm::Function *fn =
nullptr;
139 if (llvm::Intrinsic::isOverloaded(
id)) {
142 if (failed(fnOrFailure))
146 fn = llvm::Intrinsic::getDeclaration(module,
id, {});
150 const llvm::Type *intrinType =
152 ? llvm::Type::getVoidTy(module->getContext())
154 if (intrinType != fn->getReturnType()) {
156 <<
diagStr(intrinType) <<
" but " << op.getIntrinAttr()
157 <<
" actually returns " <<
diagStr(fn->getReturnType());
162 if (!fn->getFunctionType()->isVarArg() &&
163 op.getArgs().size() != fn->arg_size()) {
165 << op.getArgs().size() <<
" operands but " << op.getIntrinAttr()
166 <<
" expects " << fn->arg_size();
168 if (fn->getFunctionType()->isVarArg() &&
169 op.getArgs().size() < fn->arg_size()) {
171 << op.getArgs().size() <<
" operands but variadic "
172 << op.getIntrinAttr() <<
" expects at least " << fn->arg_size();
175 for (
unsigned i = 0, e = fn->arg_size(); i != e; ++i) {
176 const llvm::Type *expected = fn->getArg(i)->getType();
177 const llvm::Type *actual =
179 if (actual != expected) {
181 << i <<
" has type " <<
diagStr(actual) <<
" but "
182 << op.getIntrinAttr() <<
" expects " <<
diagStr(expected);
186 FastmathFlagsInterface itf = op;
189 auto *inst = builder.CreateCall(
199 llvm::IRBuilderBase &builder,
201 llvm::Module *llvmModule = moduleTranslation.
getLLVMModule();
202 llvm::LLVMContext &context = llvmModule->getContext();
203 llvm::NamedMDNode *linkerMDNode =
204 llvmModule->getOrInsertNamedMetadata(
"llvm.linker.options");
206 MDNodes.reserve(
options.size());
207 for (
auto s :
options.getAsRange<StringAttr>()) {
209 MDNodes.push_back(MDNode);
213 linkerMDNode->addOperand(listMDNode);
220 llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
221 if (
auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
224 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
225 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
231 if (
auto callOp = dyn_cast<LLVM::CallOp>(opInst)) {
232 auto operands = moduleTranslation.
lookupValues(callOp.getCalleeOperands());
235 callOp.getOpBundleTags(), moduleTranslation);
237 llvm::CallInst *call;
238 if (
auto attr = callOp.getCalleeAttr()) {
240 builder.CreateCall(moduleTranslation.
lookupFunction(attr.getValue()),
241 operandsRef, opBundles);
243 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
244 moduleTranslation.
convertType(callOp.getCalleeFunctionType()));
245 call = builder.CreateCall(calleeType, operandsRef.front(),
246 operandsRef.drop_front(), opBundles);
248 call->setCallingConv(convertCConvToLLVM(callOp.getCConv()));
249 call->setTailCallKind(convertTailCallKindToLLVM(callOp.getTailCallKind()));
250 if (callOp.getConvergentAttr())
251 call->addFnAttr(llvm::Attribute::Convergent);
252 if (callOp.getNoUnwindAttr())
253 call->addFnAttr(llvm::Attribute::NoUnwind);
254 if (callOp.getWillReturnAttr())
255 call->addFnAttr(llvm::Attribute::WillReturn);
257 if (MemoryEffectsAttr memAttr = callOp.getMemoryEffectsAttr()) {
258 llvm::MemoryEffects memEffects =
259 llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
260 convertModRefInfoToLLVM(memAttr.getArgMem())) |
262 llvm::MemoryEffects::Location::InaccessibleMem,
263 convertModRefInfoToLLVM(memAttr.getInaccessibleMem())) |
264 llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
265 convertModRefInfoToLLVM(memAttr.getOther()));
266 call->setMemoryEffects(memEffects);
277 else if (!call->getType()->isVoidTy())
279 moduleTranslation.
mapCall(callOp, call);
283 if (
auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
287 llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
290 if (inlineAsmOp.getNumResults() == 0) {
293 assert(inlineAsmOp.getNumResults() == 1);
294 resultType = inlineAsmOp.getResultTypes()[0];
297 llvm::InlineAsm *inlineAsmInst =
298 inlineAsmOp.getAsmDialect()
300 static_cast<llvm::FunctionType *
>(
302 inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
303 inlineAsmOp.getHasSideEffects(),
304 inlineAsmOp.getIsAlignStack(),
305 convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
308 inlineAsmOp.getAsmString(),
309 inlineAsmOp.getConstraints(),
310 inlineAsmOp.getHasSideEffects(),
311 inlineAsmOp.getIsAlignStack());
312 llvm::CallInst *inst = builder.CreateCall(
314 moduleTranslation.
lookupValues(inlineAsmOp.getOperands()));
315 if (
auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
316 llvm::AttributeList attrList;
321 DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
323 cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
325 llvm::Type *ty = moduleTranslation.
convertType(tAttr.getValue());
326 b.addTypeAttr(llvm::Attribute::ElementType, ty);
330 attrList = attrList.addAttributesAtIndex(
333 inst->setAttributes(attrList);
341 if (
auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
342 auto operands = moduleTranslation.
lookupValues(invOp.getCalleeOperands());
345 invOp.getOpBundleTags(), moduleTranslation);
347 llvm::InvokeInst *result;
349 result = builder.CreateInvoke(
351 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
352 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)), operandsRef,
355 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
356 moduleTranslation.
convertType(invOp.getCalleeFunctionType()));
357 result = builder.CreateInvoke(
358 calleeType, operandsRef.front(),
359 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
360 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)),
361 operandsRef.drop_front(), opBundles);
363 result->setCallingConv(convertCConvToLLVM(invOp.getCConv()));
364 moduleTranslation.
mapBranch(invOp, result);
366 if (invOp->getNumResults() != 0) {
370 return success(result->getType()->isVoidTy());
373 if (
auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
374 llvm::Type *ty = moduleTranslation.
convertType(lpOp.getType());
375 llvm::LandingPadInst *lpi =
376 builder.CreateLandingPad(ty, lpOp.getNumOperands());
377 lpi->setCleanup(lpOp.getCleanup());
380 for (llvm::Value *operand :
383 if (
auto *constOperand = dyn_cast<llvm::Constant>(operand))
384 lpi->addClause(constOperand);
386 moduleTranslation.
mapValue(lpOp.getResult(), lpi);
392 if (
auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
393 llvm::BranchInst *branch =
394 builder.CreateBr(moduleTranslation.
lookupBlock(brOp.getSuccessor()));
395 moduleTranslation.
mapBranch(&opInst, branch);
399 if (
auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
400 llvm::BranchInst *branch = builder.CreateCondBr(
401 moduleTranslation.
lookupValue(condbrOp.getOperand(0)),
402 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(0)),
403 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(1)));
404 moduleTranslation.
mapBranch(&opInst, branch);
408 if (
auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
409 llvm::SwitchInst *switchInst = builder.CreateSwitch(
410 moduleTranslation.
lookupValue(switchOp.getValue()),
411 moduleTranslation.
lookupBlock(switchOp.getDefaultDestination()),
412 switchOp.getCaseDestinations().size());
415 if (!switchOp.getCaseValues())
418 auto *ty = llvm::cast<llvm::IntegerType>(
419 moduleTranslation.
convertType(switchOp.getValue().getType()));
421 llvm::zip(llvm::cast<DenseIntElementsAttr>(*switchOp.getCaseValues()),
422 switchOp.getCaseDestinations()))
427 moduleTranslation.
mapBranch(&opInst, switchInst);
434 if (
auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
435 LLVM::GlobalOp global =
436 addressOfOp.getGlobal(moduleTranslation.
symbolTable());
437 LLVM::LLVMFuncOp
function =
438 addressOfOp.getFunction(moduleTranslation.
symbolTable());
441 assert((global ||
function) &&
442 "referencing an undefined global or function");
445 addressOfOp.getResult(),
457 class LLVMDialectLLVMIRTranslationInterface
465 convertOperation(
Operation *op, llvm::IRBuilderBase &builder,
473 registry.
insert<LLVM::LLVMDialect>();
475 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 SmallVector< llvm::OperandBundleDef > convertOperandBundles(OperandRangeRange bundleOperands, ArrayRef< std::string > bundleTags, LLVM::ModuleTranslation &moduleTranslation)
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 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.
Location getLoc()
The source location the operation was defined or derived from.
operand_type_range getOperandTypes()
result_type_range getResultTypes()
result_range getResults()
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...
Type front()
Return first type in the range.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this 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...