[flang-commits] [flang] 67b23fe - [flang] Lower some numeric intrinsics

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Thu Mar 17 09:19:36 PDT 2022


Author: Valentin Clement
Date: 2022-03-17T17:19:29+01:00
New Revision: 67b23feab2ab2aef836394ab71d3dad2ec7bc7aa

URL: https://github.com/llvm/llvm-project/commit/67b23feab2ab2aef836394ab71d3dad2ec7bc7aa
DIFF: https://github.com/llvm/llvm-project/commit/67b23feab2ab2aef836394ab71d3dad2ec7bc7aa.diff

LOG: [flang] Lower some numeric intrinsics

This patch adds lowering for the following numeric intrinsics:
- aint
- anint
- cmplx
- conjg
- dble
- dprod
- sign

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: schweitz

Differential Revision: https://reviews.llvm.org/D121917

Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: V Donaldson <vdonaldson at nvidia.com>

Added: 
    flang/test/Lower/Intrinsics/aint.f90
    flang/test/Lower/Intrinsics/anint.f90
    flang/test/Lower/Intrinsics/cmplx.f90
    flang/test/Lower/Intrinsics/conjg.f90
    flang/test/Lower/Intrinsics/dble.f90
    flang/test/Lower/Intrinsics/dprod.f90
    flang/test/Lower/Intrinsics/sign.f90

Modified: 
    flang/lib/Lower/ConvertExpr.cpp
    flang/lib/Lower/IntrinsicCall.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 2906fd68c8299..2116ac69476f6 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -345,10 +345,16 @@ static fir::ExtendedValue genLoad(fir::FirOpBuilder &builder,
         return builder.create<fir::LoadOp>(loc, fir::getBase(v));
       },
       [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
-        TODO(loc, "genLoad for MutableBoxValue");
+        return genLoad(builder, loc,
+                       fir::factory::genMutableBoxRead(builder, loc, box));
       },
       [&](const fir::BoxValue &box) -> fir::ExtendedValue {
-        TODO(loc, "genLoad for BoxValue");
+        if (box.isUnlimitedPolymorphic())
+          fir::emitFatalError(
+              loc,
+              "lowering attempting to load an unlimited polymorphic entity");
+        return genLoad(builder, loc,
+                       fir::factory::readBoxValue(builder, loc, box));
       },
       [&](const auto &) -> fir::ExtendedValue {
         fir::emitFatalError(

diff  --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index e04984433ed47..67c50eb4bbdc6 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -110,6 +110,9 @@ static bool isAbsent(const fir::ExtendedValue &exv) {
 static bool isAbsent(llvm::ArrayRef<fir::ExtendedValue> args, size_t argIndex) {
   return args.size() <= argIndex || isAbsent(args[argIndex]);
 }
+static bool isAbsent(llvm::ArrayRef<mlir::Value> args, size_t argIndex) {
+  return args.size() <= argIndex || !args[argIndex];
+}
 
 /// Test if an ExtendedValue is present.
 static bool isPresent(const fir::ExtendedValue &exv) { return !isAbsent(exv); }
@@ -437,9 +440,11 @@ struct IntrinsicLibrary {
   fir::ExtendedValue genAdjustRtCall(mlir::Type,
                                      llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genAll(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genAllocated(mlir::Type,
                                   llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genAny(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genAssociated(mlir::Type,
                                    llvm::ArrayRef<fir::ExtendedValue>);
@@ -452,12 +457,15 @@ struct IntrinsicLibrary {
   template <mlir::arith::CmpIPredicate pred>
   fir::ExtendedValue genCharacterCompare(mlir::Type,
                                          llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
   void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genCshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genDotProduct(mlir::Type,
                                    llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   void genExit(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
@@ -505,6 +513,7 @@ struct IntrinsicLibrary {
   fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genSetExponent(mlir::Type resultType,
                              llvm::ArrayRef<mlir::Value> args);
+  mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genSpread(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@@ -517,6 +526,10 @@ struct IntrinsicLibrary {
   fir::ExtendedValue genUbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genUnpack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genVerify(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  /// Implement all conversion functions like DBLE, the first argument is
+  /// the value to convert. There may be an additional KIND arguments that
+  /// is ignored because this is already reflected in the result type.
+  mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
 
   /// Define the 
diff erent FIR generators that can be mapped to intrinsic to
   /// generate the related code.
@@ -621,6 +634,7 @@ static constexpr IntrinsicHandler handlers[]{
      {{{"string", asAddr}}},
      /*isElemental=*/true},
     {"aimag", &I::genAimag},
+    {"aint", &I::genAint},
     {"all",
      &I::genAll,
      {{{"mask", asAddr}, {"dim", asValue}}},
@@ -629,6 +643,7 @@ static constexpr IntrinsicHandler handlers[]{
      &I::genAllocated,
      {{{"array", asInquired}, {"scalar", asInquired}}},
      /*isElemental=*/false},
+    {"anint", &I::genAnint},
     {"any",
      &I::genAny,
      {{{"mask", asAddr}, {"dim", asValue}}},
@@ -640,7 +655,11 @@ static constexpr IntrinsicHandler handlers[]{
     {"btest", &I::genBtest},
     {"ceiling", &I::genCeiling},
     {"char", &I::genChar},
+    {"cmplx",
+     &I::genCmplx,
+     {{{"x", asValue}, {"y", asValue, handleDynamicOptional}}}},
     {"command_argument_count", &I::genCommandArgumentCount},
+    {"conjg", &I::genConjg},
     {"count",
      &I::genCount,
      {{{"mask", asAddr}, {"dim", asValue}, {"kind", asValue}}},
@@ -660,11 +679,13 @@ static constexpr IntrinsicHandler handlers[]{
        {"zone", asAddr, handleDynamicOptional},
        {"values", asBox, handleDynamicOptional}}},
      /*isElemental=*/false},
+    {"dble", &I::genConversion},
     {"dim", &I::genDim},
     {"dot_product",
      &I::genDotProduct,
      {{{"vector_a", asBox}, {"vector_b", asBox}}},
      /*isElemental=*/false},
+    {"dprod", &I::genDprod},
     {"eoshift",
      &I::genEoshift,
      {{{"array", asBox},
@@ -811,6 +832,7 @@ static constexpr IntrinsicHandler handlers[]{
        {"kind", asValue}}},
      /*isElemental=*/true},
     {"set_exponent", &I::genSetExponent},
+    {"sign", &I::genSign},
     {"size",
      &I::genSize,
      {{{"array", asBox},
@@ -928,6 +950,16 @@ static mlir::FunctionType genF64F64F64FuncType(mlir::MLIRContext *context) {
   return mlir::FunctionType::get(context, {t, t}, {t});
 }
 
+static mlir::FunctionType genF80F80F80FuncType(mlir::MLIRContext *context) {
+  auto t = mlir::FloatType::getF80(context);
+  return mlir::FunctionType::get(context, {t, t}, {t});
+}
+
+static mlir::FunctionType genF128F128F128FuncType(mlir::MLIRContext *context) {
+  auto t = mlir::FloatType::getF128(context);
+  return mlir::FunctionType::get(context, {t, t}, {t});
+}
+
 template <int Bits>
 static mlir::FunctionType genIntF64FuncType(mlir::MLIRContext *context) {
   auto t = mlir::FloatType::getF64(context);
@@ -948,6 +980,10 @@ static mlir::FunctionType genIntF32FuncType(mlir::MLIRContext *context) {
 static constexpr RuntimeFunction llvmIntrinsics[] = {
     {"abs", "llvm.fabs.f32", genF32F32FuncType},
     {"abs", "llvm.fabs.f64", genF64F64FuncType},
+    {"aint", "llvm.trunc.f32", genF32F32FuncType},
+    {"aint", "llvm.trunc.f64", genF64F64FuncType},
+    {"anint", "llvm.round.f32", genF32F32FuncType},
+    {"anint", "llvm.round.f64", genF64F64FuncType},
     // ceil is used for CEILING but is 
diff erent, it returns a real.
     {"ceil", "llvm.ceil.f32", genF32F32FuncType},
     {"ceil", "llvm.ceil.f64", genF64F64FuncType},
@@ -960,6 +996,10 @@ static constexpr RuntimeFunction llvmIntrinsics[] = {
     {"nint", "llvm.lround.i32.f32", genIntF32FuncType<32>},
     {"pow", "llvm.pow.f32", genF32F32F32FuncType},
     {"pow", "llvm.pow.f64", genF64F64F64FuncType},
+    {"sign", "llvm.copysign.f32", genF32F32F32FuncType},
+    {"sign", "llvm.copysign.f64", genF64F64F64FuncType},
+    {"sign", "llvm.copysign.f80", genF80F80F80FuncType},
+    {"sign", "llvm.copysign.f128", genF128F128F128FuncType},
 };
 
 // This helper class computes a "distance" between two function types.
@@ -1611,6 +1651,13 @@ mlir::Value IntrinsicLibrary::genRuntimeCall(llvm::StringRef name,
   return getRuntimeCallGenerator(name, soughtFuncType)(builder, loc, args);
 }
 
+mlir::Value IntrinsicLibrary::genConversion(mlir::Type resultType,
+                                            llvm::ArrayRef<mlir::Value> args) {
+  // There can be an optional kind in second argument.
+  assert(args.size() >= 1);
+  return builder.convertWithSemantics(loc, resultType, args[0]);
+}
+
 // ABS
 mlir::Value IntrinsicLibrary::genAbs(mlir::Type resultType,
                                      llvm::ArrayRef<mlir::Value> args) {
@@ -1679,6 +1726,15 @@ mlir::Value IntrinsicLibrary::genAimag(mlir::Type resultType,
       args[0], true /* isImagPart */);
 }
 
+// AINT
+mlir::Value IntrinsicLibrary::genAint(mlir::Type resultType,
+                                      llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() >= 1 && args.size() <= 2);
+  // Skip optional kind argument to search the runtime; it is already reflected
+  // in result type.
+  return genRuntimeCall("aint", resultType, {args[0]});
+}
+
 // ALL
 fir::ExtendedValue
 IntrinsicLibrary::genAll(mlir::Type resultType,
@@ -1740,6 +1796,15 @@ IntrinsicLibrary::genAllocated(mlir::Type resultType,
       });
 }
 
+// ANINT
+mlir::Value IntrinsicLibrary::genAnint(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() >= 1 && args.size() <= 2);
+  // Skip optional kind argument to search the runtime; it is already reflected
+  // in result type.
+  return genRuntimeCall("anint", resultType, {args[0]});
+}
+
 // ANY
 fir::ExtendedValue
 IntrinsicLibrary::genAny(mlir::Type resultType,
@@ -1871,6 +1936,20 @@ IntrinsicLibrary::genChar(mlir::Type type,
   return fir::CharBoxValue{cast, len};
 }
 
+// CMPLX
+mlir::Value IntrinsicLibrary::genCmplx(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() >= 1);
+  fir::factory::Complex complexHelper(builder, loc);
+  mlir::Type partType = complexHelper.getComplexPartType(resultType);
+  mlir::Value real = builder.createConvert(loc, partType, args[0]);
+  mlir::Value imag = isAbsent(args, 1)
+                         ? builder.createRealZeroConstant(loc, partType)
+                         : builder.createConvert(loc, partType, args[1]);
+  return fir::factory::Complex{builder, loc}.createComplex(resultType, real,
+                                                           imag);
+}
+
 // COMMAND_ARGUMENT_COUNT
 fir::ExtendedValue IntrinsicLibrary::genCommandArgumentCount(
     mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
@@ -1882,6 +1961,21 @@ fir::ExtendedValue IntrinsicLibrary::genCommandArgumentCount(
   ;
 }
 
+// CONJG
+mlir::Value IntrinsicLibrary::genConjg(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 1);
+  if (resultType != args[0].getType())
+    llvm_unreachable("argument type mismatch");
+
+  mlir::Value cplx = args[0];
+  auto imag = fir::factory::Complex{builder, loc}.extractComplexPart(
+      cplx, /*isImagPart=*/true);
+  auto negImag = builder.create<mlir::arith::NegFOp>(loc, imag);
+  return fir::factory::Complex{builder, loc}.insertComplexPart(
+      cplx, negImag, /*isImagPart=*/true);
+}
+
 // COUNT
 fir::ExtendedValue
 IntrinsicLibrary::genCount(mlir::Type resultType,
@@ -2030,6 +2124,17 @@ mlir::Value IntrinsicLibrary::genDim(mlir::Type resultType,
   return builder.create<mlir::arith::SelectOp>(loc, cmp, 
diff , zero);
 }
 
+// DPROD
+mlir::Value IntrinsicLibrary::genDprod(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 2);
+  assert(fir::isa_real(resultType) &&
+         "Result must be double precision in DPROD");
+  mlir::Value a = builder.createConvert(loc, resultType, args[0]);
+  mlir::Value b = builder.createConvert(loc, resultType, args[1]);
+  return builder.create<mlir::arith::MulFOp>(loc, a, b);
+}
+
 // DOT_PRODUCT
 fir::ExtendedValue
 IntrinsicLibrary::genDotProduct(mlir::Type resultType,
@@ -3010,51 +3115,19 @@ mlir::Value IntrinsicLibrary::genSetExponent(mlir::Type resultType,
                                    fir::getBase(args[1])));
 }
 
-// SPREAD
-fir::ExtendedValue
-IntrinsicLibrary::genSpread(mlir::Type resultType,
-                            llvm::ArrayRef<fir::ExtendedValue> args) {
-
-  assert(args.size() == 3);
-
-  // Handle source argument
-  mlir::Value source = builder.createBox(loc, args[0]);
-  fir::BoxValue sourceTmp = source;
-  unsigned sourceRank = sourceTmp.rank();
-
-  // Handle Dim argument
-  mlir::Value dim = fir::getBase(args[1]);
-
-  // Handle ncopies argument
-  mlir::Value ncopies = fir::getBase(args[2]);
-
-  // Generate result descriptor
-  mlir::Type resultArrayType =
-      builder.getVarLenSeqTy(resultType, sourceRank + 1);
-  fir::MutableBoxValue resultMutableBox =
-      fir::factory::createTempMutableBox(builder, loc, resultArrayType);
-  mlir::Value resultIrBox =
-      fir::factory::getMutableIRBox(builder, loc, resultMutableBox);
-
-  fir::runtime::genSpread(builder, loc, resultIrBox, source, dim, ncopies);
-
-  return readAndAddCleanUp(resultMutableBox, resultType,
-                           "unexpected result for SPREAD");
-}
-
-// SUM
-fir::ExtendedValue
-IntrinsicLibrary::genSum(mlir::Type resultType,
-                         llvm::ArrayRef<fir::ExtendedValue> args) {
-  return genProdOrSum(fir::runtime::genSum, fir::runtime::genSumDim, resultType,
-                      builder, loc, stmtCtx, "unexpected result for Sum", args);
-}
-
-// SYSTEM_CLOCK
-void IntrinsicLibrary::genSystemClock(llvm::ArrayRef<fir::ExtendedValue> args) {
-  assert(args.size() == 3);
-  Fortran::lower::genSystemClock(builder, loc, fir::getBase(args[0]),
-                                 fir::getBase(args[1]), fir::getBase(args[2]));
+// SIGN
+mlir::Value IntrinsicLibrary::genSign(mlir::Type resultType,
+                                      llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 2);
+  if (resultType.isa<mlir::IntegerType>()) {
+    mlir::Value abs = genAbs(resultType, {args[0]});
+    mlir::Value zero = builder.createIntegerConstant(loc, resultType, 0);
+    auto neg = builder.create<mlir::arith::SubIOp>(loc, zero, abs);
+    auto cmp = builder.create<mlir::arith::CmpIOp>(
+        loc, mlir::arith::CmpIPredicate::slt, args[1], zero);
+    return builder.create<mlir::arith::SelectOp>(loc, cmp, neg, abs);
+  }
+  return genRuntimeCall("sign", resultType, args);
 }
 
 // SIZE
@@ -3103,6 +3176,53 @@ IntrinsicLibrary::genSize(mlir::Type resultType,
       .getResults()[0];
 }
 
+// SPREAD
+fir::ExtendedValue
+IntrinsicLibrary::genSpread(mlir::Type resultType,
+                            llvm::ArrayRef<fir::ExtendedValue> args) {
+
+  assert(args.size() == 3);
+
+  // Handle source argument
+  mlir::Value source = builder.createBox(loc, args[0]);
+  fir::BoxValue sourceTmp = source;
+  unsigned sourceRank = sourceTmp.rank();
+
+  // Handle Dim argument
+  mlir::Value dim = fir::getBase(args[1]);
+
+  // Handle ncopies argument
+  mlir::Value ncopies = fir::getBase(args[2]);
+
+  // Generate result descriptor
+  mlir::Type resultArrayType =
+      builder.getVarLenSeqTy(resultType, sourceRank + 1);
+  fir::MutableBoxValue resultMutableBox =
+      fir::factory::createTempMutableBox(builder, loc, resultArrayType);
+  mlir::Value resultIrBox =
+      fir::factory::getMutableIRBox(builder, loc, resultMutableBox);
+
+  fir::runtime::genSpread(builder, loc, resultIrBox, source, dim, ncopies);
+
+  return readAndAddCleanUp(resultMutableBox, resultType,
+                           "unexpected result for SPREAD");
+}
+
+// SUM
+fir::ExtendedValue
+IntrinsicLibrary::genSum(mlir::Type resultType,
+                         llvm::ArrayRef<fir::ExtendedValue> args) {
+  return genProdOrSum(fir::runtime::genSum, fir::runtime::genSumDim, resultType,
+                      builder, loc, stmtCtx, "unexpected result for Sum", args);
+}
+
+// SYSTEM_CLOCK
+void IntrinsicLibrary::genSystemClock(llvm::ArrayRef<fir::ExtendedValue> args) {
+  assert(args.size() == 3);
+  Fortran::lower::genSystemClock(builder, loc, fir::getBase(args[0]),
+                                 fir::getBase(args[1]), fir::getBase(args[2]));
+}
+
 // TRANSFER
 fir::ExtendedValue
 IntrinsicLibrary::genTransfer(mlir::Type resultType,

diff  --git a/flang/test/Lower/Intrinsics/aint.f90 b/flang/test/Lower/Intrinsics/aint.f90
new file mode 100644
index 0000000000000..dd42f8663999b
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/aint.f90
@@ -0,0 +1,12 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func @_QPaint_test(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>{{.*}}, %[[VAL_1:.*]]: !fir.ref<f32>{{.*}}) {
+subroutine aint_test(a, b)
+! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<f32>
+! CHECK: %[[VAL_3:.*]] = fir.call @llvm.trunc.f32(%[[VAL_2]]) : (f32) -> f32
+! CHECK: fir.store %[[VAL_3]] to %[[VAL_1]] : !fir.ref<f32>
+! CHECK: return
+  real :: a, b
+  b = aint(a)
+end subroutine

diff  --git a/flang/test/Lower/Intrinsics/anint.f90 b/flang/test/Lower/Intrinsics/anint.f90
new file mode 100644
index 0000000000000..7199796710f15
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/anint.f90
@@ -0,0 +1,9 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: anint_test
+subroutine anint_test(a, b)
+  real :: a, b
+  ! CHECK: fir.call @llvm.round.f32
+  b = anint(a)
+end subroutine
+  
\ No newline at end of file

diff  --git a/flang/test/Lower/Intrinsics/cmplx.f90 b/flang/test/Lower/Intrinsics/cmplx.f90
new file mode 100644
index 0000000000000..0eb653fe05fbf
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/cmplx.f90
@@ -0,0 +1,157 @@
+! This test focus on cmplx with Y argument that may turn out
+! to be absent at runtime because it is an unallocated allocatable,
+! a disassociated pointer, or an optional argument.
+! CMPLX without such argument is re-written by the front-end as a
+! complex constructor that is tested elsewhere.
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func @_QPcmplx_test_scalar_ptr(
+! CHECK-SAME:  %[[VAL_0:.*]]: !fir.ref<f32>
+! CHECK-SAME:  %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.ptr<f32>>>
+subroutine cmplx_test_scalar_ptr(x, y)
+  real :: x
+  real, pointer :: y
+  print *, cmplx(x, y)
+! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_0]] : !fir.ref<f32>
+! CHECK:  %[[VAL_8:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.ptr<f32>>>
+! CHECK:  %[[VAL_9:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+! CHECK:  %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ptr<f32>) -> i64
+! CHECK:  %[[VAL_11:.*]] = arith.constant 0 : i64
+! CHECK:  %[[VAL_12:.*]] = arith.cmpi ne, %[[VAL_10]], %[[VAL_11]] : i64
+! CHECK:  %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (f32) {
+! CHECK:    %[[VAL_14:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.ptr<f32>>>
+! CHECK:    %[[VAL_15:.*]] = fir.box_addr %[[VAL_14]] : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+! CHECK:    %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.ptr<f32>
+! CHECK:    fir.result %[[VAL_16]] : f32
+! CHECK:  } else {
+! CHECK:    %[[VAL_17:.*]] = arith.constant 0.000000e+00 : f32
+! CHECK:    fir.result %[[VAL_17]] : f32
+! CHECK:  }
+! CHECK:  %[[VAL_18:.*]] = fir.undefined !fir.complex<4>
+! CHECK:  %[[VAL_19:.*]] = fir.insert_value %[[VAL_18]], %[[VAL_7]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK:   fir.insert_value %[[VAL_19]], %[[VAL_21:.*]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+end subroutine
+
+! CHECK-LABEL: func @_QPcmplx_test_scalar_optional(
+! CHECK-SAME:  %[[VAL_0:[^:]*]]: !fir.ref<f32>
+! CHECK-SAME:  %[[VAL_1:.*]]: !fir.ref<f32>
+subroutine cmplx_test_scalar_optional(x, y)
+  real :: x
+  real, optional :: y
+  print *, cmplx(x, y)
+! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_0]] : !fir.ref<f32>
+! CHECK:  %[[VAL_8:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref<f32>) -> i1
+! CHECK:  %[[VAL_9:.*]] = fir.if %[[VAL_8]] -> (f32) {
+! CHECK:    %[[VAL_10:.*]] = fir.load %[[VAL_1]] : !fir.ref<f32>
+! CHECK:    fir.result %[[VAL_10]] : f32
+! CHECK:  } else {
+! CHECK:    %[[VAL_11:.*]] = arith.constant 0.000000e+00 : f32
+! CHECK:    fir.result %[[VAL_11]] : f32
+! CHECK:  }
+! CHECK:  %[[VAL_12:.*]] = fir.undefined !fir.complex<4>
+! CHECK:  %[[VAL_13:.*]] = fir.insert_value %[[VAL_12]], %[[VAL_7]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK:  fir.insert_value %[[VAL_13]], %[[VAL_15:.*]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+end subroutine
+
+! CHECK-LABEL: func @_QPcmplx_test_scalar_alloc_optional(
+! CHECK-SAME:  %[[VAL_0:.*]]: !fir.ref<f32>
+! CHECK-SAME:  %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<i64>>>
+subroutine cmplx_test_scalar_alloc_optional(x, y)
+  real :: x
+  integer(8), allocatable, optional :: y
+  print *, cmplx(x, y)
+! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_0]] : !fir.ref<f32>
+! CHECK:  %[[VAL_8:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<i64>>>
+! CHECK:  %[[VAL_9:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box<!fir.heap<i64>>) -> !fir.heap<i64>
+! CHECK:  %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.heap<i64>) -> i64
+! CHECK:  %[[VAL_11:.*]] = arith.constant 0 : i64
+! CHECK:  %[[VAL_12:.*]] = arith.cmpi ne, %[[VAL_10]], %[[VAL_11]] : i64
+! CHECK:  %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (i64) {
+! CHECK:    %[[VAL_14:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<i64>>>
+! CHECK:    %[[VAL_15:.*]] = fir.box_addr %[[VAL_14]] : (!fir.box<!fir.heap<i64>>) -> !fir.heap<i64>
+! CHECK:    %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.heap<i64>
+! CHECK:    fir.result %[[VAL_16]] : i64
+! CHECK:  } else {
+! CHECK:    %[[VAL_17:.*]] = arith.constant 0 : i64
+! CHECK:    fir.result %[[VAL_17]] : i64
+! CHECK:  }
+! CHECK:  %[[VAL_18:.*]] = fir.convert %[[VAL_19:.*]] : (i64) -> f32
+! CHECK:  %[[VAL_20:.*]] = fir.undefined !fir.complex<4>
+! CHECK:  %[[VAL_21:.*]] = fir.insert_value %[[VAL_20]], %[[VAL_7]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK:  fir.insert_value %[[VAL_21]], %[[VAL_18]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+end subroutine
+
+! CHECK-LABEL: func @_QPcmplx_test_pointer_result(
+! CHECK-SAME:  %[[VAL_0:[^:]*]]: !fir.ref<f32>
+! CHECK-SAME:  %[[VAL_1:.*]]: !fir.ref<f32>
+subroutine cmplx_test_pointer_result(x, y)
+  real :: x
+  interface
+    function return_pointer()
+      real, pointer :: return_pointer
+    end function
+  end interface
+  print *, cmplx(x, return_pointer())
+! CHECK:  %[[VAL_9:.*]] = fir.call @_QPreturn_pointer() : () -> !fir.box<!fir.ptr<f32>>
+! CHECK:  fir.save_result %[[VAL_9]] to %[[VAL_2:.*]] : !fir.box<!fir.ptr<f32>>, !fir.ref<!fir.box<!fir.ptr<f32>>>
+! CHECK:  %[[VAL_10:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.ptr<f32>>>
+! CHECK:  %[[VAL_11:.*]] = fir.box_addr %[[VAL_10]] : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+! CHECK:  %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ptr<f32>) -> i64
+! CHECK:  %[[VAL_13:.*]] = arith.constant 0 : i64
+! CHECK:  %[[VAL_14:.*]] = arith.cmpi ne, %[[VAL_12]], %[[VAL_13]] : i64
+! CHECK:  %[[VAL_15:.*]] = fir.if %[[VAL_14]] -> (f32) {
+! CHECK:    %[[VAL_16:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.ptr<f32>>>
+! CHECK:    %[[VAL_17:.*]] = fir.box_addr %[[VAL_16]] : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+! CHECK:    %[[VAL_18:.*]] = fir.load %[[VAL_17]] : !fir.ptr<f32>
+! CHECK:    fir.result %[[VAL_18]] : f32
+! CHECK:  } else {
+! CHECK:    %[[VAL_19:.*]] = arith.constant 0.000000e+00 : f32
+! CHECK:    fir.result %[[VAL_19]] : f32
+! CHECK:  }
+! CHECK:  %[[VAL_20:.*]] = fir.undefined !fir.complex<4>
+! CHECK:  %[[VAL_21:.*]] = fir.insert_value %[[VAL_20]], %[[VAL_8]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK:  fir.insert_value %[[VAL_21]], %[[VAL_23:.*]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+end subroutine
+
+! CHECK-LABEL: func @_QPcmplx_array(
+! CHECK-SAME:  %[[VAL_0:[^:]*]]: !fir.box<!fir.array<?xf32>>
+! CHECK-SAME:  %[[VAL_1:.*]]: !fir.box<!fir.array<?xf32>>
+subroutine cmplx_array(x, y)
+  ! Important, note that the shape is taken from `x` and not `y` that
+  ! may be absent.
+  real :: x(:)
+  real, optional :: y(:)
+  print *, cmplx(x, y)
+! CHECK:  %[[VAL_7:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_8:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_7]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_9:.*]] = fir.array_load %[[VAL_0]] : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>
+! CHECK:  %[[VAL_10:.*]] = fir.is_present %[[VAL_1]] : (!fir.box<!fir.array<?xf32>>) -> i1
+! CHECK:  %[[VAL_11:.*]] = fir.zero_bits !fir.ref<!fir.array<?xf32>>
+! CHECK:  %[[VAL_12:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_14:.*]] = fir.embox %[[VAL_11]](%[[VAL_13]]) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
+! CHECK:  %[[VAL_15:.*]] = arith.select %[[VAL_10]], %[[VAL_1]], %[[VAL_14]] : !fir.box<!fir.array<?xf32>>
+! CHECK:  %[[VAL_16:.*]] = fir.array_load %[[VAL_15]] {fir.optional} : (!fir.box<!fir.array<?xf32>>) -> !fir.array<?xf32>
+! CHECK:  %[[VAL_17:.*]] = fir.allocmem !fir.array<?x!fir.complex<4>>, %[[VAL_8]]#1 {uniq_name = ".array.expr"}
+! CHECK:  %[[VAL_18:.*]] = fir.shape %[[VAL_8]]#1 : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_19:.*]] = fir.array_load %[[VAL_17]](%[[VAL_18]]) : (!fir.heap<!fir.array<?x!fir.complex<4>>>, !fir.shape<1>) -> !fir.array<?x!fir.complex<4>>
+! CHECK:  %[[VAL_20:.*]] = arith.constant 1 : index
+! CHECK:  %[[VAL_21:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_22:.*]] = arith.subi %[[VAL_8]]#1, %[[VAL_20]] : index
+! CHECK:  %[[VAL_23:.*]] = fir.do_loop %[[VAL_24:.*]] = %[[VAL_21]] to %[[VAL_22]] step %[[VAL_20]] unordered iter_args(%[[VAL_25:.*]] = %[[VAL_19]]) -> (!fir.array<?x!fir.complex<4>>) {
+  ! CHECK:  %[[VAL_26:.*]] = fir.array_fetch %[[VAL_9]], %[[VAL_24]] : (!fir.array<?xf32>, index) -> f32
+  ! CHECK:  %[[VAL_27:.*]] = fir.if %[[VAL_10]] -> (f32) {
+    ! CHECK:  %[[VAL_28:.*]] = fir.array_fetch %[[VAL_16]], %[[VAL_24]] : (!fir.array<?xf32>, index) -> f32
+    ! CHECK:  fir.result %[[VAL_28]] : f32
+  ! CHECK:  } else {
+    ! CHECK:  %[[VAL_29:.*]] = arith.constant 0.000000e+00 : f32
+    ! CHECK:  fir.result %[[VAL_29]] : f32
+  ! CHECK:  }
+  ! CHECK:  %[[VAL_30:.*]] = fir.undefined !fir.complex<4>
+  ! CHECK:  %[[VAL_31:.*]] = fir.insert_value %[[VAL_30]], %[[VAL_26]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  ! CHECK:  %[[VAL_32:.*]] = fir.insert_value %[[VAL_31]], %[[VAL_33:.*]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  ! CHECK:  %[[VAL_34:.*]] = fir.array_update %[[VAL_25]], %[[VAL_32]], %[[VAL_24]] : (!fir.array<?x!fir.complex<4>>, !fir.complex<4>, index) -> !fir.array<?x!fir.complex<4>>
+  ! CHECK:  fir.result %[[VAL_34]] : !fir.array<?x!fir.complex<4>>
+! CHECK:  }
+! CHECK:  fir.array_merge_store
+end subroutine

diff  --git a/flang/test/Lower/Intrinsics/conjg.f90 b/flang/test/Lower/Intrinsics/conjg.f90
new file mode 100644
index 0000000000000..a1c5a56d9de5a
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/conjg.f90
@@ -0,0 +1,10 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: conjg_test
+subroutine conjg_test(z1, z2)
+  complex :: z1, z2
+  ! CHECK: fir.extract_value
+  ! CHECK: negf
+  ! CHECK: fir.insert_value
+  z2 = conjg(z1)
+end subroutine

diff  --git a/flang/test/Lower/Intrinsics/dble.f90 b/flang/test/Lower/Intrinsics/dble.f90
new file mode 100644
index 0000000000000..3a896443f5c12
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/dble.f90
@@ -0,0 +1,8 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: dble_test
+subroutine dble_test(a)
+  real :: a
+  ! CHECK: fir.convert {{.*}} : (f32) -> f64
+  print *, dble(a)
+end subroutine

diff  --git a/flang/test/Lower/Intrinsics/dprod.f90 b/flang/test/Lower/Intrinsics/dprod.f90
new file mode 100644
index 0000000000000..4a4220c63b581
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/dprod.f90
@@ -0,0 +1,14 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: dprod_test
+subroutine dprod_test (x, y, z)
+  real :: x,y
+  double precision :: z
+  z = dprod(x,y)
+  ! CHECK-DAG: %[[x:.*]] = fir.load %arg0
+  ! CHECK-DAG: %[[y:.*]] = fir.load %arg1
+  ! CHECK-DAG: %[[a:.*]] = fir.convert %[[x]] : (f32) -> f64
+  ! CHECK-DAG: %[[b:.*]] = fir.convert %[[y]] : (f32) -> f64
+  ! CHECK: %[[res:.*]] = arith.mulf %[[a]], %[[b]]
+  ! CHECK: fir.store %[[res]] to %arg2
+end subroutine

diff  --git a/flang/test/Lower/Intrinsics/sign.f90 b/flang/test/Lower/Intrinsics/sign.f90
new file mode 100644
index 0000000000000..fe24a23e867c6
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/sign.f90
@@ -0,0 +1,29 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+! CHECK-LABEL: sign_testi
+subroutine sign_testi(a, b, c)
+  integer a, b, c
+  ! CHECK: %[[VAL_1:.*]] = arith.shrsi %{{.*}}, %{{.*}} : i32
+  ! CHECK: %[[VAL_2:.*]] = arith.xori %{{.*}}, %[[VAL_1]] : i32
+  ! CHECK: %[[VAL_3:.*]] = arith.subi %[[VAL_2]], %[[VAL_1]] : i32
+  ! CHECK-DAG: %[[VAL_4:.*]] = arith.subi %{{.*}}, %[[VAL_3]] : i32
+  ! CHECK-DAG: %[[VAL_5:.*]] = arith.cmpi slt, %{{.*}}, %{{.*}} : i32
+  ! CHECK: select %[[VAL_5]], %[[VAL_4]], %[[VAL_3]] : i32
+  c = sign(a, b)
+end subroutine
+
+! CHECK-LABEL: sign_testr
+subroutine sign_testr(a, b, c)
+  real a, b, c
+  ! CHECK-NOT: fir.call @{{.*}}fabs
+  ! CHECK: fir.call @{{.*}}copysign{{.*}} : (f32, f32) -> f32
+  c = sign(a, b)
+end subroutine
+
+! CHECK-LABEL: sign_testr2
+subroutine sign_testr2(a, b, c)
+  real(KIND=16) a, b, c
+  ! CHECK-NOT: fir.call @{{.*}}fabs
+  ! CHECK: fir.call @{{.*}}copysign{{.*}} : (f128, f128) -> f128
+  c = sign(a, b)
+end subroutine


        


More information about the flang-commits mailing list