From 15ea26de243ab56dd0cfe8cafee1366b59d2bb84 Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Fri, 1 Oct 2021 14:39:03 +0200 Subject: [PATCH] [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 --- flang/include/flang/Optimizer/Dialect/FIROps.td | 40 ++++++++++++++++++++++ flang/lib/Optimizer/Dialect/FIROps.cpp | 18 ++++++++++ flang/test/Fir/fir-ops.fir | 9 +++++ flang/test/Fir/invalid.fir | 44 +++++++++++++++++++++++++ 4 files changed, 111 insertions(+) diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index c118d0d..2e37db7 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -294,6 +294,46 @@ def fir_LoadOp : fir_OneResultOp<"load"> { }]; } +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>, i32, + !fir.ref> + ``` + + 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:$from, + AnyIntegerType:$count, + Arg:$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/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 69f7e85..bc4d685 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -668,6 +668,24 @@ static mlir::ParseResult parseCmpOp(mlir::OpAsmParser &parser, } //===----------------------------------------------------------------------===// +// 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(); + }; + 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/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index 2abbcd3..21f3755 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -682,3 +682,12 @@ func @test_save_result(%buffer: !fir.ref>>) { fir.save_result %res to %buffer(%shape) typeparams %c50 : !fir.array>, !fir.ref>>, !fir.shape<1>, index return } + +func @char_convert() { + %1 = fir.undefined i32 + %2 = fir.undefined !fir.ref> + %3 = fir.undefined !fir.ref>> + // CHECK: fir.char_convert %{{.*}} for %{{.*}} to %{{.*}} : !fir.ref>, i32, !fir.ref>> + fir.char_convert %2 for %1 to %3 : !fir.ref>, i32, !fir.ref>> + return +} diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index 4e74de9..a2b367c 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -380,6 +380,50 @@ fir.do_loop %i = %c1 to %c10 step %c1 -> index { // ----- +func @ugly_char_convert() { + %1 = fir.undefined i32 + %2 = fir.undefined !fir.ref> + %3 = fir.undefined !fir.ref>> + // expected-error@+1 {{'fir.char_convert' op buffers must have different KIND values}} + fir.char_convert %2 for %1 to %3 : !fir.ref>, i32, !fir.ref>> + return +} + +// ----- + +func @ugly_char_convert() { + %1 = fir.undefined i32 + %2 = fir.undefined !fir.ref> + %3 = fir.undefined !fir.ref> + // expected-error@+1 {{'fir.char_convert' op not a reference to a character}} + fir.char_convert %2 for %1 to %3 : !fir.ref>, i32, !fir.ref> + return +} + +// ----- + +func @ugly_char_convert() { + %1 = fir.undefined i32 + %2 = fir.undefined !fir.ref> + %3 = fir.undefined !fir.ref>> + // 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>> + return +} + +// ----- + +func @ugly_char_convert() { + %1 = fir.undefined i32 + %2 = fir.undefined !fir.ref> + %3 = fir.undefined !fir.ref>> + // expected-error@+1 {{'fir.char_convert' op operand #1 must be any integer, but got '!fir.ref>'}} + fir.char_convert %2 for %2 to %3 : !fir.ref>, !fir.ref>, !fir.ref>> + return +} + +// ----- + fir.global internal @_QEmultiarray : !fir.array<32x32xi32> { %c0_i32 = constant 1 : i32 %0 = fir.undefined !fir.array<32x32xi32> -- 2.7.4