[flang-commits] [flang] 396ead9 - [flang] Use proper attributes for runtime calls with 'i1' arguments/returns.

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Fri Nov 18 12:53:15 PST 2022


Author: Slava Zakharin
Date: 2022-11-18T12:52:57-08:00
New Revision: 396ead93e3cead59727947afdea1fc2b49f0fc34

URL: https://github.com/llvm/llvm-project/commit/396ead93e3cead59727947afdea1fc2b49f0fc34
DIFF: https://github.com/llvm/llvm-project/commit/396ead93e3cead59727947afdea1fc2b49f0fc34.diff

LOG: [flang] Use proper attributes for runtime calls with 'i1' arguments/returns.

Clang uses signext/zeroext attributes for integer arguments shorter than
the default 'int' type on a target. So Flang has to match this for functions
from Fortran runtime and also for BIND(C) routines. This patch implements
ABI adjustments only for Fortran runtime calls. BIND(C) part will be done
separately.

This resolves https://github.com/llvm/llvm-project/issues/58579

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

Added: 
    flang/test/Fir/target-rewrite-integer.fir

Modified: 
    flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
    flang/include/flang/Optimizer/Dialect/FIRDialect.h
    flang/lib/Lower/IO.cpp
    flang/lib/Lower/IntrinsicCall.cpp
    flang/lib/Optimizer/CodeGen/Target.cpp
    flang/lib/Optimizer/CodeGen/Target.h
    flang/lib/Optimizer/CodeGen/TargetRewrite.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 3a21479a1cfe2..30504555bfca7 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -20,6 +20,7 @@
 #include "flang/Common/Fortran.h"
 #include "flang/Common/uint128.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/MLIRContext.h"
@@ -411,7 +412,7 @@ static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
     return func;
   auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
   func = builder.createFunction(loc, name, funTy);
-  func->setAttr("fir.runtime", builder.getUnitAttr());
+  func->setAttr(FIROpsDialect::getFirRuntimeAttrName(), builder.getUnitAttr());
   return func;
 }
 

diff  --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.h b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
index 5a69e3fa23a8f..c639e7b53eac4 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
@@ -37,6 +37,11 @@ class FIROpsDialect final : public mlir::Dialect {
   void printAttribute(mlir::Attribute attr,
                       mlir::DialectAsmPrinter &p) const override;
 
+  /// Return string name of fir.runtime attribute.
+  static constexpr llvm::StringRef getFirRuntimeAttrName() {
+    return "fir.runtime";
+  }
+
 private:
   // Register the Attributes of this dialect.
   void registerAttributes();

diff  --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 4b08b06e013d3..2664c8100709b 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -27,6 +27,7 @@
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
 #include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Support/FIRContext.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Runtime/io-api.h"
@@ -167,7 +168,8 @@ static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
     return func;
   auto funTy = getTypeModel<E>()(builder.getContext());
   func = builder.createFunction(loc, name, funTy);
-  func->setAttr("fir.runtime", builder.getUnitAttr());
+  func->setAttr(fir::FIROpsDialect::getFirRuntimeAttrName(),
+                builder.getUnitAttr());
   func->setAttr("fir.io", builder.getUnitAttr());
   return func;
 }

diff  --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index abd31558aa05d..87f144dadbdbb 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -32,6 +32,7 @@
 #include "flang/Optimizer/Builder/Runtime/Stop.h"
 #include "flang/Optimizer/Builder/Runtime/Transformational.h"
 #include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
 #include "flang/Optimizer/Support/FatalError.h"
 #include "flang/Runtime/entry-names.h"
@@ -1684,7 +1685,8 @@ static mlir::func::FuncOp getFuncOp(mlir::Location loc,
                                     const RuntimeFunction &runtime) {
   mlir::func::FuncOp function = builder.addNamedFunction(
       loc, runtime.symbol, runtime.typeGenerator(builder.getContext()));
-  function->setAttr("fir.runtime", builder.getUnitAttr());
+  function->setAttr(fir::FIROpsDialect::getFirRuntimeAttrName(),
+                    builder.getUnitAttr());
   return function;
 }
 

diff  --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 17cf3caf8e557..6ec6dde062644 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -22,6 +22,19 @@
 
 using namespace fir;
 
+namespace fir::details {
+llvm::StringRef Attributes::getIntExtensionAttrName() const {
+  // The attribute names are available via LLVM dialect interfaces
+  // like getZExtAttrName(), getByValAttrName(), etc., so we'd better
+  // use them than literals.
+  if (isZeroExt())
+    return "llvm.zeroext";
+  else if (isSignExt())
+    return "llvm.signext";
+  return {};
+}
+} // namespace fir::details
+
 // Reduce a REAL/float type to the floating point semantics.
 static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap,
                                                   mlir::Type type) {
@@ -67,6 +80,46 @@ struct GenericTarget : public CodeGenSpecifics {
                                    /*sret=*/sret, /*append=*/!sret});
     return marshal;
   }
+
+  CodeGenSpecifics::Marshalling
+  integerArgumentType(mlir::Location loc,
+                      mlir::IntegerType argTy) const override {
+    CodeGenSpecifics::Marshalling marshal;
+    AT::IntegerExtension intExt = AT::IntegerExtension::None;
+    if (argTy.getWidth() < getCIntTypeWidth()) {
+      // isSigned() and isUnsigned() branches below are dead code currently.
+      // If needed, we can generate calls with signed/unsigned argument types
+      // to more precisely match C side (e.g. for Fortran runtime functions
+      // with 'unsigned short' arguments).
+      if (argTy.isSigned())
+        intExt = AT::IntegerExtension::Sign;
+      else if (argTy.isUnsigned())
+        intExt = AT::IntegerExtension::Zero;
+      else if (argTy.isSignless()) {
+        // Zero extend for 'i1' and sign extend for other types.
+        if (argTy.getWidth() == 1)
+          intExt = AT::IntegerExtension::Zero;
+        else
+          intExt = AT::IntegerExtension::Sign;
+      }
+    }
+
+    marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false,
+                                   /*sret=*/false, /*append=*/false,
+                                   /*intExt=*/intExt});
+    return marshal;
+  }
+
+  CodeGenSpecifics::Marshalling
+  integerReturnType(mlir::Location loc,
+                    mlir::IntegerType argTy) const override {
+    return integerArgumentType(loc, argTy);
+  }
+
+  // Width of 'int' type is 32-bits for almost all targets, except
+  // for AVR and MSP430 (see TargetInfo initializations
+  // in clang/lib/Basic/Targets).
+  unsigned char getCIntTypeWidth() const override { return 32; }
 };
 } // namespace
 

diff  --git a/flang/lib/Optimizer/CodeGen/Target.h b/flang/lib/Optimizer/CodeGen/Target.h
index 7f6d8d96d23bc..be6ae6cd75f83 100644
--- a/flang/lib/Optimizer/CodeGen/Target.h
+++ b/flang/lib/Optimizer/CodeGen/Target.h
@@ -29,21 +29,29 @@ namespace details {
 /// LLVMContext.
 class Attributes {
 public:
+  enum class IntegerExtension { None, Zero, Sign };
+
   Attributes(unsigned short alignment = 0, bool byval = false,
-             bool sret = false, bool append = false)
-      : alignment{alignment}, byval{byval}, sret{sret}, append{append} {}
+             bool sret = false, bool append = false,
+             IntegerExtension intExt = IntegerExtension::None)
+      : alignment{alignment}, byval{byval}, sret{sret}, append{append},
+        intExt{intExt} {}
 
   unsigned getAlignment() const { return alignment; }
   bool hasAlignment() const { return alignment != 0; }
   bool isByVal() const { return byval; }
   bool isSRet() const { return sret; }
   bool isAppend() const { return append; }
+  bool isZeroExt() const { return intExt == IntegerExtension::Zero; }
+  bool isSignExt() const { return intExt == IntegerExtension::Sign; }
+  llvm::StringRef getIntExtensionAttrName() const;
 
 private:
   unsigned short alignment{};
   bool byval : 1;
   bool sret : 1;
   bool append : 1;
+  IntegerExtension intExt;
 };
 
 } // namespace details
@@ -94,6 +102,47 @@ class CodeGenSpecifics {
   virtual Marshalling boxcharArgumentType(mlir::Type eleTy,
                                           bool sret = false) const = 0;
 
+  // Compute ABI rules for an integer argument of the given mlir::IntegerType
+  // \p argTy. Note that this methods is supposed to be called for
+  // arguments passed by value not via reference, e.g. the 'i1' argument here:
+  //   declare i1 @_FortranAioOutputLogical(ptr, i1)
+  //
+  // \p loc is the location of the operation using/specifying the argument.
+  //
+  // Currently, the only supported marshalling is whether the argument
+  // should be zero or sign extended.
+  //
+  // The zero/sign extension is especially important to comply with the ABI
+  // used by C/C++ compiler that builds Fortran runtime. As in the above
+  // example the callee will expect the caller to zero extend the second
+  // argument up to the size of the C/C++'s 'int' type.
+  // The corresponding handling in clang is done in
+  // DefaultABIInfo::classifyArgumentType(), and the logic may brielfy
+  // be explained as some sort of extension is required if the integer
+  // type is shorter than the size of 'int' for the target.
+  // The related code is located in ASTContext::isPromotableIntegerType()
+  // and ABIInfo::isPromotableIntegerTypeForABI().
+  // In particular, the latter returns 'true' for 'bool', several kinds
+  // of 'char', 'short', 'wchar' and enumerated types.
+  // The type of the extensions (zero or sign) depends on the signedness
+  // of the original language type.
+  //
+  // It is not clear how to handle signless integer types.
+  // From the point of Fortran-C interface all supported integer types
+  // seem to be signed except for CFI_type_Bool/bool that is supported
+  // via signless 'i1', but that is treated as unsigned type by clang
+  // (e.g. 'bool' arguments are using 'zeroext' ABI).
+  virtual Marshalling integerArgumentType(mlir::Location loc,
+                                          mlir::IntegerType argTy) const = 0;
+
+  // By default, integer argument and return values use the same
+  // zero/sign extension rules.
+  virtual Marshalling integerReturnType(mlir::Location loc,
+                                        mlir::IntegerType argTy) const = 0;
+
+  // Returns width in bits of C/C++ 'int' type size.
+  virtual unsigned char getCIntTypeWidth() const = 0;
+
 protected:
   mlir::MLIRContext &context;
   llvm::Triple triple;

diff  --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index 9bf51cc6ee1a4..06846ccb3d02a 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -100,14 +100,14 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
     // Convert ops in target-specific patterns.
     mod.walk([&](mlir::Operation *op) {
       if (auto call = mlir::dyn_cast<fir::CallOp>(op)) {
-        if (!hasPortableSignature(call.getFunctionType()))
+        if (!hasPortableSignature(call.getFunctionType(), op))
           convertCallOp(call);
       } else if (auto dispatch = mlir::dyn_cast<fir::DispatchOp>(op)) {
-        if (!hasPortableSignature(dispatch.getFunctionType()))
+        if (!hasPortableSignature(dispatch.getFunctionType(), op))
           convertCallOp(dispatch);
       } else if (auto addr = mlir::dyn_cast<fir::AddrOfOp>(op)) {
         if (addr.getType().isa<mlir::FunctionType>() &&
-            !hasPortableSignature(addr.getType()))
+            !hasPortableSignature(addr.getType(), op))
           convertAddrOp(addr);
       }
     });
@@ -443,19 +443,23 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
   /// then it is considered portable for any target, and this function will
   /// return `true`. Otherwise, the signature is not portable and `false` is
   /// returned.
-  bool hasPortableSignature(mlir::Type signature) {
+  bool hasPortableSignature(mlir::Type signature, mlir::Operation *op) {
     assert(signature.isa<mlir::FunctionType>());
     auto func = signature.dyn_cast<mlir::FunctionType>();
+    bool hasFirRuntime = op->hasAttrOfType<mlir::UnitAttr>(
+        fir::FIROpsDialect::getFirRuntimeAttrName());
     for (auto ty : func.getResults())
       if ((ty.isa<fir::BoxCharType>() && !noCharacterConversion) ||
-          (fir::isa_complex(ty) && !noComplexConversion)) {
+          (fir::isa_complex(ty) && !noComplexConversion) ||
+          (ty.isa<mlir::IntegerType>() && hasFirRuntime)) {
         LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n");
         return false;
       }
     for (auto ty : func.getInputs())
       if (((ty.isa<fir::BoxCharType>() || fir::isCharacterProcedureTuple(ty)) &&
            !noCharacterConversion) ||
-          (fir::isa_complex(ty) && !noComplexConversion)) {
+          (fir::isa_complex(ty) && !noComplexConversion) ||
+          (ty.isa<mlir::IntegerType>() && hasFirRuntime)) {
         LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n");
         return false;
       }
@@ -476,13 +480,14 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
   /// the immediately subsequent target code gen.
   void convertSignature(mlir::func::FuncOp func) {
     auto funcTy = func.getFunctionType().cast<mlir::FunctionType>();
-    if (hasPortableSignature(funcTy) && !hasHostAssociations(func))
+    if (hasPortableSignature(funcTy, func) && !hasHostAssociations(func))
       return;
     llvm::SmallVector<mlir::Type> newResTys;
     llvm::SmallVector<mlir::Type> newInTys;
     llvm::SmallVector<std::pair<unsigned, mlir::NamedAttribute>> savedAttrs;
     llvm::SmallVector<std::pair<unsigned, mlir::NamedAttribute>> extraAttrs;
     llvm::SmallVector<FixupTy> fixups;
+    llvm::SmallVector<std::pair<unsigned, mlir::NamedAttrList>, 1> resultAttrs;
 
     // Save argument attributes in case there is a shift so we can replace them
     // correctly.
@@ -509,6 +514,22 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
             else
               doComplexReturn(func, cmplx, newResTys, newInTys, fixups);
           })
+          .Case<mlir::IntegerType>([&](mlir::IntegerType intTy) {
+            auto m = specifics->integerArgumentType(func.getLoc(), intTy);
+            assert(m.size() == 1);
+            auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]);
+            auto retTy = std::get<mlir::Type>(m[0]);
+            std::size_t resId = newResTys.size();
+            llvm::StringRef extensionAttrName = attr.getIntExtensionAttrName();
+            if (!extensionAttrName.empty() &&
+                // TODO: we have to do the same for BIND(C) routines.
+                func->hasAttrOfType<mlir::UnitAttr>(
+                    fir::FIROpsDialect::getFirRuntimeAttrName()))
+              resultAttrs.emplace_back(
+                  resId, rewriter->getNamedAttr(extensionAttrName,
+                                                rewriter->getUnitAttr()));
+            newResTys.push_back(retTy);
+          })
           .Default([&](mlir::Type ty) { newResTys.push_back(ty); });
 
     // Saved potential shift in argument. Handling of result can add arguments
@@ -572,6 +593,26 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
               newInTys.push_back(ty);
             }
           })
+          .Case<mlir::IntegerType>([&](mlir::IntegerType intTy) {
+            auto m = specifics->integerArgumentType(func.getLoc(), intTy);
+            assert(m.size() == 1);
+            auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]);
+            auto argTy = std::get<mlir::Type>(m[0]);
+            auto argNo = newInTys.size();
+            llvm::StringRef extensionAttrName = attr.getIntExtensionAttrName();
+            if (!extensionAttrName.empty() &&
+                // TODO: we have to do the same for BIND(C) routines.
+                func->hasAttrOfType<mlir::UnitAttr>(
+                    fir::FIROpsDialect::getFirRuntimeAttrName())) {
+              fixups.emplace_back(FixupTy::Codes::ArgumentType, argNo,
+                                  [=](mlir::func::FuncOp func) {
+                                    func.setArgAttr(
+                                        argNo, extensionAttrName,
+                                        mlir::UnitAttr::get(func.getContext()));
+                                  });
+            }
+            newInTys.push_back(argTy);
+          })
           .Default([&](mlir::Type ty) { newInTys.push_back(ty); });
 
       if (func.getArgAttrOfType<mlir::UnitAttr>(index,
@@ -608,14 +649,18 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
         case FixupTy::Codes::ArgumentType: {
           // Argument is pass-by-value, but its type has likely been modified to
           // suit the target ABI convention.
+          auto oldArgTy =
+              fir::ReferenceType::get(oldArgTys[fixup.index - offset]);
+          // If type did not change, keep the original argument.
+          if (newInTys[fixup.index] == oldArgTy)
+            break;
+
           auto newArg = func.front().insertArgument(fixup.index,
                                                     newInTys[fixup.index], loc);
           rewriter->setInsertionPointToStart(&func.front());
           auto mem =
               rewriter->create<fir::AllocaOp>(loc, newInTys[fixup.index]);
           rewriter->create<fir::StoreOp>(loc, newArg, mem);
-          auto oldArgTy =
-              fir::ReferenceType::get(oldArgTys[fixup.index - offset]);
           auto cast = rewriter->create<fir::ConvertOp>(loc, oldArgTy, mem);
           mlir::Value load = rewriter->create<fir::LoadOp>(loc, cast);
           func.getArgument(fixup.index + 1).replaceAllUsesWith(load);
@@ -744,6 +789,10 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
       func.setArgAttr(extraAttr.first, extraAttr.second.getName(),
                       extraAttr.second.getValue());
 
+    for (auto [resId, resAttrList] : resultAttrs)
+      for (mlir::NamedAttribute resAttr : resAttrList)
+        func.setResultAttr(resId, resAttr.getName(), resAttr.getValue());
+
     // Replace attributes to the correct argument if there was an argument shift
     // to the right.
     if (argumentShift > 0) {

diff  --git a/flang/test/Fir/target-rewrite-integer.fir b/flang/test/Fir/target-rewrite-integer.fir
new file mode 100644
index 0000000000000..b7426acf06238
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-integer.fir
@@ -0,0 +1,77 @@
+// RUN: fir-opt --split-input-file --target-rewrite="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=I32,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=X64,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=AARCH64,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=powerpc64le-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=PPC,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=sparc64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
+// RUN: fir-opt --split-input-file --target-rewrite="target=sparcv9-sun-solaris2.11" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
+
+// -----
+
+// subroutine test_i1(x)
+//   logical x
+//   print *, x
+// end subroutine test_i1
+
+// ALL-LABEL: @_QPtest_i1
+// I32: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+// X64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+// AARCH64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+// PPC: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+// SPARCV9: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
+func.func @_QPtest_i1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
+  %c3_i32 = arith.constant 3 : i32
+  %c-1_i32 = arith.constant -1 : i32
+  %0 = fir.address_of(@_QQcl.2E2F746573742E66393000) : !fir.ref<!fir.char<1,11>>
+  %1 = fir.convert %0 : (!fir.ref<!fir.char<1,11>>) -> !fir.ref<i8>
+  %2 = fir.call @_FortranAioBeginExternalListOutput(%c-1_i32, %1, %c3_i32) : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
+  %3 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
+  %4 = fir.convert %3 : (!fir.logical<4>) -> i1
+  %5 = fir.call @_FortranAioOutputLogical(%2, %4) : (!fir.ref<i8>, i1) -> i1
+  %6 = fir.call @_FortranAioEndIoStatement(%2) : (!fir.ref<i8>) -> i32
+  return
+}
+func.func private @_FortranAioBeginExternalListOutput(i32, !fir.ref<i8>, i32) -> !fir.ref<i8> attributes {fir.io, fir.runtime}
+fir.global linkonce @_QQcl.2E2F746573742E66393000 constant : !fir.char<1,11> {
+  %0 = fir.string_lit "./test.f90\00"(11) : !fir.char<1,11>
+  fir.has_value %0 : !fir.char<1,11>
+}
+func.func private @_FortranAioOutputLogical(!fir.ref<i8>, i1) -> i1 attributes {fir.io, fir.runtime}
+func.func private @_FortranAioEndIoStatement(!fir.ref<i8>) -> i32 attributes {fir.io, fir.runtime}
+
+// -----
+
+// Manually created test with 'si1' argument/return type.
+// Flang does not use 'si1' type currently.
+
+// ALL-LABEL: @_QPtest_si1
+// I32: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+// X64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+// AARCH64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+// PPC: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+// SPARCV9: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
+func.func @_QPtest_si1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
+  %0 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
+  %1 = fir.convert %0 : (!fir.logical<4>) -> si1
+  %2 = fir.call @_SomeFunc_si1(%1) : (si1) -> si1
+  return
+}
+func.func private @_SomeFunc_si1(si1) -> si1 attributes {fir.runtime}
+
+// -----
+
+// Manually created test with 'ui1' argument/return type.
+// Flang does not use 'ui1' type currently.
+
+// ALL-LABEL: @_QPtest_ui1
+// I32: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+// X64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+// AARCH64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+// PPC: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+// SPARCV9: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
+func.func @_QPtest_ui1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"}) {
+  %0 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
+  %1 = fir.convert %0 : (!fir.logical<4>) -> ui1
+  %2 = fir.call @_SomeFunc_ui1(%1) : (ui1) -> ui1
+  return
+}
+func.func private @_SomeFunc_ui1(ui1) -> ui1 attributes {fir.runtime}


        


More information about the flang-commits mailing list