Skip to content

Commit 1dc58b5

Browse files
committed
Move ops to fir
1 parent 1c7a3e9 commit 1dc58b5

File tree

7 files changed

+374
-376
lines changed

7 files changed

+374
-376
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3446,4 +3446,109 @@ def fir_BoxTotalElementsOp
34463446
let hasCanonicalizer = 1;
34473447
}
34483448

3449+
def fir_DoConcurrentOp : fir_Op<"do_concurrent",
3450+
[SingleBlock, AutomaticAllocationScope]> {
3451+
let summary = "do concurrent loop wrapper";
3452+
3453+
let description = [{
3454+
A wrapper operation for the actual op modeling `do concurrent` loops:
3455+
`fir.do_concurrent.loop` (see op declaration below for more info about it).
3456+
3457+
The `fir.do_concurrent` wrapper op consists of one single-block region with
3458+
the following properties:
3459+
- The first ops in the region are responsible for allocating storage for the
3460+
loop's iteration variables. This is property is **not** enforced by the op
3461+
verifier, but expected to be respected when building the op.
3462+
- The terminator of the region is an instance of `fir.do_concurrent.loop`.
3463+
3464+
For example, a 2D loop nest would be represented as follows:
3465+
```
3466+
fir.do_concurrent {
3467+
%i = fir.alloca i32
3468+
%j = fir.alloca i32
3469+
fir.do_concurrent.loop ...
3470+
}
3471+
```
3472+
}];
3473+
3474+
let regions = (region SizedRegion<1>:$region);
3475+
3476+
let assemblyFormat = "$region attr-dict";
3477+
let hasVerifier = 1;
3478+
}
3479+
3480+
def fir_DoConcurrentLoopOp : fir_Op<"do_concurrent.loop",
3481+
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopLikeOpInterface>,
3482+
Terminator, NoTerminator, SingleBlock, ParentOneOf<["DoConcurrentOp"]>]> {
3483+
let summary = "do concurrent loop";
3484+
3485+
let description = [{
3486+
An operation that models a Fortran `do concurrent` loop's header and block.
3487+
This is a single-region single-block terminator op that is expected to
3488+
terminate the region of a `omp.do_concurrent` wrapper op.
3489+
3490+
This op borrows from both `scf.parallel` and `fir.do_loop` ops. Similar to
3491+
`scf.parallel`, a loop nest takes 3 groups of SSA values as operands that
3492+
represent the lower bounds, upper bounds, and steps. Similar to `fir.do_loop`
3493+
the op takes one additional group of SSA values to represent reductions.
3494+
3495+
The body region **does not** have a terminator.
3496+
3497+
For example, a 2D loop nest with 2 reductions (sum and max) would be
3498+
represented as follows:
3499+
```
3500+
// The wrapper of the loop
3501+
fir.do_concurrent {
3502+
%i = fir.alloca i32
3503+
%j = fir.alloca i32
3504+
3505+
// The actual `do concurrent` loop
3506+
fir.do_concurrent.loop
3507+
(%i_iv, %j_iv) = (%i_lb, %j_lb) to (%i_ub, %j_ub) step (%i_st, %j_st)
3508+
reduce(#fir.reduce_attr<add> -> %sum : !fir.ref<i32>,
3509+
#fir.reduce_attr<max> -> %max : !fir.ref<f32>) {
3510+
3511+
%0 = fir.convert %i_iv : (index) -> i32
3512+
fir.store %0 to %i : !fir.ref<i32>
3513+
3514+
%1 = fir.convert %j_iv : (index) -> i32
3515+
fir.store %1 to %j : !fir.ref<i32>
3516+
3517+
// ... loop body goes here ...
3518+
}
3519+
}
3520+
```
3521+
3522+
Description of arguments:
3523+
- `lowerBound`: The group of SSA values for the nest's lower bounds.
3524+
- `upperBound`: The group of SSA values for the nest's upper bounds.
3525+
- `step`: The group of SSA values for the nest's steps.
3526+
- `reduceOperands`: The reduction SSA values, if any.
3527+
- `reduceAttrs`: Attributes to store reduction operations, if any.
3528+
- `loopAnnotation`: Loop metadata to be passed down the compiler pipeline to
3529+
LLVM.
3530+
}];
3531+
3532+
let arguments = (ins
3533+
Variadic<Index>:$lowerBound,
3534+
Variadic<Index>:$upperBound,
3535+
Variadic<Index>:$step,
3536+
Variadic<AnyType>:$reduceOperands,
3537+
OptionalAttr<ArrayAttr>:$reduceAttrs,
3538+
OptionalAttr<LoopAnnotationAttr>:$loopAnnotation
3539+
);
3540+
3541+
let regions = (region SizedRegion<1>:$region);
3542+
3543+
let hasCustomAssemblyFormat = 1;
3544+
let hasVerifier = 1;
3545+
3546+
let extraClassDeclaration = [{
3547+
// Get Number of reduction operands
3548+
unsigned getNumReduceOperands() {
3549+
return getReduceOperands().size();
3550+
}
3551+
}];
3552+
}
3553+
34493554
#endif

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ include "flang/Optimizer/Dialect/FIRAttr.td"
2121
include "flang/Optimizer/Dialect/FortranVariableInterface.td"
2222
include "mlir/Dialect/Arith/IR/ArithBase.td"
2323
include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
24-
include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
2524
include "mlir/IR/BuiltinAttributes.td"
2625

2726
// Base class for FIR operations.
@@ -1864,109 +1863,5 @@ def hlfir_EvaluateInMemoryOp : hlfir_Op<"eval_in_mem", [AttrSizedOperandSegments
18641863
let hasVerifier = 1;
18651864
}
18661865

1867-
def hlfir_DoConcurrentOp : hlfir_Op<"do_concurrent",
1868-
[SingleBlock, AutomaticAllocationScope]> {
1869-
let summary = "do concurrent loop wrapper";
1870-
1871-
let description = [{
1872-
A wrapper operation for the actual op modeling `do concurrent` loops:
1873-
`hlfir.do_concurrent.loop` (see op declaration below for more info about it).
1874-
1875-
The `hlfir.do_concurrent` wrapper op consists of one single-block region with
1876-
the following properties:
1877-
- The first ops in the region are responsible for allocating storage for the
1878-
loop's iteration variables. This is property is **not** enforced by the op
1879-
verifier, but expected to be respected when building the op.
1880-
- The terminator of the region is an instance of `hlfir.do_concurrent.loop`.
1881-
1882-
For example, a 2D loop nest would be represented as follows:
1883-
```
1884-
hlfir.do_concurrent {
1885-
%i = fir.alloca i32
1886-
%j = fir.alloca i32
1887-
hlfir.do_concurrent.loop ...
1888-
}
1889-
```
1890-
}];
1891-
1892-
let regions = (region SizedRegion<1>:$region);
1893-
1894-
let assemblyFormat = "$region attr-dict";
1895-
let hasVerifier = 1;
1896-
}
1897-
1898-
def hlfir_DoConcurrentLoopOp : hlfir_Op<"do_concurrent.loop",
1899-
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<LoopLikeOpInterface>,
1900-
Terminator, NoTerminator, SingleBlock, ParentOneOf<["DoConcurrentOp"]>]> {
1901-
let summary = "do concurrent loop";
1902-
1903-
let description = [{
1904-
An operation that models a Fortran `do concurrent` loop's header and block.
1905-
This is a single-region single-block terminator op that is expected to
1906-
terminate the region of a `omp.do_concurrent` wrapper op.
1907-
1908-
This op borrows from both `scf.parallel` and `fir.do_loop` ops. Similar to
1909-
`scf.parallel`, a loop nest takes 3 groups of SSA values as operands that
1910-
represent the lower bounds, upper bounds, and steps. Similar to `fir.do_loop`
1911-
the op takes one additional group of SSA values to represent reductions.
1912-
1913-
The body region **does not** have a terminator.
1914-
1915-
For example, a 2D loop nest with 2 reductions (sum and max) would be
1916-
represented as follows:
1917-
```
1918-
// The wrapper of the loop
1919-
hlfir.do_concurrent {
1920-
%i = fir.alloca i32
1921-
%j = fir.alloca i32
1922-
1923-
// The actual `do concurrent` loop
1924-
hlfir.do_concurrent.loop
1925-
(%i_iv, %j_iv) = (%i_lb, %j_lb) to (%i_ub, %j_ub) step (%i_st, %j_st)
1926-
reduce(#fir.reduce_attr<add> -> %sum : !fir.ref<i32>,
1927-
#fir.reduce_attr<max> -> %max : !fir.ref<f32>) {
1928-
1929-
%0 = fir.convert %i_iv : (index) -> i32
1930-
fir.store %0 to %i : !fir.ref<i32>
1931-
1932-
%1 = fir.convert %j_iv : (index) -> i32
1933-
fir.store %1 to %j : !fir.ref<i32>
1934-
1935-
// ... loop body goes here ...
1936-
}
1937-
}
1938-
```
1939-
1940-
Description of arguments:
1941-
- `lowerBound`: The group of SSA values for the nest's lower bounds.
1942-
- `upperBound`: The group of SSA values for the nest's upper bounds.
1943-
- `step`: The group of SSA values for the nest's steps.
1944-
- `reduceOperands`: The reduction SSA values, if any.
1945-
- `reduceAttrs`: Attributes to store reduction operations, if any.
1946-
- `loopAnnotation`: Loop metadata to be passed down the compiler pipeline to
1947-
LLVM.
1948-
}];
1949-
1950-
let arguments = (ins
1951-
Variadic<Index>:$lowerBound,
1952-
Variadic<Index>:$upperBound,
1953-
Variadic<Index>:$step,
1954-
Variadic<AnyType>:$reduceOperands,
1955-
OptionalAttr<ArrayAttr>:$reduceAttrs,
1956-
OptionalAttr<LoopAnnotationAttr>:$loopAnnotation
1957-
);
1958-
1959-
let regions = (region SizedRegion<1>:$region);
1960-
1961-
let hasCustomAssemblyFormat = 1;
1962-
let hasVerifier = 1;
1963-
1964-
let extraClassDeclaration = [{
1965-
// Get Number of reduction operands
1966-
unsigned getNumReduceOperands() {
1967-
return getReduceOperands().size();
1968-
}
1969-
}];
1970-
}
19711866

19721867
#endif // FORTRAN_DIALECT_HLFIR_OPS

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4748,6 +4748,167 @@ void fir::BoxTotalElementsOp::getCanonicalizationPatterns(
47484748
patterns.add<SimplifyBoxTotalElementsOp>(context);
47494749
}
47504750

4751+
//===----------------------------------------------------------------------===//
4752+
// DoConcurrentOp
4753+
//===----------------------------------------------------------------------===//
4754+
4755+
llvm::LogicalResult fir::DoConcurrentOp::verify() {
4756+
mlir::Block *body = getBody();
4757+
4758+
if (body->empty())
4759+
return emitOpError("body cannot be empty");
4760+
4761+
if (!body->mightHaveTerminator() ||
4762+
!mlir::isa<fir::DoConcurrentLoopOp>(body->getTerminator()))
4763+
return emitOpError("must be terminated by 'fir.do_concurrent.loop'");
4764+
4765+
return mlir::success();
4766+
}
4767+
4768+
//===----------------------------------------------------------------------===//
4769+
// DoConcurrentLoopOp
4770+
//===----------------------------------------------------------------------===//
4771+
4772+
mlir::ParseResult fir::DoConcurrentLoopOp::parse(mlir::OpAsmParser &parser,
4773+
mlir::OperationState &result) {
4774+
auto &builder = parser.getBuilder();
4775+
// Parse an opening `(` followed by induction variables followed by `)`
4776+
llvm::SmallVector<mlir::OpAsmParser::Argument, 4> ivs;
4777+
if (parser.parseArgumentList(ivs, mlir::OpAsmParser::Delimiter::Paren))
4778+
return mlir::failure();
4779+
4780+
// Parse loop bounds.
4781+
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> lower;
4782+
if (parser.parseEqual() ||
4783+
parser.parseOperandList(lower, ivs.size(),
4784+
mlir::OpAsmParser::Delimiter::Paren) ||
4785+
parser.resolveOperands(lower, builder.getIndexType(), result.operands))
4786+
return mlir::failure();
4787+
4788+
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> upper;
4789+
if (parser.parseKeyword("to") ||
4790+
parser.parseOperandList(upper, ivs.size(),
4791+
mlir::OpAsmParser::Delimiter::Paren) ||
4792+
parser.resolveOperands(upper, builder.getIndexType(), result.operands))
4793+
return mlir::failure();
4794+
4795+
// Parse step values.
4796+
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> steps;
4797+
if (parser.parseKeyword("step") ||
4798+
parser.parseOperandList(steps, ivs.size(),
4799+
mlir::OpAsmParser::Delimiter::Paren) ||
4800+
parser.resolveOperands(steps, builder.getIndexType(), result.operands))
4801+
return mlir::failure();
4802+
4803+
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> reduceOperands;
4804+
llvm::SmallVector<mlir::Type> reduceArgTypes;
4805+
if (succeeded(parser.parseOptionalKeyword("reduce"))) {
4806+
// Parse reduction attributes and variables.
4807+
llvm::SmallVector<fir::ReduceAttr> attributes;
4808+
if (failed(parser.parseCommaSeparatedList(
4809+
mlir::AsmParser::Delimiter::Paren, [&]() {
4810+
if (parser.parseAttribute(attributes.emplace_back()) ||
4811+
parser.parseArrow() ||
4812+
parser.parseOperand(reduceOperands.emplace_back()) ||
4813+
parser.parseColonType(reduceArgTypes.emplace_back()))
4814+
return mlir::failure();
4815+
return mlir::success();
4816+
})))
4817+
return mlir::failure();
4818+
// Resolve input operands.
4819+
for (auto operand_type : llvm::zip(reduceOperands, reduceArgTypes))
4820+
if (parser.resolveOperand(std::get<0>(operand_type),
4821+
std::get<1>(operand_type), result.operands))
4822+
return mlir::failure();
4823+
llvm::SmallVector<mlir::Attribute> arrayAttr(attributes.begin(),
4824+
attributes.end());
4825+
result.addAttribute(getReduceAttrsAttrName(result.name),
4826+
builder.getArrayAttr(arrayAttr));
4827+
}
4828+
4829+
// Now parse the body.
4830+
mlir::Region *body = result.addRegion();
4831+
for (auto &iv : ivs)
4832+
iv.type = builder.getIndexType();
4833+
if (parser.parseRegion(*body, ivs))
4834+
return mlir::failure();
4835+
4836+
// Set `operandSegmentSizes` attribute.
4837+
result.addAttribute(DoConcurrentLoopOp::getOperandSegmentSizeAttr(),
4838+
builder.getDenseI32ArrayAttr(
4839+
{static_cast<int32_t>(lower.size()),
4840+
static_cast<int32_t>(upper.size()),
4841+
static_cast<int32_t>(steps.size()),
4842+
static_cast<int32_t>(reduceOperands.size())}));
4843+
4844+
// Parse attributes.
4845+
if (parser.parseOptionalAttrDict(result.attributes))
4846+
return mlir::failure();
4847+
4848+
return mlir::success();
4849+
}
4850+
4851+
void fir::DoConcurrentLoopOp::print(mlir::OpAsmPrinter &p) {
4852+
p << " (" << getBody()->getArguments() << ") = (" << getLowerBound()
4853+
<< ") to (" << getUpperBound() << ") step (" << getStep() << ")";
4854+
4855+
if (!getReduceOperands().empty()) {
4856+
p << " reduce(";
4857+
auto attrs = getReduceAttrsAttr();
4858+
auto operands = getReduceOperands();
4859+
llvm::interleaveComma(llvm::zip(attrs, operands), p, [&](auto it) {
4860+
p << std::get<0>(it) << " -> " << std::get<1>(it) << " : "
4861+
<< std::get<1>(it).getType();
4862+
});
4863+
p << ')';
4864+
}
4865+
4866+
p << ' ';
4867+
p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);
4868+
p.printOptionalAttrDict(
4869+
(*this)->getAttrs(),
4870+
/*elidedAttrs=*/{DoConcurrentLoopOp::getOperandSegmentSizeAttr(),
4871+
DoConcurrentLoopOp::getReduceAttrsAttrName()});
4872+
}
4873+
4874+
llvm::SmallVector<mlir::Region *> fir::DoConcurrentLoopOp::getLoopRegions() {
4875+
return {&getRegion()};
4876+
}
4877+
4878+
llvm::LogicalResult fir::DoConcurrentLoopOp::verify() {
4879+
mlir::Operation::operand_range lbValues = getLowerBound();
4880+
mlir::Operation::operand_range ubValues = getUpperBound();
4881+
mlir::Operation::operand_range stepValues = getStep();
4882+
4883+
if (lbValues.empty())
4884+
return emitOpError(
4885+
"needs at least one tuple element for lowerBound, upperBound and step");
4886+
4887+
if (lbValues.size() != ubValues.size() ||
4888+
ubValues.size() != stepValues.size())
4889+
return emitOpError("different number of tuple elements for lowerBound, "
4890+
"upperBound or step");
4891+
4892+
// Check that the body defines the same number of block arguments as the
4893+
// number of tuple elements in step.
4894+
mlir::Block *body = getBody();
4895+
if (body->getNumArguments() != stepValues.size())
4896+
return emitOpError() << "expects the same number of induction variables: "
4897+
<< body->getNumArguments()
4898+
<< " as bound and step values: " << stepValues.size();
4899+
for (auto arg : body->getArguments())
4900+
if (!arg.getType().isIndex())
4901+
return emitOpError(
4902+
"expects arguments for the induction variable to be of index type");
4903+
4904+
auto reduceAttrs = getReduceAttrsAttr();
4905+
if (getNumReduceOperands() != (reduceAttrs ? reduceAttrs.size() : 0))
4906+
return emitOpError(
4907+
"mismatch in number of reduction variables and reduction attributes");
4908+
4909+
return mlir::success();
4910+
}
4911+
47514912
//===----------------------------------------------------------------------===//
47524913
// FIROpsDialect
47534914
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)