Skip to content

Commit 7e1f45c

Browse files
committed
Added the GPU related operation
1 parent 8be2741 commit 7e1f45c

File tree

3 files changed

+185
-5
lines changed

3 files changed

+185
-5
lines changed

mlir/cuda-tile/Toy/include/toy/Ops.td

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def ReshapeOp : Toy_Op<"reshape", [Pure]> {
311311
// ReturnOp
312312
//===----------------------------------------------------------------------===//
313313

314-
def ReturnOp : Toy_Op<"return", [Pure, HasParent<"FuncOp">,
314+
def ReturnOp : Toy_Op<"return", [Pure, HasParent<"FuncOp, GPUFuncOp">,
315315
Terminator]> {
316316
let summary = "return operation";
317317
let description = [{
@@ -405,4 +405,94 @@ def MatMulOp : Toy_Op<"matmul",
405405
let hasVerifier = 1;
406406
}
407407

408+
//===----------------------------------------------------------------------===//
409+
// lauch GPU Op
410+
//===----------------------------------------------------------------------===//
411+
412+
def LaunchGpuOp : Toy_Op<"launch_gpu",
413+
[DeclareOpInterfaceMethods<CallOpInterface>]> {
414+
let summary = "launch gpu kernel operation";
415+
let description = [{
416+
The "launch_gpu" operation launches a GPU kernel with given grid
417+
dimensions.
418+
419+
```mlir
420+
%4 = toy.launch_gpu @my_func(%1, %3) {grid = [16, 16, 1]}
421+
: (tensor<2x3xf32>, tensor<2x3xf32>)
422+
```
423+
424+
}];
425+
426+
let arguments = (ins
427+
FlatSymbolRefAttr:$callee,
428+
Variadic<F32Tensor>:$inputs,
429+
OptionalAttr<DictArrayAttr>:$arg_attrs,
430+
OptionalAttr<DictArrayAttr>:$res_attrs
431+
);
432+
433+
let results = (outs Variadic<F32Tensor>:$results);
434+
435+
let assemblyFormat = [{
436+
$callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results)
437+
}];
438+
439+
let builders = [
440+
OpBuilder<(ins "StringRef":$callee, "ArrayRef<Value>":$arguments)>
441+
];
442+
}
443+
444+
//===----------------------------------------------------------------------===//
445+
// GPUFuncOp
446+
//===----------------------------------------------------------------------===//
447+
448+
def GPUFuncOp : Toy_Op<"gpu_func", [
449+
FunctionOpInterface, IsolatedFromAbove
450+
]> {
451+
let summary = "GPU kernel function operation";
452+
let description = [{
453+
The "toy.gpu_func" operation represents a GPU kernel function. These are
454+
callable SSA-region operations that contain toy computations to be run on
455+
the GPU.
456+
457+
Example:
458+
459+
```mlir
460+
toy.gpu_func @my_kernel(tensor<*xf32> %arg0, tensor<*xf32> %arg1) {
461+
...
462+
toy.return
463+
}
464+
```
465+
}];
466+
467+
let arguments = (ins
468+
SymbolNameAttr:$sym_name,
469+
TypeAttrOf<FunctionType>:$function_type,
470+
OptionalAttr<DictArrayAttr>:$arg_attrs,
471+
OptionalAttr<DictArrayAttr>:$res_attrs
472+
);
473+
474+
let regions = (region AnyRegion:$body);
475+
476+
let builders = [OpBuilder<(ins
477+
"StringRef":$name, "FunctionType":$type,
478+
CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)
479+
>];
480+
let extraClassDeclaration = [{
481+
//===------------------------------------------------------------------===//
482+
// FunctionOpInterface Methods
483+
//===------------------------------------------------------------------===//
484+
485+
/// Returns the argument types of this function.
486+
ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }
487+
488+
/// Returns the result types of this function.
489+
ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
490+
491+
/// Returns the region on the function operation that is callable.
492+
Region *getCallableRegion() { return &getBody(); }
493+
}];
494+
let hasCustomAssemblyFormat = 1;
495+
let skipDefaultBuilders = 1;
496+
}
497+
408498
#endif // TOY_OPS

mlir/cuda-tile/Toy/mlir/Dialect.cpp

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,16 +373,20 @@ void MulOp::inferShapes() { getResult().setType(getLhs().getType()); }
373373
//===----------------------------------------------------------------------===//
374374

375375
llvm::LogicalResult ReturnOp::verify() {
376-
// We know that the parent operation is a function, because of the 'HasParent'
377-
// trait attached to the operation definition.
378-
auto function = cast<FuncOp>((*this)->getParentOp());
376+
// Parent can be FuncOp or GPUFuncOp; both implement FunctionOpInterface.
377+
auto *parent = (*this)->getParentOp();
378+
auto function = dyn_cast<FunctionOpInterface>(parent);
379+
if (!function)
380+
return emitOpError() << "must be enclosed in a function-like op";
381+
379382

380383
/// ReturnOps can only have a single optional operand.
381384
if (getNumOperands() > 1)
382385
return emitOpError() << "expects at most 1 return operand";
383386

384387
// The operand number and types must match the function signature.
385-
const auto &results = function.getFunctionType().getResults();
388+
auto funcType = llvm::cast<FunctionType>(function.getFunctionType());
389+
const auto &results = funcType.getResults();
386390
if (getNumOperands() != results.size())
387391
return emitOpError() << "does not return the same number of values ("
388392
<< getNumOperands() << ") as the enclosing function ("
@@ -489,6 +493,79 @@ llvm::LogicalResult MatMulOp::verify() {
489493
return mlir::success();
490494
}
491495

496+
//===----------------------------------------------------------------------===//
497+
// LaunchGpuOp
498+
//===----------------------------------------------------------------------===//
499+
500+
void LaunchGpuOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
501+
StringRef callee, ArrayRef<mlir::Value> arguments) {
502+
// Generic call always returns an unranked Tensor initially.
503+
state.addTypes(UnrankedTensorType::get(builder.getF32Type()));
504+
state.addOperands(arguments);
505+
state.addAttribute("callee",
506+
mlir::SymbolRefAttr::get(builder.getContext(), callee));
507+
state.addAttribute("grid", builder.getI64ArrayAttr({1, 1, 1}));
508+
}
509+
510+
/// Return the callee of the generic call operation, this is required by the
511+
/// call interface.
512+
CallInterfaceCallable LaunchGpuOp::getCallableForCallee() {
513+
return (*this)->getAttrOfType<SymbolRefAttr>("callee");
514+
}
515+
516+
/// Set the callee for the generic call operation, this is required by the call
517+
/// interface.
518+
void LaunchGpuOp::setCalleeFromCallable(CallInterfaceCallable callee) {
519+
(*this)->setAttr("callee", cast<SymbolRefAttr>(callee));
520+
}
521+
522+
/// Get the argument operands to the called function, this is required by the
523+
/// call interface.
524+
Operation::operand_range LaunchGpuOp::getArgOperands() { return getInputs(); }
525+
526+
/// Get the argument operands to the called function as a mutable range, this is
527+
/// required by the call interface.
528+
MutableOperandRange LaunchGpuOp::getArgOperandsMutable() {
529+
return getInputsMutable();
530+
}
531+
532+
533+
//===----------------------------------------------------------------------===//
534+
// GPUFuncOp
535+
//===----------------------------------------------------------------------===//
536+
537+
void GPUFuncOp::build(mlir::OpBuilder &builder, mlir::OperationState &state,
538+
llvm::StringRef name, mlir::FunctionType type,
539+
llvm::ArrayRef<mlir::NamedAttribute> attrs) {
540+
// FunctionOpInterface provides a convenient `build` method that will populate
541+
// the state of our GPUFuncOp, and create an entry block.
542+
buildWithEntryBlock(builder, state, name, type, attrs, type.getInputs());
543+
}
544+
545+
mlir::ParseResult GPUFuncOp::parse(mlir::OpAsmParser &parser,
546+
mlir::OperationState &result) {
547+
// Dispatch to the FunctionOpInterface provided utility method that parses the
548+
// function operation.
549+
auto buildFuncType =
550+
[](mlir::Builder &builder, llvm::ArrayRef<mlir::Type> argTypes,
551+
llvm::ArrayRef<mlir::Type> results,
552+
mlir::function_interface_impl::VariadicFlag,
553+
std::string &) { return builder.getFunctionType(argTypes, results); };
554+
555+
return mlir::function_interface_impl::parseFunctionOp(
556+
parser, result, /*allowVariadic=*/false,
557+
getFunctionTypeAttrName(result.name), buildFuncType,
558+
getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
559+
}
560+
561+
void GPUFuncOp::print(mlir::OpAsmPrinter &p) {
562+
// Dispatch to the FunctionOpInterface provided utility method that prints the
563+
// function operation.
564+
mlir::function_interface_impl::printFunctionOp(
565+
p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),
566+
getArgAttrsAttrName(), getResAttrsAttrName());
567+
}
568+
492569
//===----------------------------------------------------------------------===//
493570
// TableGen'd op method definitions
494571
//===----------------------------------------------------------------------===//

mlir/cuda-tile/sample/gpu.mlir

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
toy.gpu_func @my_kernel(%arg0: tensor<2x3xf32>, %arg1: tensor<3x2xf32>) -> tensor<2x2xf32> {
2+
%2 = toy.matmul(%arg0 : tensor<2x3xf32>, %arg1 : tensor<3x2xf32>) to tensor<2x2xf32>
3+
toy.return %2 : tensor<2x2xf32>
4+
}
5+
6+
toy.func @main() {
7+
%1 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf32>
8+
%3 = toy.constant dense<[[1.000000e+00, 2.000000e+00], [3.000000e+00, 4.000000e+00], [5.000000e+00, 6.000000e+00]]> : tensor<3x2xf32>
9+
%4 = toy.launch_gpu @my_kernel(%1, %3) {grid = [16, 16, 1]}
10+
: (tensor<2x3xf32>, tensor<3x2xf32>) -> tensor<2x2xf32>
11+
toy.print %4 : tensor<2x2xf32>
12+
toy.return
13+
}

0 commit comments

Comments
 (0)