diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -32,6 +32,7 @@ #include "flang/Optimizer/Support/FatalError.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #define DEBUG_TYPE "flang-lower-intrinsic" @@ -452,8 +453,10 @@ /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments /// in the llvm::ArrayRef. mlir::Value genIand(mlir::Type, llvm::ArrayRef); + mlir::Value genIbclr(mlir::Type, llvm::ArrayRef); mlir::Value genIbits(mlir::Type, llvm::ArrayRef); mlir::Value genIbset(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genIchar(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef); @@ -608,9 +611,12 @@ &I::genDotProduct, {{{"vector_a", asBox}, {"vector_b", asBox}}}, /*isElemental=*/false}, + {"iachar", &I::genIchar}, {"iand", &I::genIand}, + {"ibclr", &I::genIbclr}, {"ibits", &I::genIbits}, {"ibset", &I::genIbset}, + {"ichar", &I::genIchar}, {"len", &I::genLen, {{{"string", asInquired}, {"kind", asValue}}}, @@ -1706,6 +1712,22 @@ return builder.create(loc, args[0], args[1]); } +// IBCLR +mlir::Value IntrinsicLibrary::genIbclr(mlir::Type resultType, + llvm::ArrayRef args) { + // A conformant IBCLR(I,POS) call satisfies: + // POS >= 0 + // POS < BIT_SIZE(I) + // Return: I & (!(1 << POS)) + assert(args.size() == 2); + mlir::Value pos = builder.createConvert(loc, resultType, args[1]); + mlir::Value one = builder.createIntegerConstant(loc, resultType, 1); + mlir::Value ones = builder.createIntegerConstant(loc, resultType, -1); + auto mask = builder.create(loc, one, pos); + auto res = builder.create(loc, ones, mask); + return builder.create(loc, args[0], res); +} + // IBITS mlir::Value IntrinsicLibrary::genIbits(mlir::Type resultType, llvm::ArrayRef args) { @@ -1747,6 +1769,42 @@ return builder.create(loc, args[0], mask); } +// ICHAR +fir::ExtendedValue +IntrinsicLibrary::genIchar(mlir::Type resultType, + llvm::ArrayRef args) { + // There can be an optional kind in second argument. + assert(args.size() == 2); + const fir::CharBoxValue *charBox = args[0].getCharBox(); + if (!charBox) + llvm::report_fatal_error("expected character scalar"); + + fir::factory::CharacterExprHelper helper{builder, loc}; + mlir::Value buffer = charBox->getBuffer(); + mlir::Type bufferTy = buffer.getType(); + mlir::Value charVal; + if (auto charTy = bufferTy.dyn_cast()) { + assert(charTy.singleton()); + charVal = buffer; + } else { + // Character is in memory, cast to fir.ref and load. + mlir::Type ty = fir::dyn_cast_ptrEleTy(bufferTy); + if (!ty) + llvm::report_fatal_error("expected memory type"); + // The length of in the character type may be unknown. Casting + // to a singleton ref is required before loading. + fir::CharacterType eleType = helper.getCharacterType(ty); + fir::CharacterType charType = + fir::CharacterType::get(builder.getContext(), eleType.getFKind(), 1); + mlir::Type toTy = builder.getRefType(charType); + mlir::Value cast = builder.createConvert(loc, toTy, buffer); + charVal = builder.create(loc, cast); + } + LLVM_DEBUG(llvm::dbgs() << "ichar(" << charVal << ")\n"); + auto code = helper.extractCodeFromSingleton(charVal); + return builder.create(loc, resultType, code); +} + // LEN // Note that this is only used for an unrestricted intrinsic LEN call. // Other uses of LEN are rewritten as descriptor inquiries by the front-end. diff --git a/flang/test/Lower/Intrinsics/ichar.f90 b/flang/test/Lower/Intrinsics/ichar.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/Intrinsics/ichar.f90 @@ -0,0 +1,33 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s +! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: ichar_test +subroutine ichar_test(c) + character(1) :: c + character :: str(10) + ! CHECK-DAG: %[[unbox:.*]]:2 = fir.unboxchar + ! CHECK-DAG: %[[J:.*]] = fir.alloca i32 {{{.*}}uniq_name = "{{.*}}Ej"} + ! CHECK-DAG: %[[STR:.*]] = fir.alloca !fir.array{{.*}} {{{.*}}uniq_name = "{{.*}}Estr"} + ! CHECK: %[[BOX:.*]] = fir.convert %[[unbox]]#0 : (!fir.ref>) -> !fir.ref> + ! CHECK: %[[PTR:.*]] = fir.load %[[BOX]] : !fir.ref> + ! CHECK: %[[CHAR:.*]] = fir.extract_value %[[PTR]], [0 : index] : + ! CHECK: %[[ARG:.*]] = arith.extui %[[CHAR]] : i8 to i32 + ! CHECK: fir.call @{{.*}}OutputInteger32{{.*}}%[[ARG]] + ! CHECK: fir.call @{{.*}}EndIoStatement + print *, ichar(c) + + ! CHECK-DAG: %{{.*}} = fir.load %[[J]] : !fir.ref + ! CHECK: %[[PTR1:.*]] = fir.coordinate_of %[[STR]], % + ! CHECK: %[[PTR2:.*]] = fir.load %[[PTR1]] : !fir.ref> + ! CHECK: %[[CHAR:.*]] = fir.extract_value %[[PTR2]], [0 : index] : + ! CHECK: %[[ARG:.*]] = arith.extui %[[CHAR]] : i8 to i32 + ! CHECK: fir.call @{{.*}}OutputInteger32{{.*}}%[[ARG]] + ! CHECK: fir.call @{{.*}}EndIoStatement + print *, ichar(str(J)) + + ! "Magic" 88 below is the value returned by IACHAR (’X’) + ! CHECK: %[[c88:.*]] = arith.constant 88 : i32 + ! CHECK-NEXT: fir.call @{{.*}}OutputInteger32({{.*}}, %[[c88]]) + ! CHECK-NEXT: fir.call @{{.*}}EndIoStatement + print *, iachar('X') +end subroutine