From 6cafba5b9f376cb8e4a1561c3c0f7814b7dc1da6 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 16 Jan 2024 05:46:41 -0800 Subject: [PATCH] [flang] Lower BIND(C) module variables Lower initialized BIND(C) module variable as regular module variable, except that the fir.global symbol name is the binding label. For uninitialized variables, add the common linkage so that C code may define the variables. The standard does not provide a way to indicate that a variable is defined in C, but there are use cases. Beware that if the module file compiled object is added to a shared library, the variable will become a regular global definition and may override the C variable depending on the linking order. --- flang/lib/Lower/ConvertVariable.cpp | 17 +++++++----- flang/test/Lower/HLFIR/bindc-module-var.f90 | 29 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 flang/test/Lower/HLFIR/bindc-module-var.f90 diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index ad44de71ee828a..dd024a0a1ec792 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -595,14 +595,17 @@ static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter, // Creates zero initializer for globals without initializers, this is a common // and expected behavior (although not required by the standard) if (!globalIsInitialized(global)) { - // TODO: For BIND(C) variables, an initial value may be given in another - // compilation unit (on the C side), and setting an zero init here creates - // linkage conflicts. See if there is a way to get it zero initialized if - // not initialized elsewhere. MLIR also used to drop globals without - // initializers that are not used in the file, but this may not be true - // anymore. + // Fortran does not provide means to specify that a BIND(C) module + // uninitialized variables will be defined in C. + // Add the common linkage to those to allow some level of support + // for this use case. Note that this use case will not work if the Fortran + // module code is placed in a shared library since, at least for the ELF + // format, common symbols are assigned a section in shared libraries. + // The best is still to declare C defined variables in a Fortran module file + // with no other definitions, and to never link the resulting module object + // file. if (sym.attrs().test(Fortran::semantics::Attr::BIND_C)) - TODO(loc, "BIND(C) module variable linkage"); + global.setLinkName(builder.createCommonLinkage()); Fortran::lower::createGlobalInitialization( builder, global, [&](fir::FirOpBuilder &builder) { mlir::Value initValue = builder.create(loc, symTy); diff --git a/flang/test/Lower/HLFIR/bindc-module-var.f90 b/flang/test/Lower/HLFIR/bindc-module-var.f90 new file mode 100644 index 00000000000000..20848078b3eba3 --- /dev/null +++ b/flang/test/Lower/HLFIR/bindc-module-var.f90 @@ -0,0 +1,29 @@ +! Test BIND(C) module variable lowering +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s + +module some_c_module + integer, bind(c, name="i_var") :: i = 1 + integer, bind(c, name="i_var_no_init") :: i_no_init + integer, bind(c) :: j_var = 2 + integer, bind(c) :: j_var_no_init +end module + +! CHECK-LABEL: fir.global @i_var : i32 { +! CHECK: %[[VAL_0:.*]] = arith.constant 1 : i32 +! CHECK: fir.has_value %[[VAL_0]] : i32 +! CHECK: } + +! CHECK-LABEL: fir.global common @i_var_no_init : i32 { +! CHECK: %[[VAL_0:.*]] = fir.zero_bits i32 +! CHECK: fir.has_value %[[VAL_0]] : i32 +! CHECK: } + +! CHECK-LABEL: fir.global @j_var : i32 { +! CHECK: %[[VAL_0:.*]] = arith.constant 2 : i32 +! CHECK: fir.has_value %[[VAL_0]] : i32 +! CHECK: } + +! CHECK-LABEL: fir.global common @j_var_no_init : i32 { +! CHECK: %[[VAL_0:.*]] = fir.zero_bits i32 +! CHECK: fir.has_value %[[VAL_0]] : i32 +! CHECK: }