[flang-commits] [flang] [flang][MIPS] Add N32 and N64 target ABI support (PR #224920)

Jiaxun Yang via flang-commits flang-commits at lists.llvm.org
Sun Sep 20 05:09:42 PDT 2026


https://github.com/FlyGoat created https://github.com/llvm/llvm-project/pull/224920

Add code generation specifics for both MIPS64 endiannesses. Default an empty target ABI from the triple before constructing the target, then use the initialized ABI to select the character length width. Preserve explicit ABI values and sign-extend 32-bit integers, including unsigned integers.

Lower complex arguments and results according to the MIPS ABI. Pass preceding argument information through target rewriting so complex arguments use integer registers or the stack when fewer than two argument-register slots remain.

Fixes #126014

>From e7930313f0bcdde6d07cc1615c2b1a2dc569dd2d Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Sun, 20 Sep 2026 12:19:30 +0100
Subject: [PATCH] [flang][MIPS] Add N32 and N64 target ABI support

Add code generation specifics for both MIPS64 endiannesses. Default an
empty target ABI from the triple before constructing the target, then
use the initialized ABI to select the character length width. Preserve
explicit ABI values and sign-extend 32-bit integers, including unsigned
integers.

Lower complex arguments and results according to the MIPS ABI. Pass
preceding argument information through target rewriting so complex
arguments use integer registers or the stack when fewer than two
argument-register slots remain.

Fixes #126014
---
 .../include/flang/Optimizer/CodeGen/Target.h  |   8 ++
 flang/lib/Optimizer/CodeGen/Target.cpp        |  94 +++++++++++++++-
 flang/lib/Optimizer/CodeGen/TargetRewrite.cpp |  11 +-
 flang/test/Fir/target-rewrite-boxchar.fir     |   6 +
 flang/test/Fir/target-rewrite-mips.fir        | 104 ++++++++++++++++++
 flang/test/Integration/mips-abi.f90           |  39 +++++++
 6 files changed, 255 insertions(+), 7 deletions(-)
 create mode 100644 flang/test/Fir/target-rewrite-mips.fir
 create mode 100644 flang/test/Integration/mips-abi.f90

diff --git a/flang/include/flang/Optimizer/CodeGen/Target.h b/flang/include/flang/Optimizer/CodeGen/Target.h
index 10eb786776a2f..9917dcf6ced07 100644
--- a/flang/include/flang/Optimizer/CodeGen/Target.h
+++ b/flang/include/flang/Optimizer/CodeGen/Target.h
@@ -123,6 +123,14 @@ class CodeGenSpecifics {
   virtual Marshalling complexArgumentType(mlir::Location loc,
                                           mlir::Type eleTy) const = 0;
 
+  /// Account for preceding arguments when the ABI depends on the available
+  /// argument registers.
+  virtual Marshalling
+  complexArgumentType(mlir::Location loc, mlir::Type eleTy,
+                      const Marshalling &previousArguments) const {
+    return complexArgumentType(loc, eleTy);
+  }
+
   /// Type representation of a `complex<eleTy>` type return value. Such a return
   /// value may need to be converted to a hidden reference argument.
   virtual Marshalling complexReturnType(mlir::Location loc,
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 3e6a2151fb311..a36a55653c32d 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -71,7 +71,8 @@ struct GenericTarget : public CodeGenSpecifics {
   }
 
   mlir::Type boxcharMemoryType(mlir::Type eleTy) const override {
-    auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
+    auto idxTy = mlir::IntegerType::get(
+        eleTy.getContext(), static_cast<const S *>(this)->defaultWidth);
     auto ptrTy = fir::ReferenceType::get(eleTy);
     // Use a type that will be translated into LLVM as:
     // { t*, index }
@@ -81,7 +82,8 @@ struct GenericTarget : public CodeGenSpecifics {
 
   Marshalling boxcharArgumentType(mlir::Type eleTy) const override {
     CodeGenSpecifics::Marshalling marshal;
-    auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
+    auto idxTy = mlir::IntegerType::get(
+        eleTy.getContext(), static_cast<const S *>(this)->defaultWidth);
     auto ptrTy = fir::ReferenceType::get(eleTy);
     marshal.emplace_back(ptrTy, AT{});
     // Characters are passed in a split format with all pointers first (in the
@@ -1409,6 +1411,87 @@ struct TargetSparcV9 : public GenericTarget<TargetSparcV9> {
 };
 } // namespace
 
+//===----------------------------------------------------------------------===//
+// MIPS N32 and N64 target specifics.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct TargetMips64 : public GenericTarget<TargetMips64> {
+  using GenericTarget::GenericTarget;
+
+  const int defaultWidth = targetABI == "n32" ? 32 : 64;
+
+  CodeGenSpecifics::Marshalling
+  complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
+    return complexArgumentType(loc, eleTy, {});
+  }
+
+  CodeGenSpecifics::Marshalling
+  complexArgumentType(mlir::Location loc, mlir::Type eleTy,
+                      const Marshalling &previousArguments) const override {
+    const auto *sem = &floatToSemantics(kindMap, eleTy);
+    if (sem != &llvm::APFloat::IEEEsingle() &&
+        sem != &llvm::APFloat::IEEEdouble())
+      typeTodo(sem, loc, "argument");
+
+    // N32/N64 share eight argument slots between integer and floating-point
+    // registers. A complex argument uses two FPRs when both parts fit.
+    // Otherwise, pass its memory representation in GPRs or on the stack,
+    // packing COMPLEX(4) into one slot.
+    uint64_t slots = 0;
+    for (auto [ty, attr] : previousArguments) {
+      if (attr.isAppend())
+        continue;
+      if (fir::conformsWithPassByRef(ty)) {
+        if (++slots >= 7)
+          break;
+        continue;
+      }
+      auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash(
+          loc, ty, getDataLayout(), kindMap);
+      slots = llvm::alignTo(slots, align > 8 ? 2 : 1);
+      slots += llvm::divideCeil(size, uint64_t{8});
+      if (slots >= 7)
+        break;
+    }
+
+    if (slots < 7)
+      return {{eleTy, AT{}}, {eleTy, AT{}}};
+
+    auto i64Ty = mlir::IntegerType::get(eleTy.getContext(), 64);
+    if (sem == &llvm::APFloat::IEEEsingle())
+      return {{i64Ty, AT{}}};
+    return {{mlir::TupleType::get(eleTy.getContext(), {i64Ty, i64Ty}), AT{}}};
+  }
+
+  CodeGenSpecifics::Marshalling
+  complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
+    const auto *sem = &floatToSemantics(kindMap, eleTy);
+    auto structTy =
+        mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy});
+    if (sem == &llvm::APFloat::IEEEsingle() ||
+        sem == &llvm::APFloat::IEEEdouble())
+      return {{structTy, AT{}}};
+    if (sem == &llvm::APFloat::IEEEquad())
+      return {{fir::ReferenceType::get(structTy),
+               AT{/*alignment=*/16, /*byval=*/false, /*sret=*/true}}};
+    typeTodo(sem, loc, "return");
+    return {};
+  }
+
+  CodeGenSpecifics::Marshalling
+  integerArgumentType(mlir::Location loc,
+                      mlir::IntegerType argTy) const override {
+    // N32/N64 sign-extend all 32-bit integers, including unsigned values.
+    // Smaller integers follow the usual extension rules.
+    if (argTy.getWidth() == 32)
+      return {{argTy, AT{/*alignment=*/0, /*byval=*/false, /*sret=*/false,
+                         /*append=*/false, AT::IntegerExtension::Sign}}};
+    return GenericTarget::integerArgumentType(loc, argTy);
+  }
+};
+} // namespace
+
 //===----------------------------------------------------------------------===//
 // RISCV64 linux target specifics.
 //===----------------------------------------------------------------------===//
@@ -2086,6 +2169,13 @@ std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get(
     return std::make_unique<TargetRISCV64>(ctx, std::move(trp),
                                            std::move(kindMap), targetCPU,
                                            targetFeatures, targetABI, dl);
+  case llvm::Triple::ArchType::mips64:
+  case llvm::Triple::ArchType::mips64el:
+    if (targetABI.empty())
+      targetABI = trp.isABIN32() ? "n32" : "n64";
+    return std::make_unique<TargetMips64>(ctx, std::move(trp),
+                                          std::move(kindMap), targetCPU,
+                                          targetFeatures, targetABI, dl);
   case llvm::Triple::ArchType::amdgpu:
     return std::make_unique<TargetAMDGPU>(ctx, std::move(trp),
                                           std::move(kindMap), targetCPU,
diff --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index f8eb8087a9b90..85b890e12bf96 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -352,7 +352,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
       newOpers.push_back(oper);
       return;
     }
-    auto m = specifics->complexArgumentType(loc, ty.getElementType());
+    auto m = specifics->complexArgumentType(loc, ty.getElementType(),
+                                            newInTyAndAttrs);
     rewriteCallOperands(loc, m, ty, oper, newOpers, savedStackPtr,
                         newInTyAndAttrs);
   }
@@ -670,8 +671,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
     if (noComplexConversion) {
       newInTyAndAttrs.push_back(fir::CodeGenSpecifics::getTypeAndAttr(cmplx));
     } else {
-      auto cplxArgs =
-          specifics->complexArgumentType(loc, cmplx.getElementType());
+      auto cplxArgs = specifics->complexArgumentType(
+          loc, cmplx.getElementType(), newInTyAndAttrs);
       newInTyAndAttrs.insert(newInTyAndAttrs.end(), cplxArgs.begin(),
                              cplxArgs.end());
     }
@@ -1359,8 +1360,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
       newInTyAndAttrs.push_back(fir::CodeGenSpecifics::getTypeAndAttr(cmplx));
       return;
     }
-    auto cplxArgs =
-        specifics->complexArgumentType(func.getLoc(), cmplx.getElementType());
+    auto cplxArgs = specifics->complexArgumentType(
+        func.getLoc(), cmplx.getElementType(), newInTyAndAttrs);
     createFuncOpArgFixups(func, newInTyAndAttrs, cplxArgs, fixups);
   }
 
diff --git a/flang/test/Fir/target-rewrite-boxchar.fir b/flang/test/Fir/target-rewrite-boxchar.fir
index 228ee7a367b71..a94c41212acd1 100644
--- a/flang/test/Fir/target-rewrite-boxchar.fir
+++ b/flang/test/Fir/target-rewrite-boxchar.fir
@@ -6,6 +6,12 @@
 // RUN: fir-opt --target-rewrite="target=nvptx64-nvidia-cuda" %s | FileCheck %s --check-prefix=INT64
 // RUN: fir-opt --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=INT64
 // RUN: fir-opt --target-rewrite="target=s390x-unknown-linux-gnu" %s | FileCheck %s --check-prefix=INT64
+// RUN: fir-opt --target-rewrite="target=mips64-unknown-linux-gnuabi64" %s | FileCheck %s --check-prefix=INT64
+// RUN: fir-opt --target-rewrite="target=mips64el-unknown-linux-gnuabi64" %s | FileCheck %s --check-prefix=INT64
+// RUN: fir-opt --target-rewrite="target=mips64-unknown-linux-gnuabin32" %s | FileCheck %s --check-prefix=INT32
+// RUN: fir-opt --target-rewrite="target=mips64el-unknown-linux-gnuabin32" %s | FileCheck %s --check-prefix=INT32
+// RUN: fir-opt --target-rewrite="target=mips64-unknown-linux-gnuabi64 target-abi=n32" %s | FileCheck %s --check-prefix=INT32
+// RUN: fir-opt --target-rewrite="target=mips64el-unknown-linux-gnuabin32 target-abi=n64" %s | FileCheck %s --check-prefix=INT64
 
 // Test that we rewrite the signatures and bodies of functions that take boxchar
 // parameters.
diff --git a/flang/test/Fir/target-rewrite-mips.fir b/flang/test/Fir/target-rewrite-mips.fir
new file mode 100644
index 0000000000000..208cd43d05596
--- /dev/null
+++ b/flang/test/Fir/target-rewrite-mips.fir
@@ -0,0 +1,104 @@
+// RUN: fir-opt --target-rewrite="target=mips64-unknown-linux-gnuabi64" %s | FileCheck %s
+// RUN: fir-opt --target-rewrite="target=mips64el-unknown-linux-gnuabi64" %s | FileCheck %s
+// RUN: fir-opt --target-rewrite="target=mips64-unknown-linux-gnuabin32" %s | FileCheck %s
+// RUN: fir-opt --target-rewrite="target=mips64el-unknown-linux-gnuabin32" %s | FileCheck %s
+
+// Single and double precision complex results use two floating-point registers.
+// CHECK-LABEL: func.func @return4() -> tuple<f32, f32>
+func.func @return4() -> complex<f32> {
+  %z = fir.undefined complex<f32>
+  return %z : complex<f32>
+}
+// CHECK-LABEL: func.func @return8() -> tuple<f64, f64>
+func.func @return8() -> complex<f64> {
+  %z = fir.undefined complex<f64>
+  return %z : complex<f64>
+}
+// Quad precision results use a hidden pointer.
+// CHECK-LABEL: func.func @return16(
+// CHECK-SAME: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.sret = tuple<f128, f128>})
+func.func @return16() -> complex<f128> {
+  %z = fir.undefined complex<f128>
+  return %z : complex<f128>
+}
+
+// 32-bit integers, including unsigned integers, must be sign extended.
+// CHECK: func.func private @integers(i1 {llvm.zeroext}, i8 {llvm.signext}, ui8 {llvm.zeroext}, i16 {llvm.signext}, ui16 {llvm.zeroext}, i32 {llvm.signext}, ui32 {llvm.signext}, i64) -> (i32 {llvm.signext})
+func.func private @integers(i1, i8, ui8, i16, ui16, i32, ui32, i64) -> i32 attributes {fir.runtime}
+// CHECK: func.func private @unsigned_result() -> (ui32 {llvm.signext})
+func.func private @unsigned_result() -> ui32 attributes {fir.runtime}
+
+// CHECK-LABEL: func.func @complex32_after0({{%[^:]+}}: f32, {{%[^:]+}}: f32, {{%[^:]+}}: i64) -> tuple<f32, f32>
+func.func @complex32_after0(%a0: complex<f32>, %a1: i64) -> complex<f32> {
+  // CHECK: fir.call @complex32_after0({{.*}}) : (f32, f32, i64) -> tuple<f32, f32>
+  %r = fir.call @complex32_after0(%a0, %a1) : (complex<f32>, i64) -> complex<f32>
+  return %r : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex32_after6({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: f32, {{%[^:]+}}: f32, {{%[^:]+}}: i64) -> tuple<f32, f32>
+func.func @complex32_after6(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: complex<f32>, %a7: i64) -> complex<f32> {
+  // CHECK: fir.call @complex32_after6({{.*}}) : (i64, i64, i64, i64, i64, i64, f32, f32, i64) -> tuple<f32, f32>
+  %r = fir.call @complex32_after6(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7) : (i64, i64, i64, i64, i64, i64, complex<f32>, i64) -> complex<f32>
+  return %r : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex32_after7({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64) -> tuple<f32, f32>
+func.func @complex32_after7(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: i64, %a7: complex<f32>, %a8: i64) -> complex<f32> {
+  // CHECK: fir.call @complex32_after7({{.*}}) : (i64, i64, i64, i64, i64, i64, i64, i64, i64) -> tuple<f32, f32>
+  %r = fir.call @complex32_after7(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8) : (i64, i64, i64, i64, i64, i64, i64, complex<f32>, i64) -> complex<f32>
+  return %r : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex32_after8({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64) -> tuple<f32, f32>
+func.func @complex32_after8(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: i64, %a7: i64, %a8: complex<f32>, %a9: i64) -> complex<f32> {
+  // CHECK: fir.call @complex32_after8({{.*}}) : (i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) -> tuple<f32, f32>
+  %r = fir.call @complex32_after8(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9) : (i64, i64, i64, i64, i64, i64, i64, i64, complex<f32>, i64) -> complex<f32>
+  return %r : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex64_after0({{%[^:]+}}: f64, {{%[^:]+}}: f64, {{%[^:]+}}: i64) -> tuple<f64, f64>
+func.func @complex64_after0(%a0: complex<f64>, %a1: i64) -> complex<f64> {
+  // CHECK: fir.call @complex64_after0({{.*}}) : (f64, f64, i64) -> tuple<f64, f64>
+  %r = fir.call @complex64_after0(%a0, %a1) : (complex<f64>, i64) -> complex<f64>
+  return %r : complex<f64>
+}
+
+// CHECK-LABEL: func.func @complex64_after6({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: f64, {{%[^:]+}}: f64, {{%[^:]+}}: i64) -> tuple<f64, f64>
+func.func @complex64_after6(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: complex<f64>, %a7: i64) -> complex<f64> {
+  // CHECK: fir.call @complex64_after6({{.*}}) : (i64, i64, i64, i64, i64, i64, f64, f64, i64) -> tuple<f64, f64>
+  %r = fir.call @complex64_after6(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7) : (i64, i64, i64, i64, i64, i64, complex<f64>, i64) -> complex<f64>
+  return %r : complex<f64>
+}
+
+// CHECK-LABEL: func.func @complex64_after7({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: tuple<i64, i64>, {{%[^:]+}}: i64) -> tuple<f64, f64>
+func.func @complex64_after7(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: i64, %a7: complex<f64>, %a8: i64) -> complex<f64> {
+  // CHECK: fir.call @complex64_after7({{.*}}) : (i64, i64, i64, i64, i64, i64, i64, tuple<i64, i64>, i64) -> tuple<f64, f64>
+  %r = fir.call @complex64_after7(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8) : (i64, i64, i64, i64, i64, i64, i64, complex<f64>, i64) -> complex<f64>
+  return %r : complex<f64>
+}
+
+// CHECK-LABEL: func.func @complex64_after8({{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: i64, {{%[^:]+}}: tuple<i64, i64>, {{%[^:]+}}: i64) -> tuple<f64, f64>
+func.func @complex64_after8(%a0: i64, %a1: i64, %a2: i64, %a3: i64, %a4: i64, %a5: i64, %a6: i64, %a7: i64, %a8: complex<f64>, %a9: i64) -> complex<f64> {
+  // CHECK: fir.call @complex64_after8({{.*}}) : (i64, i64, i64, i64, i64, i64, i64, i64, tuple<i64, i64>, i64) -> tuple<f64, f64>
+  %r = fir.call @complex64_after8(%a0, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9) : (i64, i64, i64, i64, i64, i64, i64, i64, complex<f64>, i64) -> complex<f64>
+  return %r : complex<f64>
+}
+
+// Previously split complex arguments each consume two slots, even for f32.
+// CHECK: func.func private @five_complex(f32, f32, f32, f32, f32, f32, f32, f32, i64)
+func.func private @five_complex(complex<f32>, complex<f32>, complex<f32>, complex<f32>, complex<f32>)
+
+// Count the hidden result pointer as an argument slot.
+// CHECK-LABEL: func.func private @hidden_result(
+// CHECK-SAME: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.sret = tuple<f128, f128>}, i64, i64, i64, i64, i64, i64, i64)
+func.func private @hidden_result(i64, i64, i64, i64, i64, i64, complex<f32>) -> complex<f128>
+
+// Function addresses and indirect calls must use the same rewritten signature.
+// CHECK-LABEL: func.func @indirect(
+func.func @indirect(%a: i64, %z: complex<f32>) -> complex<f32> {
+  // CHECK: fir.address_of(@complex32_after7) : (i64, i64, i64, i64, i64, i64, i64, i64, i64) -> tuple<f32, f32>
+  %fn = fir.address_of(@complex32_after7) : (i64, i64, i64, i64, i64, i64, i64, complex<f32>, i64) -> complex<f32>
+  // CHECK: fir.call %{{.*}}({{.*}}) : (i64, i64, i64, i64, i64, i64, i64, i64, i64) -> tuple<f32, f32>
+  %r = fir.call %fn(%a, %a, %a, %a, %a, %a, %a, %z, %a) : (i64, i64, i64, i64, i64, i64, i64, complex<f32>, i64) -> complex<f32>
+  return %r : complex<f32>
+}
diff --git a/flang/test/Integration/mips-abi.f90 b/flang/test/Integration/mips-abi.f90
new file mode 100644
index 0000000000000..a7b7600dca218
--- /dev/null
+++ b/flang/test/Integration/mips-abi.f90
@@ -0,0 +1,39 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+! REQUIRES: mips-registered-target
+! REQUIRES: module-independent
+! RUN: %flang_fc1 -triple mips64-unknown-linux-gnuabi64 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,N64
+! RUN: %flang_fc1 -triple mips64el-unknown-linux-gnuabi64 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,N64
+! RUN: %flang_fc1 -triple mips64-unknown-linux-gnuabin32 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,N32
+! RUN: %flang_fc1 -triple mips64el-unknown-linux-gnuabin32 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,N32
+
+! N32: target datalayout = "{{.*}}-p:32:32-{{.*}}"
+! N64: target datalayout = "{{[Ee]}}-m:e-i8:8:32-{{.*}}"
+
+! CHECK-LABEL: define { float, float } @complex_value(float {{.*}}, float {{.*}})
+function complex_value(z) result(r) bind(c)
+  complex, value :: z
+  complex :: r
+  r = z
+end function
+
+! CHECK-LABEL: define signext i32 @integer_value(i32 signext {{.*}})
+function integer_value(x) result(r) bind(c)
+  integer, value :: x
+  integer :: r
+  r = x
+end function
+
+! N32-LABEL: define i64 @character_length_(ptr {{.*}}, i32 {{.*}})
+! N64-LABEL: define i64 @character_length_(ptr {{.*}}, i64 {{.*}})
+function character_length(s) result(n)
+  character(*) :: s
+  integer(8) :: n
+  n = len(s, kind=8)
+end function



More information about the flang-commits mailing list