[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