Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions include/hip/Dialect/Hipsr/IR/HipsrComputeOp.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
// Licensed under the MIT License.
//
// The hipsr.compute op: a DPS op whose region groups a multi-operation
// computation. Its terminator, hipsr.compute_yield, lives in
// HipsrComputeYieldOp.td.
//

//===----------------------------------------------------------------------===//
// Hipsr_ComputeOp
//===----------------------------------------------------------------------===//

def Hipsr_ComputeOp : Hipsr_Op<"compute", [
AttrSizedOperandSegments,
AutomaticAllocationScope,
DeclareOpInterfaceMethods<DestinationStyleOpInterface,
["getDpsInitsMutable"]>,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>,
IsolatedFromAbove,
RecursiveMemoryEffects,
SingleBlockImplicitTerminator<"ComputeYieldOp">
]> {
let summary = "Group a multi-operation computation as one DPS op";
let description = [{
Groups the operations that implement one high-level computation, so an ONNX
op that needs several tensor or shape operations still appears as a single
hipsr op. Without this grouping the intermediate values would sit in the
enclosing block, where the `hipsr.placeholder` of a later op would have to
take one as an input; a placeholder accepts only block arguments and
constant or placeholder results.

Destination-passing style: the `outs` inits are the destinations, and each
tensor init is tied to the matching result. The inits come from
`hipsr.placeholder`, which owns the output-shape computation; this op has no
shape region of its own.

`IsolatedFromAbove` keeps every value crossing the boundary explicit, so
stock MLIR passes stay correct over the body. `ctx`, the inputs, and the
inits therefore enter the body as entry-block arguments, in that order.
`RecursiveMemoryEffects` keeps nested effects visible to analyses, and the
body is an allocation scope so allocations made inside it end there.

Example:
```mlir
%out = hipsr.compute(%ctx) ins(%data : tensor<2x3xf16>)
outs(%init : tensor<6xf16>) {
^bb0(%body_ctx: !hipsr.context, %in: tensor<2x3xf16>, %dest: tensor<6xf16>):
%flat = tensor.collapse_shape %in [[0, 1]]
: tensor<2x3xf16> into tensor<6xf16>
%filled = tensor.insert_slice %flat into %dest[0] [6] [1]
: tensor<6xf16> into tensor<6xf16>
hipsr.compute_yield %filled : tensor<6xf16>
} : tensor<6xf16>
```
}];

let arguments = (ins
Hipsr_ContextType:$ctx,
Variadic<AnyType>:$inputs,
Variadic<Hipsr_TensorOrDeviceMemRef>:$inits
);
let results = (outs Variadic<AnyRankedTensor>:$result_tensors);
let regions = (region SizedRegion<1>:$body);

// Both operand lists are optional groups so an empty one prints as `ins()`.
// The result types trail the body after `:`, as in the other hipsr DPS ops.
let assemblyFormat = [{
`(` $ctx `)`
`ins` `(` ($inputs^ `:` type($inputs))? `)`
`outs` `(` ($inits^ `:` type($inits))? `)`
$body (`:` type($result_tensors)^)? attr-dict
}];
}
41 changes: 41 additions & 0 deletions include/hip/Dialect/Hipsr/IR/HipsrComputeYieldOp.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
// Licensed under the MIT License.
//
// The hipsr.compute_yield op: the terminator of a hipsr.compute region. The
// hipsr.compute op itself lives in HipsrComputeOp.td.
//

//===----------------------------------------------------------------------===//
// Hipsr_ComputeYieldOp
//===----------------------------------------------------------------------===//

def Hipsr_ComputeYieldOp : Hipsr_Op<"compute_yield",
[Pure, ReturnLike, Terminator, HasParent<"ComputeOp">]> {
let summary = "Yield the computed values out of a hipsr.compute region";
let description = [{
Returns the values a compute body produced to the parent op.

`ReturnLike` lets the parent's `RegionBranchOpInterface` verify these
outputs. Because the op only forwards values, `Pure` lets effect analyses
ignore it. `AnyType` keeps the same boundary before and after bufferization.

Example:
```mlir
hipsr.compute_yield %out, %count : tensor<2x?xi64>, tensor<i32>
```
}];

let arguments = (ins Variadic<AnyType>:$operands);

// Operands are optional, so the empty implicit terminator prints as just the
// mnemonic.
let assemblyFormat = "($operands^ `:` type($operands))? attr-dict";

let builders = [
// SingleBlockImplicitTerminator requires a no-argument builder.
OpBuilder<(ins), [{
build($_builder, $_state, ::mlir::ValueRange{});
}]>
];
}
2 changes: 2 additions & 0 deletions include/hip/Dialect/Hipsr/IR/HipsrOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ include "hip/Dialect/Hipsr/IR/HipsrPlaceholderOp.td"
include "hip/Dialect/Hipsr/IR/HipsrShapeYieldOp.td"
include "hip/Dialect/Hipsr/IR/HipsrPoolDomainOp.td"
include "hip/Dialect/Hipsr/IR/HipsrPoolDomainYieldOp.td"
include "hip/Dialect/Hipsr/IR/HipsrComputeOp.td"
include "hip/Dialect/Hipsr/IR/HipsrComputeYieldOp.td"
include "hip/Dialect/Hipsr/IR/HipsrEmptyOp.td"
include "hip/Dialect/Hipsr/IR/HipsrEmptyYieldOp.td"
include "hip/Dialect/Hipsr/IR/HipsrMatMulOp.td"
Expand Down
2 changes: 2 additions & 0 deletions lib/Dialect/Hipsr/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ add_library(HipsrDialectIR STATIC
HipsrOps.cpp
HipsrPoolDomainYieldOp.cpp
HipsrPoolDomainOp.cpp
HipsrComputeYieldOp.cpp
HipsrComputeOp.cpp
HipsrEmptyYieldOp.cpp
HipsrEmptyOp.cpp
HipsrConstantOp.cpp
Expand Down
40 changes: 40 additions & 0 deletions lib/Dialect/Hipsr/IR/HipsrComputeOp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
* Licensed under the MIT License.
*/

#include "hip/Dialect/Hipsr/IR/HipsrOps.h"

#include "llvm/Support/ErrorHandling.h"

using namespace mlir;
using namespace mlir::hipsr;

MutableOperandRange ComputeOp::getDpsInitsMutable() {
return getInitsMutable();
}

OperandRange ComputeOp::getEntrySuccessorOperands(RegionSuccessor successor) {
if (successor.getSuccessor() != &getBody()) {
llvm::report_fatal_error(
"hipsr.compute received an unexpected entry successor");
}
// The body is isolated from above, so every operand crosses the boundary as
// an entry-block argument: the context first, then the inputs and the inits.
return getOperands();
}

void ComputeOp::getSuccessorRegions(RegionBranchPoint point,
SmallVectorImpl<RegionSuccessor> &regions) {
if (point.isParent()) {
regions.emplace_back(&getBody(), getBody().getArguments());
return;
}

Operation *terminator = point.getTerminatorPredecessorOrNull();
if (!terminator || terminator->getParentRegion() != &getBody()) {
llvm::report_fatal_error(
"hipsr.compute received an unexpected branch point");
}
regions.emplace_back(getOperation(), getResults());
}
6 changes: 6 additions & 0 deletions lib/Dialect/Hipsr/IR/HipsrComputeYieldOp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
* Licensed under the MIT License.
*/

#include "hip/Dialect/Hipsr/IR/HipsrOps.h"
Loading
Loading