20 #include "llvm/IR/ConstantRange.h"
21 #include "llvm/IR/IRBuilder.h"
22 #include "llvm/IR/IntrinsicsAMDGPU.h"
23 #include "llvm/Support/raw_ostream.h"
36 llvm::Module *module = builder.GetInsertBlock()->getModule();
38 llvm::Type::getInt64Ty(module->getContext()),
39 llvm::Type::getInt32Ty(module->getContext()),
41 llvm::Function *fn = dyn_cast<llvm::Function>(
42 module->getOrInsertFunction(fnName, functionType).getCallee());
44 llvm::Type::getInt32Ty(module->getContext()), parameter);
46 if (
auto rangeAttr = op->
getAttrOfType<LLVM::ConstantRangeAttr>(
"range")) {
49 call->addRangeRetAttr(llvm::ConstantRange(rangeAttr.getLower().zext(64),
50 rangeAttr.getUpper().zext(64)));
58 class ROCDLDialectLLVMIRTranslationInterface
66 convertOperation(
Operation *op, llvm::IRBuilderBase &builder,
69 #include "mlir/Dialect/LLVMIR/ROCDLConversions.inc"
79 auto *dialect = dyn_cast<ROCDL::ROCDLDialect>(attribute.getNameDialect());
80 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
81 if (dialect->getKernelAttrHelper().getName() == attribute.getName()) {
82 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
84 return op->emitOpError(Twine(attribute.getName()) +
85 " is only supported on `llvm.func` operations");
92 llvm::Function *llvmFunc =
93 moduleTranslation.lookupFunction(func.getName());
94 llvmFunc->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
95 if (!llvmFunc->hasFnAttribute(
"amdgpu-flat-work-group-size")) {
96 llvmFunc->addFnAttr(
"amdgpu-flat-work-group-size",
"1,256");
103 if (!llvmFunc->hasFnAttribute(
"uniform-work-group-size"))
104 llvmFunc->addFnAttr(
"uniform-work-group-size",
"true");
109 if (dialect->getMaxFlatWorkGroupSizeAttrHelper().getName() ==
110 attribute.getName()) {
111 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
113 return op->emitOpError(Twine(attribute.getName()) +
114 " is only supported on `llvm.func` operations");
115 auto value = dyn_cast<IntegerAttr>(attribute.getValue());
117 return op->emitOpError(Twine(attribute.getName()) +
118 " must be an integer");
120 llvm::Function *llvmFunc =
121 moduleTranslation.lookupFunction(func.getName());
123 llvm::raw_svector_ostream attrValueStream(llvmAttrValue);
124 attrValueStream <<
"1," << value.getInt();
125 llvmFunc->addFnAttr(
"amdgpu-flat-work-group-size", llvmAttrValue);
127 if (dialect->getWavesPerEuAttrHelper().getName() == attribute.getName()) {
128 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
130 return op->emitOpError(Twine(attribute.getName()) +
131 " is only supported on `llvm.func` operations");
132 auto value = dyn_cast<IntegerAttr>(attribute.getValue());
134 return op->emitOpError(Twine(attribute.getName()) +
135 " must be an integer");
137 llvm::Function *llvmFunc =
138 moduleTranslation.lookupFunction(func.getName());
140 llvm::raw_svector_ostream attrValueStream(llvmAttrValue);
141 attrValueStream << value.getInt();
142 llvmFunc->addFnAttr(
"amdgpu-waves-per-eu", llvmAttrValue);
144 if (dialect->getFlatWorkGroupSizeAttrHelper().getName() ==
145 attribute.getName()) {
146 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
148 return op->emitOpError(Twine(attribute.getName()) +
149 " is only supported on `llvm.func` operations");
150 auto value = dyn_cast<StringAttr>(attribute.getValue());
152 return op->emitOpError(Twine(attribute.getName()) +
153 " must be a string");
155 llvm::Function *llvmFunc =
156 moduleTranslation.lookupFunction(func.getName());
158 llvmAttrValue.append(value.getValue());
159 llvmFunc->addFnAttr(
"amdgpu-flat-work-group-size", llvmAttrValue);
161 if (ROCDL::ROCDLDialect::getUniformWorkGroupSizeAttrName() ==
162 attribute.getName()) {
163 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
165 return op->emitOpError(Twine(attribute.getName()) +
166 " is only supported on `llvm.func` operations");
167 auto value = dyn_cast<BoolAttr>(attribute.getValue());
169 return op->emitOpError(Twine(attribute.getName()) +
170 " must be a boolean");
171 llvm::Function *llvmFunc =
172 moduleTranslation.lookupFunction(func.getName());
173 llvmFunc->addFnAttr(
"uniform-work-group-size",
174 value.getValue() ?
"true" :
"false");
176 if (dialect->getUnsafeFpAtomicsAttrHelper().getName() ==
177 attribute.getName()) {
178 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
180 return op->emitOpError(Twine(attribute.getName()) +
181 " is only supported on `llvm.func` operations");
182 auto value = dyn_cast<BoolAttr>(attribute.getValue());
184 return op->emitOpError(Twine(attribute.getName()) +
185 " must be a boolean");
186 llvm::Function *llvmFunc =
187 moduleTranslation.lookupFunction(func.getName());
188 llvmFunc->addFnAttr(
"amdgpu-unsafe-fp-atomics",
189 value.getValue() ?
"true" :
"false");
192 if (dialect->getReqdWorkGroupSizeAttrHelper().getName() ==
193 attribute.getName()) {
194 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
196 return op->emitOpError(Twine(attribute.getName()) +
197 " is only supported on `llvm.func` operations");
198 auto value = dyn_cast<DenseI32ArrayAttr>(attribute.getValue());
200 return op->emitOpError(Twine(attribute.getName()) +
201 " must be a dense i32 array attribute");
204 for (int32_t i : value.asArrayRef()) {
208 llvm::Function *llvmFunc =
209 moduleTranslation.lookupFunction(func.getName());
211 llvmFunc->setMetadata(
"reqd_work_group_size", node);
215 if (dialect->getLastUseAttrHelper().getName() == attribute.getName()) {
216 for (llvm::Instruction *i : instructions)
219 if (dialect->getNoRemoteMemoryAttrHelper().getName() ==
220 attribute.getName()) {
221 for (llvm::Instruction *i : instructions)
222 i->setMetadata(
"amdgpu.no.remote.memory",
225 if (dialect->getNoFineGrainedMemoryAttrHelper().getName() ==
226 attribute.getName()) {
227 for (llvm::Instruction *i : instructions)
228 i->setMetadata(
"amdgpu.no.fine.grained.memory",
231 if (dialect->getIgnoreDenormalModeAttrHelper().getName() ==
232 attribute.getName()) {
233 for (llvm::Instruction *i : instructions)
234 i->setMetadata(
"amdgpu.ignore.denormal.mode",
244 registry.
insert<ROCDL::ROCDLDialect>();
246 dialect->addInterfaces<ROCDLDialectLLVMIRTranslationInterface>();
static llvm::Value * createDimGetterFunctionCall(llvm::IRBuilderBase &builder, Operation *op, StringRef fnName, int parameter)
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.
Base class for dialect interfaces providing translation to LLVM IR.
LLVMTranslationDialectInterface(Dialect *dialect)
Implementation class for module translation.
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.
NamedAttribute represents a combination of a name and an Attribute value.
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
llvm::CallInst * createIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic, ArrayRef< llvm::Value * > args={}, ArrayRef< llvm::Type * > tys={})
Creates a call to an LLVM IR intrinsic function with the given arguments.
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void registerROCDLDialectTranslation(DialectRegistry ®istry)
Register the ROCDL dialect and the translation from it to the LLVM IR in the given registry;.