diff --git a/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt b/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt --- a/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt +++ b/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt @@ -1,6 +1,6 @@ set(LLVM_TARGET_DEFINITIONS HLFIROpBase.td) -mlir_tablegen(HLFIRTypes.h.inc -gen-typedef-decls) -mlir_tablegen(HLFIRTypes.cpp.inc -gen-typedef-defs) +mlir_tablegen(HLFIRTypes.h.inc -gen-typedef-decls -typedefs-dialect=hlfir) +mlir_tablegen(HLFIRTypes.cpp.inc -gen-typedef-defs -typedefs-dialect=hlfir) mlir_tablegen(HLFIRDialect.h.inc -gen-dialect-decls -dialect=hlfir) mlir_tablegen(HLFIRDialect.cpp.inc -gen-dialect-defs -dialect=hlfir) mlir_tablegen(HLFIRAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=hlfir) diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td --- a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td @@ -16,6 +16,7 @@ include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" +include "flang/Optimizer/Dialect/FIRTypes.td" def hlfir_Dialect : Dialect { let name = "hlfir"; @@ -72,7 +73,17 @@ def IsFortranVariablePred : CPred<"::hlfir::isFortranVariableType($_self)">; +def AnyFortranVariable : Type; + + +def AnyFortranValue : TypeConstraint, "any Fortran value type">; + + +def AnyFortranEntity : TypeConstraint, "any Fortran value or variable type">; -def AnyFortranVariableLike : Type; #endif // FORTRAN_DIALECT_HLFIR_OP_BASE diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -83,7 +83,7 @@ OptionalAttr:$fortran_attrs ); - let results = (outs AnyFortranVariableLike, AnyRefOrBoxLike); + let results = (outs AnyFortranVariable, AnyRefOrBoxLike); let assemblyFormat = [{ $memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)? @@ -116,4 +116,21 @@ let hasVerifier = 1; } +def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> { + let summary = "Assign an expression or variable value to a Fortran variable"; + + let description = [{ + Assign rhs to lhs following Fortran intrinsic assignments rules. + The operation deals with inserting a temporary if the lhs and rhs + may overlap. + }]; + + let arguments = (ins AnyFortranEntity:$rhs, + Arg:$lhs); + + let assemblyFormat = [{ + $rhs `to` $lhs attr-dict `:` type(operands) + }]; +} + #endif // FORTRAN_DIALECT_HLFIR_OPS diff --git a/flang/test/HLFIR/assign.fir b/flang/test/HLFIR/assign.fir new file mode 100644 --- /dev/null +++ b/flang/test/HLFIR/assign.fir @@ -0,0 +1,130 @@ +// Test hlfir.assign operation parse, verify (no errors), and unparse. + +// RUN: fir-opt %s | fir-opt | FileCheck %s + +func.func @scalar_logical(%arg0: !fir.ref>, %arg1: !fir.ref>) { + hlfir.assign %arg1 to %arg0 : !fir.ref>, !fir.ref> + return +} +// CHECK-LABEL: func.func @scalar_logical( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.ref>, !fir.ref> + +func.func @scalar_logical_2(%arg0: !fir.ref>, %arg1: i1) { + hlfir.assign %arg1 to %arg0 : i1, !fir.ref> + return +} +// CHECK-LABEL: func.func @scalar_logical_2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: i1) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : i1, !fir.ref> + +func.func @scalar_integer(%arg0: !fir.ref, %arg1: !fir.ref) { + hlfir.assign %arg1 to %arg0 : !fir.ref, !fir.ref + return +} +// CHECK-LABEL: func.func @scalar_integer( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.ref, !fir.ref + +func.func @scalar_integer_2(%arg0: !fir.ref, %arg1: i32) { + hlfir.assign %arg1 to %arg0 : i32, !fir.ref + return +} +// CHECK-LABEL: func.func @scalar_integer_2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref, +// CHECK-SAME: %[[VAL_1:.*]]: i32) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : i32, !fir.ref + +func.func @scalar_real(%arg0: !fir.ref, %arg1: !fir.ref) { + hlfir.assign %arg1 to %arg0 : !fir.ref, !fir.ref + return +} +// CHECK-LABEL: func.func @scalar_real( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.ref, !fir.ref + +func.func @scalar_complex(%arg0: !fir.ref>, %arg1: !fir.ref>) { + hlfir.assign %arg1 to %arg0 : !fir.ref>, !fir.ref> + return +} +// CHECK-LABEL: func.func @scalar_complex( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.ref>, !fir.ref> + +func.func @scalar_complex_2(%arg0: !fir.ref>, %arg1: !fir.complex<8>) { + hlfir.assign %arg1 to %arg0 : !fir.complex<8>, !fir.ref> + return +} +// CHECK-LABEL: func.func @scalar_complex_2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.complex<8>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.complex<8>, !fir.ref> + + +func.func @scalar_character(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>) { + hlfir.assign %arg1 to %arg0 : !fir.boxchar<1>, !fir.boxchar<1> + return +} +// CHECK-LABEL: func.func @scalar_character( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.boxchar<1>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.boxchar<1>, !fir.boxchar<1> + +func.func @scalar_character_2(%arg0: !fir.ref>, %arg1: !fir.ref>) { + hlfir.assign %arg1 to %arg0 : !fir.ref>, !fir.ref> + return +} +// CHECK-LABEL: func.func @scalar_character_2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.ref>, !fir.ref> + +func.func @scalar_character_3(%arg0: !fir.boxchar<1>, %arg1: !hlfir.expr>) { + hlfir.assign %arg1 to %arg0 : !hlfir.expr>, !fir.boxchar<1> + return +} +// CHECK-LABEL: func.func @scalar_character_3( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1>, +// CHECK-SAME: %[[VAL_1:.*]]: !hlfir.expr>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !hlfir.expr>, !fir.boxchar<1> + +func.func @array(%arg0: !fir.ref>, %arg1: i32) { + hlfir.assign %arg1 to %arg0 : i32, !fir.ref> + return +} +// CHECK-LABEL: func.func @array( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: i32) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : i32, !fir.ref> + +func.func @array_2(%arg0: !fir.ref>, %arg1: !hlfir.expr) { + hlfir.assign %arg1 to %arg0 : !hlfir.expr, !fir.ref> + return +} +// CHECK-LABEL: func.func @array_2( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>, +// CHECK-SAME: %[[VAL_1:.*]]: !hlfir.expr) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !hlfir.expr, !fir.ref> + +func.func @array_3(%arg0: !fir.box>, %arg1: !hlfir.expr) { + hlfir.assign %arg1 to %arg0 : !hlfir.expr, !fir.box> + return +} +// CHECK-LABEL: func.func @array_3( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>, +// CHECK-SAME: %[[VAL_1:.*]]: !hlfir.expr) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !hlfir.expr, !fir.box> + +func.func @array_4(%arg0: !fir.box>, %arg1: !fir.box>) { + hlfir.assign %arg1 to %arg0 : !fir.box>, !fir.box> + return +} +// CHECK-LABEL: func.func @array_4( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.box>) { +// CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_0]] : !fir.box>, !fir.box> diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -35,3 +35,38 @@ %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.ref>) -> (!fir.box>, !fir.ref>) return } + +// ----- +func.func @bad_assign_scalar_character(%arg0: !fir.boxchar<1>, %arg1: !fir.char<1,?>) { + // expected-error@+1 {{'hlfir.assign' op operand #0 must be any Fortran value or variable type, but got '!fir.char<1,?>'}} + hlfir.assign %arg1 to %arg0 : !fir.char<1,?>, !fir.boxchar<1> + return +} + +// ----- +func.func @bad_assign_scalar_character_1(%arg0: !fir.boxchar<1>, %arg1: !hlfir.expr>) { + // expected-error@+1 {{'hlfir.assign' op operand #1 must be any HLFIR variable type, but got '!hlfir.expr>'}} + hlfir.assign %arg0 to %arg1 : !fir.boxchar<1>, !hlfir.expr> + return +} + +// ----- +func.func @bad_assign_scalar_integer(%arg0: !fir.ref, %arg1: i32) { + // expected-error@+1 {{'hlfir.assign' op operand #1 must be any HLFIR variable type, but got 'i32'}} + hlfir.assign %arg0 to %arg1 : !fir.ref, i32 + return +} + +// ----- +func.func @bad_assign_array(%arg0: !fir.ref>, %arg1: !hlfir.expr) { + // expected-error@+1 {{'hlfir.assign' op operand #1 must be any HLFIR variable type, but got '!fir.ref>'}} + hlfir.assign %arg1 to %arg0 : !hlfir.expr, !fir.ref> + return +} + +// ----- +func.func @bad_assign_array_2(%arg0: !fir.ref>, %arg1: !hlfir.expr) { + // expected-error@+1 {{'hlfir.assign' op operand #1 must be any HLFIR variable type, but got '!hlfir.expr'}} + hlfir.assign %arg0 to %arg1 : !fir.ref>, !hlfir.expr + return +}