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);
109 llvm::Module *module = builder.GetInsertBlock()->getModule();
111 llvm::Function::lookupIntrinsicID(op.getIntrinAttr());
114 << op.getIntrinAttr();
116 llvm::Function *fn =
nullptr;
117 if (llvm::Intrinsic::isOverloaded(
id)) {
120 if (failed(fnOrFailure))
124 fn = llvm::Intrinsic::getDeclaration(module,
id, {});
128 const llvm::Type *intrinType =
130 ? llvm::Type::getVoidTy(module->getContext())
132 if (intrinType != fn->getReturnType()) {
134 <<
diagStr(intrinType) <<
" but " << op.getIntrinAttr()
135 <<
" actually returns " <<
diagStr(fn->getReturnType());
140 if (!fn->getFunctionType()->isVarArg() &&
144 <<
" expects " << fn->arg_size();
146 if (fn->getFunctionType()->isVarArg() &&
150 << op.getIntrinAttr() <<
" expects at least " << fn->arg_size();
153 for (
unsigned i = 0, e = fn->arg_size(); i != e; ++i) {
154 const llvm::Type *expected = fn->getArg(i)->getType();
155 const llvm::Type *actual =
157 if (actual != expected) {
159 << i <<
" has type " <<
diagStr(actual) <<
" but "
160 << op.getIntrinAttr() <<
" expects " <<
diagStr(expected);
164 FastmathFlagsInterface itf = op;
175 llvm::IRBuilderBase &builder,
177 llvm::Module *llvmModule = moduleTranslation.
getLLVMModule();
178 llvm::LLVMContext &context = llvmModule->getContext();
179 llvm::NamedMDNode *linkerMDNode =
180 llvmModule->getOrInsertNamedMetadata(
"llvm.linker.options");
182 MDNodes.reserve(
options.size());
183 for (
auto s :
options.getAsRange<StringAttr>()) {
185 MDNodes.push_back(MDNode);
189 linkerMDNode->addOperand(listMDNode);
196 llvm::IRBuilder<>::FastMathFlagGuard fmfGuard(builder);
197 if (
auto fmf = dyn_cast<FastmathFlagsInterface>(opInst))
200 #include "mlir/Dialect/LLVMIR/LLVMConversions.inc"
201 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicConversions.inc"
207 if (
auto callOp = dyn_cast<LLVM::CallOp>(opInst)) {
208 auto operands = moduleTranslation.
lookupValues(callOp.getOperands());
210 llvm::CallInst *call;
211 if (
auto attr = callOp.getCalleeAttr()) {
212 call = builder.CreateCall(
215 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
216 moduleTranslation.
convertType(callOp.getCalleeFunctionType()));
217 call = builder.CreateCall(calleeType, operandsRef.front(),
218 operandsRef.drop_front());
220 call->setCallingConv(convertCConvToLLVM(callOp.getCConv()));
221 call->setTailCallKind(convertTailCallKindToLLVM(callOp.getTailCallKind()));
222 if (callOp.getConvergentAttr())
223 call->addFnAttr(llvm::Attribute::Convergent);
224 if (callOp.getNoUnwindAttr())
225 call->addFnAttr(llvm::Attribute::NoUnwind);
226 if (callOp.getWillReturnAttr())
227 call->addFnAttr(llvm::Attribute::WillReturn);
229 if (MemoryEffectsAttr memAttr = callOp.getMemoryEffectsAttr()) {
230 llvm::MemoryEffects memEffects =
231 llvm::MemoryEffects(llvm::MemoryEffects::Location::ArgMem,
232 convertModRefInfoToLLVM(memAttr.getArgMem())) |
234 llvm::MemoryEffects::Location::InaccessibleMem,
235 convertModRefInfoToLLVM(memAttr.getInaccessibleMem())) |
236 llvm::MemoryEffects(llvm::MemoryEffects::Location::Other,
237 convertModRefInfoToLLVM(memAttr.getOther()));
238 call->setMemoryEffects(memEffects);
249 else if (!call->getType()->isVoidTy())
251 moduleTranslation.
mapCall(callOp, call);
255 if (
auto inlineAsmOp = dyn_cast<LLVM::InlineAsmOp>(opInst)) {
259 llvm::append_range(operandTypes, inlineAsmOp.getOperands().getTypes());
262 if (inlineAsmOp.getNumResults() == 0) {
265 assert(inlineAsmOp.getNumResults() == 1);
266 resultType = inlineAsmOp.getResultTypes()[0];
269 llvm::InlineAsm *inlineAsmInst =
270 inlineAsmOp.getAsmDialect()
272 static_cast<llvm::FunctionType *
>(
274 inlineAsmOp.getAsmString(), inlineAsmOp.getConstraints(),
275 inlineAsmOp.getHasSideEffects(),
276 inlineAsmOp.getIsAlignStack(),
277 convertAsmDialectToLLVM(*inlineAsmOp.getAsmDialect()))
280 inlineAsmOp.getAsmString(),
281 inlineAsmOp.getConstraints(),
282 inlineAsmOp.getHasSideEffects(),
283 inlineAsmOp.getIsAlignStack());
284 llvm::CallInst *inst = builder.CreateCall(
286 moduleTranslation.
lookupValues(inlineAsmOp.getOperands()));
287 if (
auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
288 llvm::AttributeList attrList;
293 DictionaryAttr dAttr = cast<DictionaryAttr>(attr);
295 cast<TypeAttr>(dAttr.get(InlineAsmOp::getElementTypeAttrName()));
297 llvm::Type *ty = moduleTranslation.
convertType(tAttr.getValue());
298 b.addTypeAttr(llvm::Attribute::ElementType, ty);
302 attrList = attrList.addAttributesAtIndex(
305 inst->setAttributes(attrList);
313 if (
auto invOp = dyn_cast<LLVM::InvokeOp>(opInst)) {
314 auto operands = moduleTranslation.
lookupValues(invOp.getCalleeOperands());
316 llvm::InvokeInst *result;
318 result = builder.CreateInvoke(
320 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
321 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)), operandsRef);
323 llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
324 moduleTranslation.
convertType(invOp.getCalleeFunctionType()));
325 result = builder.CreateInvoke(
326 calleeType, operandsRef.front(),
327 moduleTranslation.
lookupBlock(invOp.getSuccessor(0)),
328 moduleTranslation.
lookupBlock(invOp.getSuccessor(1)),
329 operandsRef.drop_front());
331 result->setCallingConv(convertCConvToLLVM(invOp.getCConv()));
332 moduleTranslation.
mapBranch(invOp, result);
334 if (invOp->getNumResults() != 0) {
338 return success(result->getType()->isVoidTy());
341 if (
auto lpOp = dyn_cast<LLVM::LandingpadOp>(opInst)) {
342 llvm::Type *ty = moduleTranslation.
convertType(lpOp.getType());
343 llvm::LandingPadInst *lpi =
344 builder.CreateLandingPad(ty, lpOp.getNumOperands());
345 lpi->setCleanup(lpOp.getCleanup());
348 for (llvm::Value *operand :
351 if (
auto *constOperand = dyn_cast<llvm::Constant>(operand))
352 lpi->addClause(constOperand);
354 moduleTranslation.
mapValue(lpOp.getResult(), lpi);
360 if (
auto brOp = dyn_cast<LLVM::BrOp>(opInst)) {
361 llvm::BranchInst *branch =
362 builder.CreateBr(moduleTranslation.
lookupBlock(brOp.getSuccessor()));
363 moduleTranslation.
mapBranch(&opInst, branch);
367 if (
auto condbrOp = dyn_cast<LLVM::CondBrOp>(opInst)) {
368 llvm::BranchInst *branch = builder.CreateCondBr(
369 moduleTranslation.
lookupValue(condbrOp.getOperand(0)),
370 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(0)),
371 moduleTranslation.
lookupBlock(condbrOp.getSuccessor(1)));
372 moduleTranslation.
mapBranch(&opInst, branch);
376 if (
auto switchOp = dyn_cast<LLVM::SwitchOp>(opInst)) {
377 llvm::SwitchInst *switchInst = builder.CreateSwitch(
378 moduleTranslation.
lookupValue(switchOp.getValue()),
379 moduleTranslation.
lookupBlock(switchOp.getDefaultDestination()),
380 switchOp.getCaseDestinations().size());
383 if (!switchOp.getCaseValues())
386 auto *ty = llvm::cast<llvm::IntegerType>(
387 moduleTranslation.
convertType(switchOp.getValue().getType()));
389 llvm::zip(llvm::cast<DenseIntElementsAttr>(*switchOp.getCaseValues()),
390 switchOp.getCaseDestinations()))
395 moduleTranslation.
mapBranch(&opInst, switchInst);
402 if (
auto addressOfOp = dyn_cast<LLVM::AddressOfOp>(opInst)) {
403 LLVM::GlobalOp global =
404 addressOfOp.getGlobal(moduleTranslation.
symbolTable());
405 LLVM::LLVMFuncOp
function =
406 addressOfOp.getFunction(moduleTranslation.
symbolTable());
409 assert((global ||
function) &&
410 "referencing an undefined global or function");
413 addressOfOp.getResult(),
425 class LLVMDialectLLVMIRTranslationInterface
433 convertOperation(
Operation *op, llvm::IRBuilderBase &builder,
441 registry.
insert<LLVM::LLVMDialect>();
443 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 LogicalResult convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
Builder for LLVM_CallIntrinsicOp.
static llvm::FastMathFlags getFastmathFlags(FastmathFlagsInterface &op)
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.
void addExtension(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.
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.
unsigned getNumOperands()
operand_type_range getOperandTypes()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
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.
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...