Skip to content

Commit 56bf019

Browse files
authored
Don't require setting dimensions when lowering to garel (#22)
Callers must now provide 'dimension scans' as arguments to functions, rather than forcing dimensions to be hardcoded. Includes a new GraphAlg For op, merging both kinds of loops into a single op. Since we still require constant bounds on loops, but those constants might be passed in as argument, we add a new util (and pass) `setConstantArguments` to inline constants before lowering to the core set of ops.
1 parent 8505f84 commit 56bf019

41 files changed

Lines changed: 651 additions & 466 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/include/garel/GARelAttr.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def AggregateFunc : I64EnumAttr<
3838
I64EnumAttrCase<"MAX", 2>,
3939
I64EnumAttrCase<"LOR", 3>, /* Logical OR (over i1) */
4040
I64EnumAttrCase<"ARGMIN", 4>,
41+
I64EnumAttrCase<"COUNT", 5>,
4142
]
4243
> {
4344
let cppNamespace = "::garel";
@@ -49,7 +50,7 @@ def Aggregator : GARel_Attr<"Aggregator", "aggregator"> {
4950

5051
let parameters = (ins
5152
"AggregateFunc":$func,
52-
ArrayRefParameter<"ColumnIdx">:$inputs);
53+
OptionalArrayRefParameter<"ColumnIdx">:$inputs);
5354

5455
let assemblyFormat = [{
5556
`<` $func $inputs `>`

compiler/include/garel/GARelOps.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def ForOp : GARel_Op<"for", [InferTypeOpAdaptor]> {
143143

144144
let arguments = (ins
145145
Variadic<Relation>:$init,
146-
I64Attr:$iters,
146+
I64Relation:$iters,
147147
I64Attr:$resultIdx);
148148

149149
let regions = (region

compiler/include/garel/GARelTypes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <mlir/IR/MLIRContext.h>
34
#include <mlir/IR/Types.h>
45

56
#include "garel/GARelAttr.h"
@@ -11,4 +12,6 @@ namespace garel {
1112

1213
bool isColumnType(mlir::Type t);
1314

15+
RelationType getI64RelationType(mlir::MLIRContext *ctx);
16+
1417
} // namespace garel

compiler/include/garel/GARelTypes.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,10 @@ def Tuple : GARel_Type<"Tuple", "tuple"> {
3434

3535
def ColumnType : Type<CPred<"::garel::isColumnType($_self)">, "column type">;
3636

37+
def I64Relation : Type<
38+
CPred<"::garel::getI64RelationType($_self.getContext()) == $_self">,
39+
"relation with a single i64 column",
40+
"RelationType">,
41+
BuildableType<"::garel::getI64RelationType($_builder.getContext())">;
42+
3743
#endif // GAREL_TYPES

compiler/include/graphalg/GraphAlgOps.td

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -403,16 +403,22 @@ def BroadcastOp : Core_Op<"broadcast", [
403403
let hasVerifier = 1;
404404
}
405405

406-
// Not core according to spec, but we don't want to unroll in the general case.
407-
def ForConstOp : Core_Op<"for_const", [
406+
def ForOp : Core_Op<"for", [
408407
Pure,
409-
AllTypesMatch<["rangeBegin", "rangeEnd"]>,
408+
AttrSizedOperandSegments,
410409
DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getEntrySuccessorOperands"]>]> {
411-
let summary = "For loop with constant bounds";
410+
let summary = "For loop with dynamic bounds";
412411

413412
let description = [{
414-
A loop iterating over the integer range starting at `rangeBegin`
415-
(inclusive) and ending at `rangeEnd` (exclusive).
413+
A loop iterating over one of three ranges:
414+
1) `dynBegin` (inclusive) to `dynEnd` (exclusive)
415+
2) `begin` to `begin` + `iters`, where `iters` is an integer
416+
3) `begin` to `begin` + `iters`, where `iters` is a matrix dimension
417+
418+
Only instances with range types 2 or 3 are considered part of GraphAlg
419+
Core. Constant propagation is expected to transform range type 1 into
420+
either 2 or 3.
421+
416422
The `body` region is executed once for every value in the integer range
417423
(that value is passed as the first block argument).
418424
At the first iteration of the loop, the other block arguments take the
@@ -432,58 +438,39 @@ def ForConstOp : Core_Op<"for_const", [
432438

433439
let arguments = (ins
434440
Variadic<Matrix>:$initArgs,
435-
I64Scalar:$rangeBegin,
436-
I64Scalar:$rangeEnd);
441+
Optional<I64Scalar>:$dynBegin,
442+
Optional<I64Scalar>:$dynEnd,
443+
OptionalAttr<I64Attr>:$begin,
444+
OptionalAttr<DimAttr>:$iters);
437445

438446
let results = (outs Variadic<Matrix>:$results);
439447

440448
let regions = (region SizedRegion<1>:$body, MaxSizedRegion<1>:$until);
441449

442450
let assemblyFormat = [{
443-
`range` `(`
444-
$rangeBegin `,`
445-
$rangeEnd
446-
`)` `:` type($rangeEnd)
451+
(`dyn_begin` `` `=` `` $dynBegin^)?
452+
(`dyn_end` `` `=` `` $dynEnd^)?
453+
(`begin` `` `=` `` $begin^)?
454+
(`iters` `` `=` `` $iters^)?
447455
`init` `(` $initArgs `)` `:` type($initArgs) `->` type($results) attr-dict
448456
`body` $body
449457
`until` $until
450458
}];
451459

460+
let hasVerifier = 1;
452461
let hasRegionVerifier = 1;
453-
}
454-
455-
def ForDimOp : Core_Op<"for_dim", [
456-
Pure,
457-
DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getEntrySuccessorOperands"]>]> {
458-
let summary = "For loop over a matrix dimension";
459-
460-
let description = [{
461-
A loop iterating over the half-open range [0..`dim`).
462-
463-
This op is otherwise equivalent to `ForConstOp`.
464-
}];
465-
466-
let arguments = (ins Variadic<Matrix>:$initArgs, DimAttr:$dim);
467-
468-
let results = (outs Variadic<Matrix>:$results);
469-
470-
let regions = (region SizedRegion<1>:$body, MaxSizedRegion<1>:$until);
462+
let hasFolder = 1;
471463

472-
let assemblyFormat = [{
473-
`range` `(` custom<BareAttr>($dim) `)`
474-
`init` `(` $initArgs `)` `:` type($initArgs) `->` type($results) attr-dict
475-
`body` $body
476-
`until` $until
464+
let extraClassDeclaration = [{
465+
/** Whether at least one of `dyn_begin` and `dyn_end` is set. */
466+
bool isDynamicRange();
477467
}];
478-
479-
let hasRegionVerifier = 1;
480-
let hasCanonicalizer = 1;
481468
}
482469

483470
def YieldOp : Core_Op<"yield", [
484471
Pure,
485472
Terminator,
486-
ParentOneOf<["ForConstOp", "ForDimOp"]>,
473+
HasParent<"ForOp">,
487474
DeclareOpInterfaceMethods<RegionBranchTerminatorOpInterface>]> {
488475
let summary = "Yield from a loop body";
489476

compiler/include/graphalg/GraphAlgPasses.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33

44
include "mlir/Pass/PassBase.td"
55

6+
def GraphAlgSetConstArg : Pass<"graphalg-set-const-arg", "::mlir::ModuleOp"> {
7+
let summary = "Propagate a constant integer argument into a function";
8+
9+
let options = [
10+
Option<"functionName", "func", "std::string", /*default=*/"\"\"", "Name of the function to call">,
11+
Option<"argumentNumber", "argNum", "int", /*default=*/"-1", "The argument number that is constant">,
12+
Option<"value", "value", "std::int64_t", /*default=*/"0", "The value to propagate">,
13+
];
14+
}
15+
616
def GraphAlgPrepareInline : Pass<"graphalg-prepare-inline", "::mlir::ModuleOp"> {
717
let summary = "Prepares the IR for function inlining";
818

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#include <llvm/ADT/ArrayRef.h>
4+
#include <mlir/Dialect/Func/IR/FuncOps.h>
5+
#include <mlir/IR/BuiltinAttributeInterfaces.h>
6+
#include <mlir/Support/LLVM.h>
7+
8+
namespace graphalg {
9+
10+
/**
11+
* Inlines constant values for function parameters.
12+
*
13+
* The function parameters to set to constants must be scalar.
14+
*
15+
* Constant parameters are NOT removed from the function signature,
16+
* but the corresponding block arguments will have zero uses.
17+
*
18+
* @param op the function for which to inline argument values.
19+
* @param values for each parameter, the constant value to inline, or null if
20+
* the argument is not constant.
21+
*/
22+
mlir::LogicalResult
23+
setConstantArguments(mlir::func::FuncOp op,
24+
llvm::ArrayRef<mlir::TypedAttr> values);
25+
26+
} // namespace graphalg

compiler/src/garel/GARelAttr.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,32 @@ mlir::Type AggregatorAttr::getResultType(mlir::Type inputRel) {
2424
case AggregateFunc::ARGMIN:
2525
// NOTE: argmin(arg, val) also uses first input column as output type.
2626
return llvm::cast<RelationType>(inputRel).getColumns()[getInputs()[0]];
27+
case AggregateFunc::COUNT:
28+
return mlir::IntegerType::get(inputRel.getContext(), 64);
29+
}
30+
}
31+
32+
static std::size_t expectedNumInputs(AggregateFunc f) {
33+
switch (f) {
34+
case AggregateFunc::SUM:
35+
case AggregateFunc::MIN:
36+
case AggregateFunc::MAX:
37+
case AggregateFunc::LOR:
38+
return 1;
39+
case AggregateFunc::ARGMIN:
40+
return 2;
41+
case AggregateFunc::COUNT:
42+
return 0;
2743
}
2844
}
2945

3046
mlir::LogicalResult
3147
AggregatorAttr::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
3248
AggregateFunc func, llvm::ArrayRef<ColumnIdx> inputs) {
33-
if (func == AggregateFunc::ARGMIN) {
34-
if (inputs.size() != 2) {
35-
return emitError() << stringifyAggregateFunc(func)
36-
<< " expects exactly two inputs (arg, val), got "
37-
<< inputs.size();
38-
}
39-
} else {
40-
if (inputs.size() != 1) {
41-
return emitError() << stringifyAggregateFunc(func)
42-
<< " expects exactly one input, got " << inputs.size();
43-
}
49+
if (inputs.size() != expectedNumInputs(func)) {
50+
return emitError() << stringifyAggregateFunc(func) << " expects exactly "
51+
<< expectedNumInputs(func) << " inputs, got "
52+
<< inputs.size();
4453
}
4554

4655
return mlir::success();

compiler/src/garel/GARelTypes.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <llvm/ADT/ArrayRef.h>
22
#include <llvm/ADT/TypeSwitch.h>
33
#include <mlir/IR/Builders.h>
4+
#include <mlir/IR/BuiltinTypes.h>
45
#include <mlir/IR/DialectImplementation.h>
56
#include <mlir/IR/OpImplementation.h>
67

@@ -18,6 +19,11 @@ bool isColumnType(mlir::Type t) {
1819
t.isIndex();
1920
}
2021

22+
RelationType getI64RelationType(mlir::MLIRContext *ctx) {
23+
return RelationType::get(
24+
ctx, mlir::ArrayRef<mlir::Type>{mlir::IntegerType::get(ctx, 64)});
25+
}
26+
2127
// Need to define this here to avoid depending on IPRTypes in
2228
// IPRDialect and creating a cycle.
2329
void GARelDialect::registerTypes() {

0 commit comments

Comments
 (0)