diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index 5f3f533792431..1bb0e3f9c5859 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -731,10 +731,9 @@ def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects, hlfir_Ele The shape and typeparams operands represent the extents and type parameters of the resulting array value. - Currently there is no way to control the iteration order of a hlfir - elemental operation and so operations in the body of the elemental must - not have side effects. If this is changed, an attribute must be added so - that the elemental inlining pass can skip these impure elementals. + The unordered attribute can be set to allow out of order processing + of the indices. This is safe only if the operations in the body + of the elemental do not have side effects. Example: Y + X, with Integer :: X(10, 20), Y(10,20) @@ -754,14 +753,15 @@ def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects, hlfir_Ele let arguments = (ins AnyShapeType:$shape, - Variadic:$typeparams + Variadic:$typeparams, + OptionalAttr:$unordered ); let results = (outs hlfir_ExprType); let regions = (region SizedRegion<1>:$region); let assemblyFormat = [{ - $shape (`typeparams` $typeparams^)? + $shape (`typeparams` $typeparams^)? (`unordered` $unordered^)? attr-dict `:` functional-type(operands, results) $region }]; @@ -775,13 +775,12 @@ def hlfir_ElementalOp : hlfir_Op<"elemental", [RecursiveMemoryEffects, hlfir_Ele } /// ElementalOpInterface implementation. - mlir::Region& getElementalRegion() {return getRegion();} + mlir::Region& getElementalRegion() { return getRegion(); } mlir::Value getElementEntity(); - mlir::Region* getElementCleanup() {return nullptr;} + mlir::Region* getElementCleanup() { return nullptr; } /// Must this elemental be evaluated in order? - /// TODO: add attribute and set it in lowering. - bool isOrdered() {return true;} + bool isOrdered() { return !getUnordered(); } }]; let skipDefaultBuilders = 1; @@ -1209,7 +1208,9 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R let arguments = (ins fir_ShapeType:$shape, - Variadic:$typeparams); + Variadic:$typeparams, + OptionalAttr:$unordered + ); let regions = (region SizedRegion<1>:$body, MaxSizedRegion<1>:$cleanup); @@ -1219,7 +1220,7 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R ]; let assemblyFormat = [{ - $shape (`typeparams` $typeparams^)? + $shape (`typeparams` $typeparams^)? (`unordered` $unordered^)? attr-dict `:` type(operands) $body custom($cleanup)}]; @@ -1235,13 +1236,12 @@ def hlfir_ElementalAddrOp : hlfir_Op<"elemental_addr", [Terminator, HasParent<"R /// ElementalOpInterface implementation. - mlir::Region& getElementalRegion() {return getBody();} + mlir::Region& getElementalRegion() { return getBody(); } mlir::Value getElementEntity(); mlir::Region* getElementCleanup(); /// Must this elemental be evaluated in order? - /// TODO: add attribute and set it in lowering. - bool isOrdered() {return true;} + bool isOrdered() { return !getUnordered(); } }]; let hasVerifier = 1; diff --git a/flang/test/HLFIR/element-addr.fir b/flang/test/HLFIR/element-addr.fir index c6f2b06b9f688..73946f8b40e3d 100644 --- a/flang/test/HLFIR/element-addr.fir +++ b/flang/test/HLFIR/element-addr.fir @@ -81,3 +81,36 @@ func.func @test_element_addr_cleanup(%x: !fir.box>>, // CHECK: fir.freemem %[[VAL_11]] : !fir.heap> // CHECK: } // CHECK: } + +func.func @unordered() { + %c10 = arith.constant 10 : index + %c20 = arith.constant 20 : index + %0 = fir.shape %c10, %c20 : (index, index) -> !fir.shape<2> + hlfir.region_assign { + %addr = fir.undefined !fir.ref> + hlfir.yield %addr : !fir.ref> + } to { + hlfir.elemental_addr %0 unordered : !fir.shape<2> { + ^bb0(%i: index, %j: index): + %addr = fir.undefined !fir.ref + hlfir.yield %addr : !fir.ref + } + } + return +} +// CHECK-LABEL: func.func @unordered() { +// CHECK: %[[VAL_0:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 20 : index +// CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]], %[[VAL_1]] : (index, index) -> !fir.shape<2> +// CHECK: hlfir.region_assign { +// CHECK: %[[VAL_3:.*]] = fir.undefined !fir.ref> +// CHECK: hlfir.yield %[[VAL_3]] : !fir.ref> +// CHECK: } to { +// CHECK: hlfir.elemental_addr %[[VAL_2]] unordered : !fir.shape<2> { +// CHECK: ^bb0(%[[VAL_4:.*]]: index, %[[VAL_5:.*]]: index): +// CHECK: %[[VAL_6:.*]] = fir.undefined !fir.ref +// CHECK: hlfir.yield %[[VAL_6]] : !fir.ref +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } diff --git a/flang/test/HLFIR/elemental.fir b/flang/test/HLFIR/elemental.fir index f87e45d0e9fce..d4cef6705b176 100644 --- a/flang/test/HLFIR/elemental.fir +++ b/flang/test/HLFIR/elemental.fir @@ -76,3 +76,26 @@ func.func @parametrized_derived_transpose(%x: !fir.box>, %n // CHECK: %[[VAL_9:.*]] = hlfir.as_expr %[[VAL_8]] : (!fir.box>) -> !hlfir.expr> // CHECK: hlfir.yield_element %[[VAL_9]] : !hlfir.expr> // CHECK: } + +func.func @unordered() { + %c10 = arith.constant 10 : index + %c20 = arith.constant 20 : index + %0 = fir.shape %c10, %c20 : (index, index) -> !fir.shape<2> + %3 = hlfir.elemental %0 unordered : (!fir.shape<2>) -> !hlfir.expr<10x20xi32> { + ^bb0(%i: index, %j: index): + %c0 = arith.constant 0 : i32 + hlfir.yield_element %c0 : i32 + } + return +} +// CHECK-LABEL: func.func @unordered() { +// CHECK: %[[VAL_0:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 20 : index +// CHECK: %[[VAL_2:.*]] = fir.shape %[[VAL_0]], %[[VAL_1]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_3:.*]] = hlfir.elemental %[[VAL_2]] unordered : (!fir.shape<2>) -> !hlfir.expr<10x20xi32> { +// CHECK: ^bb0(%[[VAL_4:.*]]: index, %[[VAL_5:.*]]: index): +// CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 +// CHECK: hlfir.yield_element %[[VAL_6]] : i32 +// CHECK: } +// CHECK: return +// CHECK: }