[flang-commits] [clang] [flang] [flang] Implement -mcmodel flag (PR #95411)

Mats Petersson via flang-commits flang-commits at lists.llvm.org
Mon Jul 1 07:44:00 PDT 2024


https://github.com/Leporacanthicus updated https://github.com/llvm/llvm-project/pull/95411

>From 0ef4b61d0429517b92f7b6de7fa52c516f3a1468 Mon Sep 17 00:00:00 2001
From: David Truby <david.truby at arm.com>
Date: Thu, 13 Jun 2024 14:01:36 +0000
Subject: [PATCH 1/5] [flang] Implement -mcmodel flag

This patch implements the -mcmodel flag from clang, allowing the Code Model to
be changed for the LLVM module. The same set of mcmodel flags are accepted as
in clang and the same Code Model attributes are added to the LLVM module for
those flags.
---
 clang/include/clang/Driver/Options.td         |  2 +-
 clang/lib/Driver/ToolChains/Clang.cpp         | 76 +----------------
 clang/lib/Driver/ToolChains/CommonArgs.cpp    | 81 +++++++++++++++++++
 clang/lib/Driver/ToolChains/CommonArgs.h      |  4 +
 clang/lib/Driver/ToolChains/Flang.cpp         |  5 ++
 .../include/flang/Frontend/CodeGenOptions.def |  1 +
 flang/lib/Frontend/CompilerInvocation.cpp     | 21 +++++
 flang/lib/Frontend/FrontendActions.cpp        |  3 +
 flang/test/Driver/mcmodel.f90                 | 44 ++++++++++
 flang/test/Lower/mcmodel.f90                  | 16 ++++
 10 files changed, 177 insertions(+), 76 deletions(-)
 create mode 100644 flang/test/Driver/mcmodel.f90
 create mode 100644 flang/test/Lower/mcmodel.f90

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 9f7904dd94b94..4087d3b95cc39 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4600,7 +4600,7 @@ def inline_asm_EQ : Joined<["-"], "inline-asm=">, Group<m_Group>,
   NormalizedValuesScope<"CodeGenOptions">, NormalizedValues<["IAD_ATT", "IAD_Intel"]>,
   MarshallingInfoEnum<CodeGenOpts<"InlineAsmDialect">, "IAD_ATT">;
 def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>,
-  Visibility<[ClangOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
   MarshallingInfoString<TargetOpts<"CodeModel">, [{"default"}]>;
 def mlarge_data_threshold_EQ : Joined<["-"], "mlarge-data-threshold=">, Group<m_Group>,
   Flags<[TargetSpecific]>, Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 1f8591537b6c8..0447581128cd1 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5908,81 +5908,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
 
-  if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
-    StringRef CM = A->getValue();
-    bool Ok = false;
-    if (Triple.isOSAIX() && CM == "medium")
-      CM = "large";
-    if (Triple.isAArch64(64)) {
-      Ok = CM == "tiny" || CM == "small" || CM == "large";
-      if (CM == "large" && !Triple.isOSBinFormatMachO() &&
-          RelocationModel != llvm::Reloc::Static)
-        D.Diag(diag::err_drv_argument_only_allowed_with)
-            << A->getAsString(Args) << "-fno-pic";
-    } else if (Triple.isLoongArch()) {
-      if (CM == "extreme" &&
-          Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false))
-        D.Diag(diag::err_drv_argument_not_allowed_with)
-            << A->getAsString(Args) << "-fplt";
-      Ok = CM == "normal" || CM == "medium" || CM == "extreme";
-      // Convert to LLVM recognizable names.
-      if (Ok)
-        CM = llvm::StringSwitch<StringRef>(CM)
-                 .Case("normal", "small")
-                 .Case("extreme", "large")
-                 .Default(CM);
-    } else if (Triple.isPPC64() || Triple.isOSAIX()) {
-      Ok = CM == "small" || CM == "medium" || CM == "large";
-    } else if (Triple.isRISCV()) {
-      if (CM == "medlow")
-        CM = "small";
-      else if (CM == "medany")
-        CM = "medium";
-      Ok = CM == "small" || CM == "medium";
-    } else if (Triple.getArch() == llvm::Triple::x86_64) {
-      Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"},
-                              CM);
-    } else if (Triple.isNVPTX() || Triple.isAMDGPU() || Triple.isSPIRV()) {
-      // NVPTX/AMDGPU/SPIRV does not care about the code model and will accept
-      // whatever works for the host.
-      Ok = true;
-    } else if (Triple.isSPARC64()) {
-      if (CM == "medlow")
-        CM = "small";
-      else if (CM == "medmid")
-        CM = "medium";
-      else if (CM == "medany")
-        CM = "large";
-      Ok = CM == "small" || CM == "medium" || CM == "large";
-    }
-    if (Ok) {
-      CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM));
-    } else {
-      D.Diag(diag::err_drv_unsupported_option_argument_for_target)
-          << A->getSpelling() << CM << TripleStr;
-    }
-  }
-
-  if (Triple.getArch() == llvm::Triple::x86_64) {
-    bool IsMediumCM = false;
-    bool IsLargeCM = false;
-    if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
-      IsMediumCM = StringRef(A->getValue()) == "medium";
-      IsLargeCM = StringRef(A->getValue()) == "large";
-    }
-    if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
-      if (!IsMediumCM && !IsLargeCM) {
-        D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
-            << A->getOption().getRenderName();
-      } else {
-        A->render(Args, CmdArgs);
-      }
-    } else if (IsMediumCM) {
-      CmdArgs.push_back("-mlarge-data-threshold=65536");
-    } else if (IsLargeCM) {
-      CmdArgs.push_back("-mlarge-data-threshold=0");
-    }
-  }
+  addMCModel(D, Args, Triple, RelocationModel, CmdArgs);
 
   if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) {
     StringRef Value = A->getValue();
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 2a4c1369f5a73..a33975e14c541 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -2823,3 +2823,84 @@ void tools::addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
     CmdArgs.push_back(
         TCArgs.MakeArgString(Twine("-compression-level=") + Arg->getValue()));
 }
+
+void tools::addMCModel(const Driver &D, const llvm::opt::ArgList &Args,
+                       const llvm::Triple &Triple,
+                       const llvm::Reloc::Model &RelocationModel,
+                       llvm::opt::ArgStringList &CmdArgs) {
+  if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+    StringRef CM = A->getValue();
+    bool Ok = false;
+    if (Triple.isOSAIX() && CM == "medium")
+      CM = "large";
+    if (Triple.isAArch64(64)) {
+      Ok = CM == "tiny" || CM == "small" || CM == "large";
+      if (CM == "large" && !Triple.isOSBinFormatMachO() &&
+          RelocationModel != llvm::Reloc::Static)
+        D.Diag(diag::err_drv_argument_only_allowed_with)
+            << A->getAsString(Args) << "-fno-pic";
+    } else if (Triple.isLoongArch()) {
+      if (CM == "extreme" &&
+          Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false))
+        D.Diag(diag::err_drv_argument_not_allowed_with)
+            << A->getAsString(Args) << "-fplt";
+      Ok = CM == "normal" || CM == "medium" || CM == "extreme";
+      // Convert to LLVM recognizable names.
+      if (Ok)
+        CM = llvm::StringSwitch<StringRef>(CM)
+                 .Case("normal", "small")
+                 .Case("extreme", "large")
+                 .Default(CM);
+    } else if (Triple.isPPC64() || Triple.isOSAIX()) {
+      Ok = CM == "small" || CM == "medium" || CM == "large";
+    } else if (Triple.isRISCV()) {
+      if (CM == "medlow")
+        CM = "small";
+      else if (CM == "medany")
+        CM = "medium";
+      Ok = CM == "small" || CM == "medium";
+    } else if (Triple.getArch() == llvm::Triple::x86_64) {
+      Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"},
+                              CM);
+    } else if (Triple.isNVPTX() || Triple.isAMDGPU() || Triple.isSPIRV()) {
+      // NVPTX/AMDGPU/SPIRV does not care about the code model and will accept
+      // whatever works for the host.
+      Ok = true;
+    } else if (Triple.isSPARC64()) {
+      if (CM == "medlow")
+        CM = "small";
+      else if (CM == "medmid")
+        CM = "medium";
+      else if (CM == "medany")
+        CM = "large";
+      Ok = CM == "small" || CM == "medium" || CM == "large";
+    }
+    if (Ok) {
+      CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM));
+    } else {
+      D.Diag(diag::err_drv_unsupported_option_argument_for_target)
+          << A->getSpelling() << CM << Triple.getTriple();
+    }
+  }
+
+  if (Triple.getArch() == llvm::Triple::x86_64) {
+    bool IsMediumCM = false;
+    bool IsLargeCM = false;
+    if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+      IsMediumCM = StringRef(A->getValue()) == "medium";
+      IsLargeCM = StringRef(A->getValue()) == "large";
+    }
+    if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
+      if (!IsMediumCM && !IsLargeCM) {
+        D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
+            << A->getOption().getRenderName();
+      } else {
+        A->render(Args, CmdArgs);
+      }
+    } else if (IsMediumCM) {
+      CmdArgs.push_back("-mlarge-data-threshold=65536");
+    } else if (IsLargeCM) {
+      CmdArgs.push_back("-mlarge-data-threshold=0");
+    }
+  }
+}
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h
index 5581905db3114..52818ecde924b 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.h
+++ b/clang/lib/Driver/ToolChains/CommonArgs.h
@@ -223,6 +223,10 @@ void addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
                            const llvm::Triple &Triple);
 void addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
                             llvm::opt::ArgStringList &CmdArgs);
+void addMCModel(const Driver &D, const llvm::opt::ArgList &Args,
+                const llvm::Triple &Triple,
+                const llvm::Reloc::Model &RelocationModel,
+                llvm::opt::ArgStringList &CmdArgs);
 
 } // end namespace tools
 } // end namespace driver
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 42b45dba2bd31..962a6c2c6b298 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -735,6 +735,11 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
   // Add target args, features, etc.
   addTargetOptions(Args, CmdArgs);
 
+  llvm::Reloc::Model RelocationModel =
+      std::get<0>(ParsePICArgs(getToolChain(), Args));
+  // Add MCModel information
+  addMCModel(D, Args, Triple, RelocationModel, CmdArgs);
+
   // Add Codegen options
   addCodegenOptions(Args, CmdArgs);
 
diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def
index 9d03ec88a56b8..5d364e6655b99 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.def
+++ b/flang/include/flang/Frontend/CodeGenOptions.def
@@ -39,6 +39,7 @@ ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///<
 ENUM_CODEGENOPT(DebugInfo,  llvm::codegenoptions::DebugInfoKind, 4,  llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate
 ENUM_CODEGENOPT(VecLib, llvm::driver::VectorLibrary, 3, llvm::driver::VectorLibrary::NoLibrary) ///< Vector functions library to use
 ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 2, llvm::FramePointerKind::None) ///< Enable the usage of frame pointers
+ENUM_CODEGENOPT(CodeModel, llvm::CodeModel::Model, 5, llvm::CodeModel::Model::Small)
 
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index f64a939b785ef..5c27088ec3890 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -32,6 +32,7 @@
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
+#include "llvm/Support/CodeGen.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Path.h"
@@ -381,6 +382,26 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
       opts.IsPIE = 1;
   }
 
+  // -mcmodel option.
+  if (const llvm::opt::Arg *a =
+          args.getLastArg(clang::driver::options::OPT_mcmodel_EQ)) {
+    llvm::StringRef modelName = a->getValue();
+    auto codeModel =
+        llvm::StringSwitch<std::optional<llvm::CodeModel::Model>>(modelName)
+            .Case("tiny", llvm::CodeModel::Model::Tiny)
+            .Case("small", llvm::CodeModel::Model::Small)
+            .Case("kernel", llvm::CodeModel::Model::Kernel)
+            .Case("medium", llvm::CodeModel::Model::Medium)
+            .Case("large", llvm::CodeModel::Model::Large)
+            .Default(std::nullopt);
+
+    if (codeModel.has_value())
+      opts.setCodeModel(*codeModel);
+    else
+      diags.Report(clang::diag::err_drv_invalid_value)
+          << a->getAsString(args) << modelName;
+  }
+
   // This option is compatible with -f[no-]underscoring in gfortran.
   if (args.hasFlag(clang::driver::options::OPT_fno_underscoring,
                    clang::driver::options::OPT_funderscoring, false)) {
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index b1b6391f1439c..b5c1792850fe3 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -861,6 +861,9 @@ void CodeGenAction::generateLLVMIR() {
       llvmModule->setPIELevel(
           static_cast<llvm::PIELevel::Level>(opts.PICLevel));
   }
+
+  // Set mcmodel level LLVM module flags
+  llvmModule->setCodeModel(opts.getCodeModel());
 }
 
 static std::unique_ptr<llvm::raw_pwrite_stream>
diff --git a/flang/test/Driver/mcmodel.f90 b/flang/test/Driver/mcmodel.f90
new file mode 100644
index 0000000000000..12d90ece2f24f
--- /dev/null
+++ b/flang/test/Driver/mcmodel.f90
@@ -0,0 +1,44 @@
+! RUN: not %flang -### -c --target=i686 -mcmodel=medium %s 2>&1 | FileCheck --check-prefix=ERR-MEDIUM %s
+! RUN: %flang --target=x86_64 -### -c -mcmodel=tiny %s 2>&1 | FileCheck --check-prefix=TINY %s
+! RUN: %flang --target=x86_64 -### -c -mcmodel=small %s 2>&1 | FileCheck --check-prefix=SMALL %s
+! RUN: %flang --target=x86_64 -### -S -mcmodel=kernel %s 2>&1 | FileCheck --check-prefix=KERNEL %s
+! RUN: %flang --target=x86_64 -### -c -mcmodel=medium %s 2>&1 | FileCheck --check-prefix=MEDIUM %s
+! RUN: %flang --target=x86_64 -### -S -mcmodel=large %s 2>&1 | FileCheck --check-prefix=LARGE %s
+! RUN: not %flang -### -c --target=powerpc-linux-gnu -mcmodel=medium %s 2>&1 | FileCheck --check-prefix=ERR-MEDIUM %s
+! RUN: %flang --target=powerpc-unknown-aix -### -S -mcmodel=small %s 2>&1 | FileCheck --check-prefix=SMALL %s
+! RUN: %flang --target=powerpc-unknown-aix -### -S -mcmodel=large %s 2>&1 | FileCheck --check-prefix=LARGE %s
+! RUN: %flang --target=powerpc-unknown-aix -### -S -mcmodel=medium %s 2> %t.log
+! RUN: FileCheck --check-prefix=AIX-MCMEDIUM-OVERRIDE %s < %t.log
+! RUN: not %flang -### -c -mcmodel=lager %s 2>&1 | FileCheck --check-prefix=INVALID %s
+! RUN: %flang --target=aarch64 -### -S -mcmodel=large -fno-pic %s 2>&1 | FileCheck --check-prefix=LARGE %s
+! RUN: %flang --target=aarch64-apple-macosx -### -S -mcmodel=large %s 2>&1 | FileCheck --check-prefix=LARGE %s
+! RUN: not %flang --target=aarch64 -### -S -mcmodel=large -fpic %s 2>&1 | FileCheck --check-prefix=AARCH64-PIC-LARGE %s
+! RUN: not %flang -### -c --target=aarch64 -mcmodel=medium %s 2>&1 | FileCheck --check-prefix=ERR-MEDIUM %s
+! RUN: not %flang -### -c --target=aarch64 -mcmodel=kernel %s 2>&1 | FileCheck --check-prefix=ERR-KERNEL %s
+! RUN: not %flang --target=aarch64_32-linux -### -S -mcmodel=small %s 2>&1 | FileCheck --check-prefix=ERR-AARCH64_32 %s
+! RUN: %flang --target=loongarch64 -### -S -mcmodel=normal %s 2>&1 | FileCheck --check-prefix=SMALL %s
+! RUN: %flang --target=loongarch64 -### -S -mcmodel=medium %s 2>&1 | FileCheck --check-prefix=MEDIUM %s
+! RUN: %flang --target=loongarch64 -### -S -mcmodel=extreme %s 2>&1 | FileCheck --check-prefix=LARGE %s
+! RUN: not %flang --target=loongarch64 -### -S -mcmodel=tiny %s 2>&1 | FileCheck --check-prefix=ERR-TINY %s
+! RUN: not %flang --target=loongarch64 -### -S -mcmodel=small %s 2>&1 | FileCheck --check-prefix=ERR-SMALL %s
+! RUN: not %flang --target=loongarch64 -### -S -mcmodel=kernel %s 2>&1 | FileCheck --check-prefix=ERR-KERNEL %s
+! RUN: not %flang --target=loongarch64 -### -S -mcmodel=large %s 2>&1 | FileCheck --check-prefix=ERR-LARGE %s
+
+! TINY: "-mcmodel=tiny"
+! SMALL: "-mcmodel=small"
+! KERNEL: "-mcmodel=kernel"
+! MEDIUM: "-mcmodel=medium"
+! LARGE: "-mcmodel=large"
+! AIX-MCMEDIUM-OVERRIDE: "-mcmodel=large"
+
+! INVALID: error: unsupported argument 'lager' to option '-mcmodel=' for target '{{.*}}'
+
+! ERR-TINY:   error: unsupported argument 'tiny' to option '-mcmodel=' for target '{{.*}}'
+! ERR-SMALL:  error: unsupported argument 'small' to option '-mcmodel=' for target '{{.*}}'
+! ERR-MEDIUM: error: unsupported argument 'medium' to option '-mcmodel=' for target '{{.*}}'
+! ERR-KERNEL: error: unsupported argument 'kernel' to option '-mcmodel=' for target '{{.*}}'
+! ERR-LARGE:  error: unsupported argument 'large' to option '-mcmodel=' for target '{{.*}}'
+
+! AARCH64-PIC-LARGE: error: invalid argument '-mcmodel=large' only allowed with '-fno-pic'
+! ERR-AARCH64_32: error: unsupported argument 'small' to option '-mcmodel=' for target 'aarch64_32-unknown-linux'
+
diff --git a/flang/test/Lower/mcmodel.f90 b/flang/test/Lower/mcmodel.f90
new file mode 100644
index 0000000000000..dd9eb145f5e2a
--- /dev/null
+++ b/flang/test/Lower/mcmodel.f90
@@ -0,0 +1,16 @@
+! RUN: %flang_fc1 -triple aarch64 -emit-llvm -mcmodel=tiny %s -o - | FileCheck %s -check-prefix=CHECK-TINY
+! RUN: %flang_fc1 -emit-llvm -mcmodel=small %s -o - | FileCheck %s -check-prefix=CHECK-SMALL
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-llvm -mcmodel=kernel %s -o - | FileCheck %s -check-prefix=CHECK-KERNEL
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-llvm -mcmodel=medium %s -o - | FileCheck %s -check-prefix=CHECK-MEDIUM
+! RUN: %flang_fc1 -emit-llvm -mcmodel=large %s -o - | FileCheck %s -check-prefix=CHECK-LARGE
+
+! CHECK-TINY: !llvm.module.flags = !{{{.*}}}
+! CHECK-TINY: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 0}
+! CHECK-SMALL: !llvm.module.flags = !{{{.*}}}
+! CHECK-SMALL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 1}
+! CHECK-KERNEL: !llvm.module.flags = !{{{.*}}}
+! CHECK-KERNEL: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 2}
+! CHECK-MEDIUM: !llvm.module.flags = !{{{.*}}}
+! CHECK-MEDIUM: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 3}
+! CHECK-LARGE: !llvm.module.flags = !{{{.*}}}
+! CHECK-LARGE: !{{[0-9]+}} = !{i32 1, !"Code Model", i32 4}

>From 77ca6312a09340f6368459964e446cb00e0b55f0 Mon Sep 17 00:00:00 2001
From: Mats Petersson <mats.petersson at arm.com>
Date: Fri, 28 Jun 2024 19:10:27 +0100
Subject: [PATCH 2/5] Add new flag -mlarge-data-threshold

---
 clang/include/clang/Driver/Options.td         |  2 +-
 flang/include/flang/Frontend/CodeGenOptions.h |  4 ++++
 flang/lib/Frontend/CompilerInvocation.cpp     |  9 +++++++++
 flang/lib/Frontend/FrontendActions.cpp        |  1 +
 flang/test/Driver/large-data-threshold.f90    | 18 ++++++++++++++++++
 5 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Driver/large-data-threshold.f90

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 4087d3b95cc39..54659fb6ae27c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4603,7 +4603,7 @@ def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
   MarshallingInfoString<TargetOpts<"CodeModel">, [{"default"}]>;
 def mlarge_data_threshold_EQ : Joined<["-"], "mlarge-data-threshold=">, Group<m_Group>,
-  Flags<[TargetSpecific]>, Visibility<[ClangOption, CC1Option]>,
+  Flags<[TargetSpecific]>, Visibility<[ClangOption, CC1Option,FlangOption, FC1Option]>,
   MarshallingInfoInt<TargetOpts<"LargeDataThreshold">, "0">;
 def mtls_size_EQ : Joined<["-"], "mtls-size=">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h
index 918192abae724..5cba2deb91ffb 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.h
+++ b/flang/include/flang/Frontend/CodeGenOptions.h
@@ -129,6 +129,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// transformation.
   OptRemark OptimizationRemarkAnalysis;
 
+  /// The code model-specific large data threshold to use
+  /// (-mlarge-data-threshold).
+  uint64_t LargeDataThreshold;
+
   // Define accessors/mutators for code generation options of enumeration type.
 #define CODEGENOPT(Name, Bits, Default)
 #define ENUM_CODEGENOPT(Name, Type, Bits, Default)                             \
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 5c27088ec3890..e9281672e7269 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -402,6 +402,15 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
           << a->getAsString(args) << modelName;
   }
 
+  if (const llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_mlarge_data_threshold_EQ)) {
+    uint64_t LDT;
+    if (llvm::StringRef(arg->getValue()).getAsInteger(/*Radix=*/10, LDT)) {
+      diags.Report(clang::diag::err_drv_invalid_value)
+          << arg->getSpelling() << arg->getValue();
+    }      
+    opts.LargeDataThreshold = LDT;
+  }
+  
   // This option is compatible with -f[no-]underscoring in gfortran.
   if (args.hasFlag(clang::driver::options::OPT_fno_underscoring,
                    clang::driver::options::OPT_funderscoring, false)) {
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index b5c1792850fe3..e45e9ece7adb0 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -864,6 +864,7 @@ void CodeGenAction::generateLLVMIR() {
 
   // Set mcmodel level LLVM module flags
   llvmModule->setCodeModel(opts.getCodeModel());
+  llvmModule->setLargeDataThreshold(opts.LargeDataThreshold);
 }
 
 static std::unique_ptr<llvm::raw_pwrite_stream>
diff --git a/flang/test/Driver/large-data-threshold.f90 b/flang/test/Driver/large-data-threshold.f90
new file mode 100644
index 0000000000000..ac6f78713f62c
--- /dev/null
+++ b/flang/test/Driver/large-data-threshold.f90
@@ -0,0 +1,18 @@
+! RUN: %flang -### -c --target=x86_64 -mcmodel=large -mlarge-data-threshold=32768 %s 2>&1 | FileCheck %s
+! RUN: %flang -### -c --target=x86_64 -mcmodel=large -mlarge-data-threshold=59000 %s 2>&1 | FileCheck %s --check-prefix=CHECK-59000
+! RUN: %flang -### -c --target=x86_64 -mcmodel=large -mlarge-data-threshold=1048576 %s 2>&1 | FileCheck %s --check-prefix=CHECK-1M
+! RUN: not %flang -c --target=x86_64 -mcmodel=large -mlarge-data-threshold=nonsense %s 2>&1 | FileCheck %s --check-prefix=INVALID
+! RUN: %flang -### -c --target=x86_64 -mlarge-data-threshold=32768 %s 2>&1 | FileCheck %s --check-prefix=NO-MCMODEL
+! RUN: %flang -### -c --target=x86_64 -mcmodel=small -mlarge-data-threshold=32768 %s 2>&1 | FileCheck %s --check-prefix=NO-MCMODEL
+! RUN: not %flang -### -c --target=aarch64 -mcmodel=small -mlarge-data-threshold=32768 %s 2>&1 | FileCheck %s --check-prefix=NOT-SUPPORTED
+  
+  
+! CHECK: "{{.*}}/flang-new" "-fc1"
+! CHECK-SAME: "-mlarge-data-threshold=32768"
+! CHECK-59000: "{{.*}}/flang-new" "-fc1"
+! CHECK-59000-SAME: "-mlarge-data-threshold=59000"
+! CHECK-1M: "{{.*}}/flang-new" "-fc1"
+! CHECK-1M-SAME: "-mlarge-data-threshold=1048576"
+! NO-MCMODEL: 'mlarge-data-threshold=' only applies to medium and large code models
+! INVALID: error: invalid value 'nonsense' in '-mlarge-data-threshold='
+! NOT-SUPPORTED: error: unsupported option '-mlarge-data-threshold=' for target 'aarch64'

>From af77a86ecc2d2895b51887cc4705aaec768a765c Mon Sep 17 00:00:00 2001
From: Mats Petersson <mats.petersson at arm.com>
Date: Fri, 28 Jun 2024 21:26:32 +0100
Subject: [PATCH 3/5] Make everything work

---
 .../include/flang/Frontend/CodeGenOptions.def |  1 -
 flang/include/flang/Frontend/CodeGenOptions.h |  5 +++++
 flang/lib/Frontend/CodeGenOptions.cpp         | 11 ++++++++++
 flang/lib/Frontend/CompilerInstance.cpp       | 10 ++++++++-
 flang/lib/Frontend/CompilerInvocation.cpp     | 11 ++--------
 flang/lib/Frontend/FrontendActions.cpp        | 12 +++++++++--
 flang/test/Lower/large-data-threshold.f90     | 21 +++++++++++++++++++
 7 files changed, 58 insertions(+), 13 deletions(-)
 create mode 100644 flang/test/Lower/large-data-threshold.f90

diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def
index 5d364e6655b99..9d03ec88a56b8 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.def
+++ b/flang/include/flang/Frontend/CodeGenOptions.def
@@ -39,7 +39,6 @@ ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///<
 ENUM_CODEGENOPT(DebugInfo,  llvm::codegenoptions::DebugInfoKind, 4,  llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate
 ENUM_CODEGENOPT(VecLib, llvm::driver::VectorLibrary, 3, llvm::driver::VectorLibrary::NoLibrary) ///< Vector functions library to use
 ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 2, llvm::FramePointerKind::None) ///< Enable the usage of frame pointers
-ENUM_CODEGENOPT(CodeModel, llvm::CodeModel::Model, 5, llvm::CodeModel::Model::Small)
 
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h
index 5cba2deb91ffb..d8a806b44a821 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.h
+++ b/flang/include/flang/Frontend/CodeGenOptions.h
@@ -129,6 +129,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// transformation.
   OptRemark OptimizationRemarkAnalysis;
 
+  /// The code model to use (-mcmodel).
+  std::string CodeModel;
+
   /// The code model-specific large data threshold to use
   /// (-mlarge-data-threshold).
   uint64_t LargeDataThreshold;
@@ -143,6 +146,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
   CodeGenOptions();
 };
 
+std::optional<llvm::CodeModel::Model> getCodeModel(llvm::StringRef string);
+
 } // end namespace Fortran::frontend
 
 #endif // FORTRAN_FRONTEND_CODEGENOPTIONS_H
diff --git a/flang/lib/Frontend/CodeGenOptions.cpp b/flang/lib/Frontend/CodeGenOptions.cpp
index a7947182decce..8a9d3c27c8bc3 100644
--- a/flang/lib/Frontend/CodeGenOptions.cpp
+++ b/flang/lib/Frontend/CodeGenOptions.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/CodeGenOptions.h"
+#include <optional>
 #include <string.h>
 
 namespace Fortran::frontend {
@@ -21,4 +22,14 @@ CodeGenOptions::CodeGenOptions() {
 #include "flang/Frontend/CodeGenOptions.def"
 }
 
+std::optional<llvm::CodeModel::Model> getCodeModel(llvm::StringRef string) {
+  return llvm::StringSwitch<std::optional<llvm::CodeModel::Model>>(string)
+      .Case("tiny", llvm::CodeModel::Model::Tiny)
+      .Case("small", llvm::CodeModel::Model::Small)
+      .Case("kernel", llvm::CodeModel::Model::Kernel)
+      .Case("medium", llvm::CodeModel::Model::Medium)
+      .Case("large", llvm::CodeModel::Model::Large)
+      .Default(std::nullopt);
+}
+
 } // end namespace Fortran::frontend
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index c78137346640a..27c36b7f84d89 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -321,11 +321,19 @@ bool CompilerInstance::setUpTargetMachine() {
   assert(OptLevelOrNone && "Invalid optimization level!");
   llvm::CodeGenOptLevel OptLevel = *OptLevelOrNone;
   std::string featuresStr = getTargetFeatures();
+  std::optional<llvm::CodeModel::Model> cm = getCodeModel(CGOpts.CodeModel);
   targetMachine.reset(theTarget->createTargetMachine(
       theTriple, /*CPU=*/targetOpts.cpu,
       /*Features=*/featuresStr, llvm::TargetOptions(),
       /*Reloc::Model=*/CGOpts.getRelocationModel(),
-      /*CodeModel::Model=*/std::nullopt, OptLevel));
+      /*CodeModel::Model=*/cm, OptLevel));
   assert(targetMachine && "Failed to create TargetMachine");
+  if (cm.has_value()) {
+    const llvm::Triple triple(theTriple);
+    if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) &&
+        triple.getArch() == llvm::Triple::x86_64) {
+      targetMachine->setLargeDataThreshold(CGOpts.LargeDataThreshold);
+    }
+  }
   return true;
 }
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index e9281672e7269..2fd2ac3244a17 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -386,17 +386,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
   if (const llvm::opt::Arg *a =
           args.getLastArg(clang::driver::options::OPT_mcmodel_EQ)) {
     llvm::StringRef modelName = a->getValue();
-    auto codeModel =
-        llvm::StringSwitch<std::optional<llvm::CodeModel::Model>>(modelName)
-            .Case("tiny", llvm::CodeModel::Model::Tiny)
-            .Case("small", llvm::CodeModel::Model::Small)
-            .Case("kernel", llvm::CodeModel::Model::Kernel)
-            .Case("medium", llvm::CodeModel::Model::Medium)
-            .Case("large", llvm::CodeModel::Model::Large)
-            .Default(std::nullopt);
+    std::optional<llvm::CodeModel::Model> codeModel = getCodeModel(modelName);
 
     if (codeModel.has_value())
-      opts.setCodeModel(*codeModel);
+      opts.CodeModel = modelName;
     else
       diags.Report(clang::diag::err_drv_invalid_value)
           << a->getAsString(args) << modelName;
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index e45e9ece7adb0..23f92b6c3a4ea 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -863,8 +863,15 @@ void CodeGenAction::generateLLVMIR() {
   }
 
   // Set mcmodel level LLVM module flags
-  llvmModule->setCodeModel(opts.getCodeModel());
-  llvmModule->setLargeDataThreshold(opts.LargeDataThreshold);
+  std::optional<llvm::CodeModel::Model> cm = getCodeModel(opts.CodeModel);
+  if (cm.has_value()) {
+    const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple);
+    llvmModule->setCodeModel(*cm);
+    if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) &&
+        triple.getArch() == llvm::Triple::x86_64) {
+      llvmModule->setLargeDataThreshold(opts.LargeDataThreshold);
+    }
+  }
 }
 
 static std::unique_ptr<llvm::raw_pwrite_stream>
@@ -1229,6 +1236,7 @@ void CodeGenAction::executeAction() {
   // and the command-line target option if specified, or the default if not
   // given on the command-line).
   llvm::TargetMachine &targetMachine = ci.getTargetMachine();
+
   const std::string &theTriple = targetMachine.getTargetTriple().str();
 
   if (llvmModule->getTargetTriple() != theTriple) {
diff --git a/flang/test/Lower/large-data-threshold.f90 b/flang/test/Lower/large-data-threshold.f90
new file mode 100644
index 0000000000000..51ddd429d770a
--- /dev/null
+++ b/flang/test/Lower/large-data-threshold.f90
@@ -0,0 +1,21 @@
+! REQUIRES: x86-registered-target
+
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - -mcmodel=medium | FileCheck %s --check-prefix=IR-DEFAULT
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - -mcmodel=medium -mlarge-data-threshold=200 | FileCheck %s --check-prefix=IR-CUSTOM
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - -mcmodel=large -mlarge-data-threshold=200 | FileCheck %s --check-prefix=IR-CUSTOM
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - -mcmodel=small -mlarge-data-threshold=200 | FileCheck %s --check-prefix=IR-SMALL
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=200 | FileCheck %s --check-prefix=ASM-SMALL
+! RUN: %flang_fc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=2 | FileCheck %s --check-prefix=ASM-LARGE
+
+! IR-DEFAULT: !{i32 1, !"Large Data Threshold", i64 0}
+! IR-CUSTOM: !{i32 1, !"Large Data Threshold", i64 200}
+! IR-SMALL-NOT: !"Large Data Threshold"
+
+! ASM-SMALL-NOT: movabsq
+! ASM-LARGE: movabsq
+
+function f
+  integer :: f
+  integer, save :: i
+  f = i
+end function f

>From eaad187a5e1372cc34f79f36ca5d28016a94b221 Mon Sep 17 00:00:00 2001
From: Mats Petersson <mats.petersson at arm.com>
Date: Mon, 1 Jul 2024 13:35:32 +0100
Subject: [PATCH 4/5] Don't check for path separator in Driver test

---
 flang/test/Driver/large-data-threshold.f90 | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/test/Driver/large-data-threshold.f90 b/flang/test/Driver/large-data-threshold.f90
index ac6f78713f62c..320566c4b2e43 100644
--- a/flang/test/Driver/large-data-threshold.f90
+++ b/flang/test/Driver/large-data-threshold.f90
@@ -7,11 +7,11 @@
 ! RUN: not %flang -### -c --target=aarch64 -mcmodel=small -mlarge-data-threshold=32768 %s 2>&1 | FileCheck %s --check-prefix=NOT-SUPPORTED
   
   
-! CHECK: "{{.*}}/flang-new" "-fc1"
+! CHECK: "{{.*}}flang-new" "-fc1"
 ! CHECK-SAME: "-mlarge-data-threshold=32768"
-! CHECK-59000: "{{.*}}/flang-new" "-fc1"
+! CHECK-59000: "{{.*}}flang-new" "-fc1"
 ! CHECK-59000-SAME: "-mlarge-data-threshold=59000"
-! CHECK-1M: "{{.*}}/flang-new" "-fc1"
+! CHECK-1M: "{{.*}}flang-new" "-fc1"
 ! CHECK-1M-SAME: "-mlarge-data-threshold=1048576"
 ! NO-MCMODEL: 'mlarge-data-threshold=' only applies to medium and large code models
 ! INVALID: error: invalid value 'nonsense' in '-mlarge-data-threshold='

>From 86968c65030361f1c0df2e152612fb840b3e3933 Mon Sep 17 00:00:00 2001
From: Mats Petersson <mats.petersson at arm.com>
Date: Mon, 1 Jul 2024 15:27:27 +0100
Subject: [PATCH 5/5] Fix formatting

---
 flang/lib/Frontend/CompilerInvocation.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 2fd2ac3244a17..eddfa5029de3c 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -395,15 +395,16 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
           << a->getAsString(args) << modelName;
   }
 
-  if (const llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_mlarge_data_threshold_EQ)) {
+  if (const llvm::opt::Arg *arg = args.getLastArg(
+          clang::driver::options::OPT_mlarge_data_threshold_EQ)) {
     uint64_t LDT;
     if (llvm::StringRef(arg->getValue()).getAsInteger(/*Radix=*/10, LDT)) {
       diags.Report(clang::diag::err_drv_invalid_value)
           << arg->getSpelling() << arg->getValue();
-    }      
+    }
     opts.LargeDataThreshold = LDT;
   }
-  
+
   // This option is compatible with -f[no-]underscoring in gfortran.
   if (args.hasFlag(clang::driver::options::OPT_fno_underscoring,
                    clang::driver::options::OPT_funderscoring, false)) {



More information about the flang-commits mailing list