Skip to content

[flang] Pass one element struct by register on X86-64 #75802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 19, 2023

Conversation

jeanPerier
Copy link
Contributor

Implement the C struct passing ABI on X86-64 for the trivial case where the structs have one element. This is required to cover some cases of BIND(C) derived type pass with the VALUE attribute.

Implement the C struct passing ABI on X86-64 for the trivial
case where the structs have one element. This is required to cover
some cases of BIND(C) derived type pass with the VALUE attribute.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:codegen labels Dec 18, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2023

@llvm/pr-subscribers-flang-codegen

Author: None (jeanPerier)

Changes

Implement the C struct passing ABI on X86-64 for the trivial case where the structs have one element. This is required to cover some cases of BIND(C) derived type pass with the VALUE attribute.


Full diff: https://github.com/llvm/llvm-project/pull/75802.diff

2 Files Affected:

  • (modified) flang/lib/Optimizer/CodeGen/Target.cpp (+23-1)
  • (added) flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir (+176)
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 3cd0e66fc7a1d9..ff3f9c4d6e7786 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -589,6 +589,21 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
       Hi = SSE;
   }
 
+  /// When \p recTy is a one field record type that can be passed
+  /// like the field on its own, returns the field type. Returns
+  /// a null type otherwise.
+  mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const {
+    auto typeList = recTy.getTypeList();
+    if (typeList.size() != 1)
+      return {};
+    mlir::Type fieldType = typeList[0].second;
+    if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::RealType,
+                  fir::CharacterType, fir::LogicalType>(fieldType))
+      return fieldType;
+    // Complex field that needs to be split, or array.
+    return {};
+  }
+
   /// Marshal a derived type passed by value like a C struct.
   CodeGenSpecifics::Marshalling
   structArgumentType(mlir::Location loc, fir::RecordType recTy,
@@ -617,7 +632,14 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
     if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters,
                             previousArguments))
       return passOnTheStack(loc, recTy);
-    // TODO, marshal the struct into registers.
+
+    if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) {
+      CodeGenSpecifics::Marshalling marshal;
+      marshal.emplace_back(fieldType, AT{});
+      return marshal;
+    }
+    // TODO, marshal the struct with several components, or with a single
+    // complex, array, or derived type component into registers.
     TODO(loc, "passing BIND(C), VALUE derived type in registers on X86-64");
   }
 
diff --git a/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir b/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir
new file mode 100644
index 00000000000000..9d4745becd8523
--- /dev/null
+++ b/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir
@@ -0,0 +1,176 @@
+// Test X86-64 passing ABI of struct in registers for the simple case
+// where the struct has a single intrinsic component that is not a complex.
+// REQUIRES: x86-registered-target
+// RUN: fir-opt -target-rewrite="target=x86_64-unknown-linux-gnu" %s -o - | FileCheck %s
+
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+
+func.func @test_call_i16(%0 : !fir.ref<!fir.type<ti16{i:i16}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti16{i:i16}>>
+  fir.call @test_func_i16(%7)  : (!fir.type<ti16{i:i16}>) -> ()
+  return
+}
+// CHECK-LABEL:   func.func @test_call_i16(
+// CHECK-SAME:                             %[[VAL_0:.*]]: !fir.ref<!fir.type<ti16{i:i16}>>) {
+// CHECK:           %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_2:.*]] = fir.call @llvm.stacksave.p0() : () -> !fir.ref<i8>
+// CHECK:           %[[VAL_3:.*]] = fir.alloca i16
+// CHECK:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           fir.store %[[VAL_1]] to %[[VAL_4]] : !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_5:.*]] = fir.load %[[VAL_3]] : !fir.ref<i16>
+// CHECK:           fir.call @test_func_i16(%[[VAL_5]]) : (i16) -> ()
+// CHECK:           fir.call @llvm.stackrestore.p0(%[[VAL_2]]) : (!fir.ref<i8>) -> ()
+
+func.func private @test_func_i16(%0 : !fir.type<ti16{i:i16}>) -> () {
+  return
+}
+// CHECK-LABEL:   func.func private @test_func_i16(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i16) {
+// CHECK:           %[[VAL_1:.*]] = fir.alloca i16
+// CHECK:           fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<i16>
+// CHECK:           %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.type<ti16{i:i16}>>
+
+func.func @test_call_i32(%0 : !fir.ref<!fir.type<ti32{i:i32}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti32{i:i32}>>
+  fir.call @test_func_i32(%7)  : (!fir.type<ti32{i:i32}>) -> ()
+  return
+}
+func.func private @test_func_i32(%0 : !fir.type<ti32{i:i32}>) -> () {
+  return
+}
+
+func.func @test_call_i64(%0 : !fir.ref<!fir.type<ti64{i:i64}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti64{i:i64}>>
+  fir.call @test_func_i64(%7)  : (!fir.type<ti64{i:i64}>) -> ()
+  return
+}
+func.func private @test_func_i64(%0 : !fir.type<ti64{i:i64}>) -> () {
+  return
+}
+
+func.func @test_call_i128(%0 : !fir.ref<!fir.type<ti128{i:i128}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti128{i:i128}>>
+  fir.call @test_func_i128(%7)  : (!fir.type<ti128{i:i128}>) -> ()
+  return
+}
+func.func private @test_func_i128(%0 : !fir.type<ti128{i:i128}>) -> () {
+  return
+}
+func.func @test_call_f16(%0 : !fir.ref<!fir.type<tf16{i:f16}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf16{i:f16}>>
+  fir.call @test_func_f16(%7)  : (!fir.type<tf16{i:f16}>) -> ()
+  return
+}
+func.func private @test_func_f16(%0 : !fir.type<tf16{i:f16}>) -> () {
+  return
+}
+
+func.func @test_call_f32(%0 : !fir.ref<!fir.type<tf32{i:f32}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf32{i:f32}>>
+  fir.call @test_func_f32(%7)  : (!fir.type<tf32{i:f32}>) -> ()
+  return
+}
+func.func private @test_func_f32(%0 : !fir.type<tf32{i:f32}>) -> () {
+  return
+}
+
+func.func @test_call_f64(%0 : !fir.ref<!fir.type<tf64{i:f64}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf64{i:f64}>>
+  fir.call @test_func_f64(%7)  : (!fir.type<tf64{i:f64}>) -> ()
+  return
+}
+func.func private @test_func_f64(%0 : !fir.type<tf64{i:f64}>) -> () {
+  return
+}
+
+func.func @test_call_f128(%0 : !fir.ref<!fir.type<tf128{i:f128}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf128{i:f128}>>
+  fir.call @test_func_f128(%7)  : (!fir.type<tf128{i:f128}>) -> ()
+  return
+}
+func.func private @test_func_f128(%0 : !fir.type<tf128{i:f128}>) -> () {
+  return
+}
+
+func.func @test_call_char1(%0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>
+  fir.call @test_func_char1(%7)  : (!fir.type<tchar1{i:!fir.char<1>}>) -> ()
+  return
+}
+func.func private @test_func_char1(%0 : !fir.type<tchar1{i:!fir.char<1>}>) -> () {
+  return
+}
+
+func.func @test_call_log1(%0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>
+  fir.call @test_func_log1(%7)  : (!fir.type<tlog1{i:!fir.logical<1>}>) -> ()
+  return
+}
+func.func private @test_func_log1(%0 : !fir.type<tlog1{i:!fir.logical<1>}>) -> () {
+  return
+}
+
+func.func @test_call_log2(%0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>
+  fir.call @test_func_log2(%7)  : (!fir.type<tlog2{i:!fir.logical<2>}>) -> ()
+  return
+}
+func.func private @test_func_log2(%0 : !fir.type<tlog2{i:!fir.logical<2>}>) -> () {
+  return
+}
+
+func.func @test_call_log4(%0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>
+  fir.call @test_func_log4(%7)  : (!fir.type<tlog4{i:!fir.logical<4>}>) -> ()
+  return
+}
+func.func private @test_func_log4(%0 : !fir.type<tlog4{i:!fir.logical<4>}>) -> () {
+  return
+}
+
+func.func @test_call_log8(%0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>
+  fir.call @test_func_log8(%7)  : (!fir.type<tlog8{i:!fir.logical<8>}>) -> ()
+  return
+}
+func.func private @test_func_log8(%0 : !fir.type<tlog8{i:!fir.logical<8>}>) -> () {
+  return
+}
+
+func.func @test_call_log16(%0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>
+  fir.call @test_func_log16(%7)  : (!fir.type<tlog16{i:!fir.logical<16>}>) -> ()
+  return
+}
+func.func private @test_func_log16(%0 : !fir.type<tlog16{i:!fir.logical<16>}>) -> () {
+  return
+}
+}
+
+// CHECK-LABEL:   func.func private @test_func_i32(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i32) {
+// CHECK-LABEL:   func.func private @test_func_i64(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i64) {
+// CHECK-LABEL:   func.func private @test_func_i128(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: i128) {
+// CHECK-LABEL:   func.func private @test_func_f16(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f16) {
+// CHECK-LABEL:   func.func private @test_func_f32(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f32) {
+// CHECK-LABEL:   func.func private @test_func_f64(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f64) {
+// CHECK-LABEL:   func.func private @test_func_f128(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: f128) {
+// CHECK-LABEL:   func.func private @test_func_char1(
+// CHECK-SAME:                                       %[[VAL_0:.*]]: !fir.char<1>) {
+// CHECK-LABEL:   func.func private @test_func_log1(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<1>) {
+// CHECK-LABEL:   func.func private @test_func_log2(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<2>) {
+// CHECK-LABEL:   func.func private @test_func_log4(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<4>) {
+// CHECK-LABEL:   func.func private @test_func_log8(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<8>) {
+// CHECK-LABEL:   func.func private @test_func_log16(
+// CHECK-SAME:                                       %[[VAL_0:.*]]: !fir.logical<16>) {

@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2023

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (jeanPerier)

Changes

Implement the C struct passing ABI on X86-64 for the trivial case where the structs have one element. This is required to cover some cases of BIND(C) derived type pass with the VALUE attribute.


Full diff: https://github.com/llvm/llvm-project/pull/75802.diff

2 Files Affected:

  • (modified) flang/lib/Optimizer/CodeGen/Target.cpp (+23-1)
  • (added) flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir (+176)
diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp
index 3cd0e66fc7a1d9..ff3f9c4d6e7786 100644
--- a/flang/lib/Optimizer/CodeGen/Target.cpp
+++ b/flang/lib/Optimizer/CodeGen/Target.cpp
@@ -589,6 +589,21 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
       Hi = SSE;
   }
 
+  /// When \p recTy is a one field record type that can be passed
+  /// like the field on its own, returns the field type. Returns
+  /// a null type otherwise.
+  mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const {
+    auto typeList = recTy.getTypeList();
+    if (typeList.size() != 1)
+      return {};
+    mlir::Type fieldType = typeList[0].second;
+    if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::RealType,
+                  fir::CharacterType, fir::LogicalType>(fieldType))
+      return fieldType;
+    // Complex field that needs to be split, or array.
+    return {};
+  }
+
   /// Marshal a derived type passed by value like a C struct.
   CodeGenSpecifics::Marshalling
   structArgumentType(mlir::Location loc, fir::RecordType recTy,
@@ -617,7 +632,14 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
     if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters,
                             previousArguments))
       return passOnTheStack(loc, recTy);
-    // TODO, marshal the struct into registers.
+
+    if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) {
+      CodeGenSpecifics::Marshalling marshal;
+      marshal.emplace_back(fieldType, AT{});
+      return marshal;
+    }
+    // TODO, marshal the struct with several components, or with a single
+    // complex, array, or derived type component into registers.
     TODO(loc, "passing BIND(C), VALUE derived type in registers on X86-64");
   }
 
diff --git a/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir b/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir
new file mode 100644
index 00000000000000..9d4745becd8523
--- /dev/null
+++ b/flang/test/Fir/struct-passing-x86-64-one-field-inreg.fir
@@ -0,0 +1,176 @@
+// Test X86-64 passing ABI of struct in registers for the simple case
+// where the struct has a single intrinsic component that is not a complex.
+// REQUIRES: x86-registered-target
+// RUN: fir-opt -target-rewrite="target=x86_64-unknown-linux-gnu" %s -o - | FileCheck %s
+
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+
+func.func @test_call_i16(%0 : !fir.ref<!fir.type<ti16{i:i16}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti16{i:i16}>>
+  fir.call @test_func_i16(%7)  : (!fir.type<ti16{i:i16}>) -> ()
+  return
+}
+// CHECK-LABEL:   func.func @test_call_i16(
+// CHECK-SAME:                             %[[VAL_0:.*]]: !fir.ref<!fir.type<ti16{i:i16}>>) {
+// CHECK:           %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_2:.*]] = fir.call @llvm.stacksave.p0() : () -> !fir.ref<i8>
+// CHECK:           %[[VAL_3:.*]] = fir.alloca i16
+// CHECK:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           fir.store %[[VAL_1]] to %[[VAL_4]] : !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_5:.*]] = fir.load %[[VAL_3]] : !fir.ref<i16>
+// CHECK:           fir.call @test_func_i16(%[[VAL_5]]) : (i16) -> ()
+// CHECK:           fir.call @llvm.stackrestore.p0(%[[VAL_2]]) : (!fir.ref<i8>) -> ()
+
+func.func private @test_func_i16(%0 : !fir.type<ti16{i:i16}>) -> () {
+  return
+}
+// CHECK-LABEL:   func.func private @test_func_i16(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i16) {
+// CHECK:           %[[VAL_1:.*]] = fir.alloca i16
+// CHECK:           fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<i16>
+// CHECK:           %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
+// CHECK:           %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.type<ti16{i:i16}>>
+
+func.func @test_call_i32(%0 : !fir.ref<!fir.type<ti32{i:i32}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti32{i:i32}>>
+  fir.call @test_func_i32(%7)  : (!fir.type<ti32{i:i32}>) -> ()
+  return
+}
+func.func private @test_func_i32(%0 : !fir.type<ti32{i:i32}>) -> () {
+  return
+}
+
+func.func @test_call_i64(%0 : !fir.ref<!fir.type<ti64{i:i64}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti64{i:i64}>>
+  fir.call @test_func_i64(%7)  : (!fir.type<ti64{i:i64}>) -> ()
+  return
+}
+func.func private @test_func_i64(%0 : !fir.type<ti64{i:i64}>) -> () {
+  return
+}
+
+func.func @test_call_i128(%0 : !fir.ref<!fir.type<ti128{i:i128}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<ti128{i:i128}>>
+  fir.call @test_func_i128(%7)  : (!fir.type<ti128{i:i128}>) -> ()
+  return
+}
+func.func private @test_func_i128(%0 : !fir.type<ti128{i:i128}>) -> () {
+  return
+}
+func.func @test_call_f16(%0 : !fir.ref<!fir.type<tf16{i:f16}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf16{i:f16}>>
+  fir.call @test_func_f16(%7)  : (!fir.type<tf16{i:f16}>) -> ()
+  return
+}
+func.func private @test_func_f16(%0 : !fir.type<tf16{i:f16}>) -> () {
+  return
+}
+
+func.func @test_call_f32(%0 : !fir.ref<!fir.type<tf32{i:f32}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf32{i:f32}>>
+  fir.call @test_func_f32(%7)  : (!fir.type<tf32{i:f32}>) -> ()
+  return
+}
+func.func private @test_func_f32(%0 : !fir.type<tf32{i:f32}>) -> () {
+  return
+}
+
+func.func @test_call_f64(%0 : !fir.ref<!fir.type<tf64{i:f64}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf64{i:f64}>>
+  fir.call @test_func_f64(%7)  : (!fir.type<tf64{i:f64}>) -> ()
+  return
+}
+func.func private @test_func_f64(%0 : !fir.type<tf64{i:f64}>) -> () {
+  return
+}
+
+func.func @test_call_f128(%0 : !fir.ref<!fir.type<tf128{i:f128}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tf128{i:f128}>>
+  fir.call @test_func_f128(%7)  : (!fir.type<tf128{i:f128}>) -> ()
+  return
+}
+func.func private @test_func_f128(%0 : !fir.type<tf128{i:f128}>) -> () {
+  return
+}
+
+func.func @test_call_char1(%0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>
+  fir.call @test_func_char1(%7)  : (!fir.type<tchar1{i:!fir.char<1>}>) -> ()
+  return
+}
+func.func private @test_func_char1(%0 : !fir.type<tchar1{i:!fir.char<1>}>) -> () {
+  return
+}
+
+func.func @test_call_log1(%0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>
+  fir.call @test_func_log1(%7)  : (!fir.type<tlog1{i:!fir.logical<1>}>) -> ()
+  return
+}
+func.func private @test_func_log1(%0 : !fir.type<tlog1{i:!fir.logical<1>}>) -> () {
+  return
+}
+
+func.func @test_call_log2(%0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>
+  fir.call @test_func_log2(%7)  : (!fir.type<tlog2{i:!fir.logical<2>}>) -> ()
+  return
+}
+func.func private @test_func_log2(%0 : !fir.type<tlog2{i:!fir.logical<2>}>) -> () {
+  return
+}
+
+func.func @test_call_log4(%0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>
+  fir.call @test_func_log4(%7)  : (!fir.type<tlog4{i:!fir.logical<4>}>) -> ()
+  return
+}
+func.func private @test_func_log4(%0 : !fir.type<tlog4{i:!fir.logical<4>}>) -> () {
+  return
+}
+
+func.func @test_call_log8(%0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>
+  fir.call @test_func_log8(%7)  : (!fir.type<tlog8{i:!fir.logical<8>}>) -> ()
+  return
+}
+func.func private @test_func_log8(%0 : !fir.type<tlog8{i:!fir.logical<8>}>) -> () {
+  return
+}
+
+func.func @test_call_log16(%0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>) {
+  %7 = fir.load %0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>
+  fir.call @test_func_log16(%7)  : (!fir.type<tlog16{i:!fir.logical<16>}>) -> ()
+  return
+}
+func.func private @test_func_log16(%0 : !fir.type<tlog16{i:!fir.logical<16>}>) -> () {
+  return
+}
+}
+
+// CHECK-LABEL:   func.func private @test_func_i32(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i32) {
+// CHECK-LABEL:   func.func private @test_func_i64(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: i64) {
+// CHECK-LABEL:   func.func private @test_func_i128(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: i128) {
+// CHECK-LABEL:   func.func private @test_func_f16(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f16) {
+// CHECK-LABEL:   func.func private @test_func_f32(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f32) {
+// CHECK-LABEL:   func.func private @test_func_f64(
+// CHECK-SAME:                                     %[[VAL_0:.*]]: f64) {
+// CHECK-LABEL:   func.func private @test_func_f128(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: f128) {
+// CHECK-LABEL:   func.func private @test_func_char1(
+// CHECK-SAME:                                       %[[VAL_0:.*]]: !fir.char<1>) {
+// CHECK-LABEL:   func.func private @test_func_log1(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<1>) {
+// CHECK-LABEL:   func.func private @test_func_log2(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<2>) {
+// CHECK-LABEL:   func.func private @test_func_log4(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<4>) {
+// CHECK-LABEL:   func.func private @test_func_log8(
+// CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.logical<8>) {
+// CHECK-LABEL:   func.func private @test_func_log16(
+// CHECK-SAME:                                       %[[VAL_0:.*]]: !fir.logical<16>) {

Copy link
Contributor

@psteinfeld psteinfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All builds and tests correctly.

Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you!

@jeanPerier jeanPerier merged commit 1d57b9a into llvm:main Dec 19, 2023
@jeanPerier jeanPerier deleted the jpr-struct-by-register branch December 19, 2023 08:51
jeanPerier added a commit to jeanPerier/llvm-project that referenced this pull request Jan 11, 2024
Derived type passed with VALUE in BIND(C) context must be passed like
C struct and LLVM is not implementing the ABI for this (it is up to the
frontends like clang).

Previous patch llvm#75802 implemented the simple cases where the derived
type have one field, this patch implements the general case. Note that
the generated LLVM IR is compliant from a X86-64 C ABI point of view
and compatible with clang generated assembly, but that it is not
guaranteed to match the LLVM IR signatures generated by clang for the C
equivalent functions because several LLVM IR signatures may lead to the
same X86-64 signature.
jeanPerier added a commit that referenced this pull request Jan 12, 2024
Derived type passed with VALUE in BIND(C) context must be passed like C
struct and LLVM is not implementing the ABI for this (it is up to the
frontends like clang).

Previous patch #75802 implemented the simple cases where the derived
type have one field, this patch implements the general case. Note that
the generated LLVM IR is compliant from a X86-64 C ABI point of view and
compatible with clang generated assembly, but that it is not guaranteed
to match the LLVM IR signatures generated by clang for the C equivalent
functions because several LLVM IR signatures may lead to the same X86-64
signature.
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…#77742)

Derived type passed with VALUE in BIND(C) context must be passed like C
struct and LLVM is not implementing the ABI for this (it is up to the
frontends like clang).

Previous patch llvm#75802 implemented the simple cases where the derived
type have one field, this patch implements the general case. Note that
the generated LLVM IR is compliant from a X86-64 C ABI point of view and
compatible with clang generated assembly, but that it is not guaranteed
to match the LLVM IR signatures generated by clang for the C equivalent
functions because several LLVM IR signatures may lead to the same X86-64
signature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:codegen flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants