[fir] Add fir.char_convert op
Add the fir-char_convert op.
This patch is part of the upstreaming effort from fir-dev branch.
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D110818
Co-authored-by: Valentin Clement <clementval@gmail.com>
GitOrigin-RevId: 15ea26de243ab56dd0cfe8cafee1366b59d2bb84
diff --git a/include/flang/Optimizer/Dialect/FIROps.td b/include/flang/Optimizer/Dialect/FIROps.td
index c118d0d..2e37db7 100644
--- a/include/flang/Optimizer/Dialect/FIROps.td
+++ b/include/flang/Optimizer/Dialect/FIROps.td
@@ -294,6 +294,46 @@
}];
}
+def fir_CharConvertOp : fir_Op<"char_convert", []> {
+ let summary = [{
+ Primitive to convert an entity of type CHARACTER from one KIND to a
+ different KIND.
+ }];
+
+ let description = [{
+ Copy a CHARACTER (must be in memory) of KIND _k1_ to a CHARACTER (also must
+ be in memory) of KIND _k2_ where _k1_ != _k2_ and the buffers do not
+ overlap. This latter restriction is unchecked, as the Fortran language
+ definition eliminates the overlapping in memory case.
+
+ The number of code points copied is specified explicitly as the second
+ argument. The length of the !fir.char type is ignored.
+
+ ```mlir
+ fir.char_convert %1 for %2 to %3 : !fir.ref<!fir.char<1,?>>, i32,
+ !fir.ref<!fir.char<2,20>>
+ ```
+
+ Should future support for encodings other than ASCII be supported, codegen
+ can generate a call to a runtime helper routine which will map the code
+ points from UTF-8 to UCS-2, for example. Such remappings may not always
+ be possible as they may involve the creation of more code points than the
+ `count` limit. These details are left as future to-dos.
+ }];
+
+ let arguments = (ins
+ Arg<AnyReferenceLike, "", [MemRead]>:$from,
+ AnyIntegerType:$count,
+ Arg<AnyReferenceLike, "", [MemWrite]>:$to
+ );
+
+ let assemblyFormat = [{
+ $from `for` $count `to` $to attr-dict `:` type(operands)
+ }];
+
+ let verifier = "return ::verify(*this);";
+}
+
def fir_StoreOp : fir_Op<"store", []> {
let summary = "store an SSA-value to a memory location";
diff --git a/lib/Optimizer/Dialect/FIROps.cpp b/lib/Optimizer/Dialect/FIROps.cpp
index 69f7e85..bc4d685 100644
--- a/lib/Optimizer/Dialect/FIROps.cpp
+++ b/lib/Optimizer/Dialect/FIROps.cpp
@@ -668,6 +668,24 @@
}
//===----------------------------------------------------------------------===//
+// CharConvertOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::CharConvertOp op) {
+ auto unwrap = [&](mlir::Type t) {
+ t = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t));
+ return t.dyn_cast<fir::CharacterType>();
+ };
+ auto inTy = unwrap(op.from().getType());
+ auto outTy = unwrap(op.to().getType());
+ if (!(inTy && outTy))
+ return op.emitOpError("not a reference to a character");
+ if (inTy.getFKind() == outTy.getFKind())
+ return op.emitOpError("buffers must have different KIND values");
+ return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
// CmpcOp
//===----------------------------------------------------------------------===//
diff --git a/test/Fir/fir-ops.fir b/test/Fir/fir-ops.fir
index 2abbcd3..21f3755 100644
--- a/test/Fir/fir-ops.fir
+++ b/test/Fir/fir-ops.fir
@@ -682,3 +682,12 @@
fir.save_result %res to %buffer(%shape) typeparams %c50 : !fir.array<?x!fir.char<1,?>>, !fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, index
return
}
+
+func @char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ // CHECK: fir.char_convert %{{.*}} for %{{.*}} to %{{.*}} : !fir.ref<!fir.char<1>>, i32, !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ fir.char_convert %2 for %1 to %3 : !fir.ref<!fir.char<1>>, i32, !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ return
+}
diff --git a/test/Fir/invalid.fir b/test/Fir/invalid.fir
index 4e74de9..a2b367c 100644
--- a/test/Fir/invalid.fir
+++ b/test/Fir/invalid.fir
@@ -380,6 +380,50 @@
// -----
+func @ugly_char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?x!fir.char<1>>>
+ // expected-error@+1 {{'fir.char_convert' op buffers must have different KIND values}}
+ fir.char_convert %2 for %1 to %3 : !fir.ref<!fir.char<1>>, i32, !fir.ref<!fir.array<?x!fir.char<1>>>
+ return
+}
+
+// -----
+
+func @ugly_char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?xf32>>
+ // expected-error@+1 {{'fir.char_convert' op not a reference to a character}}
+ fir.char_convert %2 for %1 to %3 : !fir.ref<!fir.char<1>>, i32, !fir.ref<!fir.array<?xf32>>
+ return
+}
+
+// -----
+
+func @ugly_char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ // expected-error@+1 {{'fir.char_convert' op operand #0 must be any reference, but got 'i32'}}
+ fir.char_convert %1 for %1 to %3 : i32, i32, !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ return
+}
+
+// -----
+
+func @ugly_char_convert() {
+ %1 = fir.undefined i32
+ %2 = fir.undefined !fir.ref<!fir.char<1>>
+ %3 = fir.undefined !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ // expected-error@+1 {{'fir.char_convert' op operand #1 must be any integer, but got '!fir.ref<!fir.char<1>>'}}
+ fir.char_convert %2 for %2 to %3 : !fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>, !fir.ref<!fir.array<?x!fir.char<2,?>>>
+ return
+}
+
+// -----
+
fir.global internal @_QEmultiarray : !fir.array<32x32xi32> {
%c0_i32 = constant 1 : i32
%0 = fir.undefined !fir.array<32x32xi32>