[flang-commits] [flang] 7f7ebff - [flang] add hlfir.transpose operation
Tom Eccles via flang-commits
flang-commits at lists.llvm.org
Tue Feb 28 07:22:29 PST 2023
Author: Tom Eccles
Date: 2023-02-28T15:21:25Z
New Revision: 7f7ebff35a0bd1a161530f056a653741938135bb
URL: https://github.com/llvm/llvm-project/commit/7f7ebff35a0bd1a161530f056a653741938135bb
DIFF: https://github.com/llvm/llvm-project/commit/7f7ebff35a0bd1a161530f056a653741938135bb.diff
LOG: [flang] add hlfir.transpose operation
Add a HLFIR operation for the TRANSPOSE transformational intrinsic,
according to the design set out in flang/doc/HighLevelFIR.md
Differential Revision: https://reviews.llvm.org/D144880
Added:
flang/test/HLFIR/transpose.fir
Modified:
flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
flang/include/flang/Optimizer/HLFIR/HLFIROps.td
flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/test/HLFIR/invalid.fir
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
index a0bcd33f57e06..9673804e09f1a 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
@@ -72,6 +72,7 @@ inline bool isBoxAddressOrValueType(mlir::Type type) {
bool isFortranScalarNumericalType(mlir::Type);
bool isFortranNumericalArrayObject(mlir::Type);
bool isFortranNumericalOrLogicalArrayObject(mlir::Type);
+bool isFortranArrayObject(mlir::Type);
bool isPassByRefOrIntegerType(mlir::Type);
bool isI1Type(mlir::Type);
// scalar i1 or logical, or sequence of logical (via (boxed?) array or expr)
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
index e210de3ce33eb..2c620af80bfeb 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td
@@ -118,6 +118,11 @@ def IsFortranNumericalOrLogicalArrayObjectPred
def AnyFortranNumericalOrLogicalArrayObject : Type<IsFortranNumericalOrLogicalArrayObjectPred,
"any array-like object containing a numerical or logical type">;
+def IsFortranArrayObjectPred
+ : CPred<"::hlfir::isFortranArrayObject($_self)">;
+def AnyFortranArrayObject : Type<IsFortranArrayObjectPred,
+ "any array-like object">;
+
def IsPassByRefOrIntegerTypePred
: CPred<"::hlfir::isPassByRefOrIntegerType($_self)">;
def AnyPassByRefOrIntegerType : Type<IsPassByRefOrIntegerTypePred,
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index be07718b9c104..b797cd2cd17e1 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -385,6 +385,23 @@ def hlfir_MatmulOp : hlfir_Op<"matmul",
let hasVerifier = 1;
}
+def hlfir_TransposeOp : hlfir_Op<"transpose", []> {
+ let summary = "TRANSPOSE transformational intrinsic";
+ let description = [{
+ Transpose a rank 2 array
+ }];
+
+ let arguments = (ins AnyFortranArrayObject:$array);
+
+ let results = (outs hlfir_ExprType);
+
+ let assemblyFormat = [{
+ $array attr-dict `:` functional-type(operands, results)
+ }];
+
+ let hasVerifier = 1;
+}
+
def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
let summary = "Create a variable from an expression value";
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
index 3dd757f993848..2cadd6880cb1f 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
@@ -127,6 +127,12 @@ bool hlfir::isFortranNumericalOrLogicalArrayObject(mlir::Type type) {
return false;
}
+bool hlfir::isFortranArrayObject(mlir::Type type) {
+ if (isBoxAddressType(type))
+ return false;
+ return !!getFortranElementOrSequenceType(type).dyn_cast<fir::SequenceType>();
+}
+
bool hlfir::isPassByRefOrIntegerType(mlir::Type type) {
mlir::Type unwrappedType = fir::unwrapPassByRefType(type);
return fir::isa_integer(unwrappedType);
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index bff5b3ba648e2..53259fe495baa 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -636,6 +636,36 @@ mlir::LogicalResult hlfir::MatmulOp::verify() {
return mlir::success();
}
+//===----------------------------------------------------------------------===//
+// TransposeOp
+//===----------------------------------------------------------------------===//
+
+mlir::LogicalResult hlfir::TransposeOp::verify() {
+ mlir::Value array = getArray();
+ fir::SequenceType arrayTy =
+ hlfir::getFortranElementOrSequenceType(array.getType())
+ .cast<fir::SequenceType>();
+ llvm::ArrayRef<int64_t> inShape = arrayTy.getShape();
+ std::size_t rank = inShape.size();
+ mlir::Type eleTy = arrayTy.getEleTy();
+ hlfir::ExprType resultTy = getResult().getType().cast<hlfir::ExprType>();
+ llvm::ArrayRef<int64_t> resultShape = resultTy.getShape();
+ std::size_t resultRank = resultShape.size();
+ mlir::Type resultEleTy = resultTy.getEleTy();
+
+ if (rank != 2 || resultRank != 2)
+ return emitOpError("input and output arrays should have rank 2");
+
+ if (inShape[0] != resultShape[1] || inShape[1] != resultShape[0])
+ return emitOpError("output shape does not match input array");
+
+ if (eleTy != resultEleTy)
+ return emitOpError(
+ "input and output arrays should have the same element type");
+
+ return mlir::success();
+}
+
//===----------------------------------------------------------------------===//
// AssociateOp
//===----------------------------------------------------------------------===//
diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir
index 0ff4bb59c8b2d..2ec7c689b5ea1 100644
--- a/flang/test/HLFIR/invalid.fir
+++ b/flang/test/HLFIR/invalid.fir
@@ -376,6 +376,27 @@ func.func @bad_matmul8(%arg0: !hlfir.expr<2xi32>, %arg1: !hlfir.expr<2x3xi32>) {
return
}
+// -----
+func.func @bad_transpose1(%arg0: !hlfir.expr<2xi32>) {
+ // expected-error at +1 {{'hlfir.transpose' op input and output arrays should have rank 2}}
+ %0 = hlfir.transpose %arg0 : (!hlfir.expr<2xi32>) -> !hlfir.expr<2xi32>
+ return
+}
+
+// -----
+func.func @bad_transpose2(%arg0: !hlfir.expr<2x3xi32>) {
+ // expected-error at +1 {{'hlfir.transpose' op output shape does not match input array}}
+ %0 = hlfir.transpose %arg0 : (!hlfir.expr<2x3xi32>) -> !hlfir.expr<2x2xi32>
+ return
+}
+
+// -----
+func.func @bad_transpose3(%arg0: !hlfir.expr<2x3xi32>) {
+ // expected-error at +1 {{'hlfir.transpose' op input and output arrays should have the same element type}}
+ %0 = hlfir.transpose %arg0 : (!hlfir.expr<2x3xi32>) -> !hlfir.expr<3x2xf64>
+ return
+}
+
// -----
func.func @bad_assign_1(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.box<!fir.array<?xi32>>) {
// expected-error at +1 {{'hlfir.assign' op lhs must be an allocatable when `realloc` is set}}
diff --git a/flang/test/HLFIR/transpose.fir b/flang/test/HLFIR/transpose.fir
new file mode 100644
index 0000000000000..14f9383d5775a
--- /dev/null
+++ b/flang/test/HLFIR/transpose.fir
@@ -0,0 +1,69 @@
+// Test hlfir.transpose operation parse, verify (no errors), and unparse
+
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+
+// square matrix of known shape
+func.func @transpose0(%arg0: !hlfir.expr<2x2xi32>) {
+ %res = hlfir.transpose %arg0 : (!hlfir.expr<2x2xi32>) -> !hlfir.expr<2x2xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose0
+// CHECK: %[[ARG0:.*]]: !hlfir.expr<2x2xi32>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!hlfir.expr<2x2xi32>) -> !hlfir.expr<2x2xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
+
+// rectangular matrix of known shape
+func.func @transpose1(%arg0: !hlfir.expr<2x3xi32>) {
+ %res = hlfir.transpose %arg0 : (!hlfir.expr<2x3xi32>) -> !hlfir.expr<3x2xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose1
+// CHECK: %[[ARG0:.*]]: !hlfir.expr<2x3xi32>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!hlfir.expr<2x3xi32>) -> !hlfir.expr<3x2xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
+
+// matrix of assumed shape
+func.func @transpose2(%arg0: !hlfir.expr<?x?xi32>) {
+ %res = hlfir.transpose %arg0 : (!hlfir.expr<?x?xi32>) -> !hlfir.expr<?x?xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose2
+// CHECK: %[[ARG0:.*]]: !hlfir.expr<?x?xi32>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!hlfir.expr<?x?xi32>) -> !hlfir.expr<?x?xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
+
+// matrix where only some dimensions are known #1
+func.func @transpose3(%arg0: !hlfir.expr<?x2xi32>) {
+ %res = hlfir.transpose %arg0 : (!hlfir.expr<?x2xi32>) -> !hlfir.expr<2x?xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose3
+// CHECK: %[[ARG0:.*]]: !hlfir.expr<?x2xi32>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!hlfir.expr<?x2xi32>) -> !hlfir.expr<2x?xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
+
+// matrix where only some dimensions are known #2
+func.func @transpose4(%arg0: !hlfir.expr<2x?xi32>) {
+ %res = hlfir.transpose %arg0 : (!hlfir.expr<2x?xi32>) -> !hlfir.expr<?x2xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose4
+// CHECK: %[[ARG0:.*]]: !hlfir.expr<2x?xi32>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!hlfir.expr<2x?xi32>) -> !hlfir.expr<?x2xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
+
+// matrix is a boxed array
+func.func @transpose5(%arg0: !fir.box<!fir.array<1x2xi32>>) {
+ %res = hlfir.transpose %arg0 : (!fir.box<!fir.array<1x2xi32>>) -> !hlfir.expr<2x1xi32>
+ return
+}
+// CHECK-LABEL: func.func @transpose5
+// CHECK: %[[ARG0:.*]]: !fir.box<!fir.array<1x2xi32>>
+// CHECK-NEXT: %[[RES:.*]] = hlfir.transpose %[[ARG0]] : (!fir.box<!fir.array<1x2xi32>>) -> !hlfir.expr<2x1xi32>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
More information about the flang-commits
mailing list