diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5240,6 +5240,16 @@ // CodeGen Options //===----------------------------------------------------------------------===// +let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] in { + +def mrelocation_model : Separate<["-"], "mrelocation-model">, + HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">, + NormalizedValuesScope<"llvm::Reloc">, + NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>, + MarshallingInfoEnum, "PIC_">; + +} // let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] + let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; @@ -5284,11 +5294,6 @@ "Note this may change .s semantics and shouldn't generally be used " "on compiler-generated code.">, MarshallingInfoFlag>; -def mrelocation_model : Separate<["-"], "mrelocation-model">, - HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">, - NormalizedValuesScope<"llvm::Reloc">, - NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>, - MarshallingInfoEnum, "PIC_">; def fno_math_builtin : Flag<["-"], "fno-math-builtin">, HelpText<"Disable implicit builtin knowledge of math functions">, MarshallingInfoFlag>; @@ -5973,6 +5978,17 @@ Flags<[CC1Option, CC1AsOption, NoDriverOption]>, MarshallingInfoString>; +let Flags = [CC1Option, FC1Option, NoDriverOption] in { + +def pic_level : Separate<["-"], "pic-level">, + HelpText<"Value for __PIC__">, + MarshallingInfoInt>; +def pic_is_pie : Flag<["-"], "pic-is-pie">, + HelpText<"File is for a position independent executable">, + MarshallingInfoFlag>; + +} // let Flags = [CC1Option, FC1Option, NoDriverOption] + let Flags = [CC1Option, NoDriverOption] in { def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">, @@ -6013,12 +6029,6 @@ def function_alignment : Separate<["-"], "function-alignment">, HelpText<"default alignment for functions">, MarshallingInfoInt>; -def pic_level : Separate<["-"], "pic-level">, - HelpText<"Value for __PIC__">, - MarshallingInfoInt>; -def pic_is_pie : Flag<["-"], "pic-is-pie">, - HelpText<"File is for a position independent executable">, - MarshallingInfoFlag>; def fhalf_no_semantic_interposition : Flag<["-"], "fhalf-no-semantic-interposition">, HelpText<"Like -fno-semantic-interposition but don't use local aliases">, MarshallingInfoFlag>; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1152,23 +1152,6 @@ } } -static const char *RelocationModelName(llvm::Reloc::Model Model) { - switch (Model) { - case llvm::Reloc::Static: - return "static"; - case llvm::Reloc::PIC_: - return "pic"; - case llvm::Reloc::DynamicNoPIC: - return "dynamic-no-pic"; - case llvm::Reloc::ROPI: - return "ropi"; - case llvm::Reloc::RWPI: - return "rwpi"; - case llvm::Reloc::ROPI_RWPI: - return "ropi-rwpi"; - } - llvm_unreachable("Unknown Reloc::Model kind"); -} static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -93,6 +93,8 @@ llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO); +const char *RelocationModelName(llvm::Reloc::Model Model); + std::tuple ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1201,6 +1201,24 @@ options::OPT_fauto_profile_EQ); } +const char *tools::RelocationModelName(llvm::Reloc::Model Model) { + switch (Model) { + case llvm::Reloc::Static: + return "static"; + case llvm::Reloc::PIC_: + return "pic"; + case llvm::Reloc::DynamicNoPIC: + return "dynamic-no-pic"; + case llvm::Reloc::ROPI: + return "ropi"; + case llvm::Reloc::RWPI: + return "rwpi"; + case llvm::Reloc::ROPI_RWPI: + return "ropi-rwpi"; + } + llvm_unreachable("Unknown Reloc::Model kind"); +} + /// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, /// smooshes them together with platform defaults, to decide whether /// this compile should be using PIC mode or not. Returns a tuple of diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h --- a/clang/lib/Driver/ToolChains/Flang.h +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -39,6 +39,15 @@ /// \param [out] CmdArgs The list of output command arguments void AddPreprocessingOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract PIC options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddPicOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract other compilation options from the driver arguments and add them /// to the command arguments. /// diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -58,6 +58,27 @@ options::OPT_std_EQ, options::OPT_W_Joined}); } +void Flang::AddPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of + // (RelocationModel, PICLevel, IsPIE). + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + if (auto *RMName = RelocationModelName(RelocationModel)) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); + } + if (PICLevel > 0) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); + if (IsPIE) + CmdArgs.push_back("-pic-is-pie"); + } +} + void Flang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -117,6 +138,9 @@ if (D.getDiags().getDiagnosticOptions().ShowColors) CmdArgs.push_back("-fcolor-diagnostics"); + // -fPIC and related options. + AddPicOptions(Args, CmdArgs); + // Add other compile options AddOtherOptions(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -692,11 +692,8 @@ } bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const { - // TODO: Remove the special treatment for Flang once its frontend driver can - // generate position independent code. - return !getDriver().IsFlangMode() && - (CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || - getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE()); + return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || + getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE(); } bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -32,10 +32,12 @@ public: #define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits; +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) #include "flang/Frontend/CodeGenOptions.def" protected: #define CODEGENOPT(Name, Bits, Default) +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) unsigned Name : Bits; #include "flang/Frontend/CodeGenOptions.def" }; @@ -44,6 +46,13 @@ class CodeGenOptions : public CodeGenOptionsBase { public: + // Define accessors/mutators for code generation options of enumeration type. +#define CODEGENOPT(Name, Bits, Default) +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ + Type get##Name() const { return static_cast(Name); } \ + void set##Name(Type Value) { Name = static_cast(Value); } +#include "flang/Frontend/CodeGenOptions.def" + CodeGenOptions(); }; diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -14,9 +14,20 @@ # error Define the CODEGENOPT macro to handle language options #endif +#ifndef ENUM_CODEGENOPT +# define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ +CODEGENOPT(Name, Bits, Default) +#endif + CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new ///< pass manager. +CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. +CODEGENOPT(IsPIE, 1, 0) ///< PIE level is the same as PIC Level. + +ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< Name of the relocation model to use. + #undef CODEGENOPT +#undef ENUM_CODEGENOPT diff --git a/flang/lib/Frontend/CodeGenOptions.cpp b/flang/lib/Frontend/CodeGenOptions.cpp --- a/flang/lib/Frontend/CodeGenOptions.cpp +++ b/flang/lib/Frontend/CodeGenOptions.cpp @@ -17,6 +17,7 @@ CodeGenOptions::CodeGenOptions() { #define CODEGENOPT(Name, Bits, Default) Name = Default; +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default); #include "flang/Frontend/CodeGenOptions.def" } diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -124,6 +124,39 @@ if (args.hasFlag(clang::driver::options::OPT_fdebug_pass_manager, clang::driver::options::OPT_fno_debug_pass_manager, false)) opts.DebugPassManager = 1; + + // -mrelocation-model option. + if (const llvm::opt::Arg *A = + args.getLastArg(clang::driver::options::OPT_mrelocation_model)) { + llvm::StringRef ModelName = A->getValue(); + auto RM = llvm::StringSwitch>(ModelName) + .Case("static", llvm::Reloc::Static) + .Case("pic", llvm::Reloc::PIC_) + .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) + .Case("ropi", llvm::Reloc::ROPI) + .Case("rwpi", llvm::Reloc::RWPI) + .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) + .Default(llvm::None); + if (RM.has_value()) + opts.setRelocationModel(*RM); + else + diags.Report(clang::diag::err_drv_invalid_value) + << A->getAsString(args) << ModelName; + } + + // -pic-level and -pic-is-pie option. + if (int PICLevel = getLastArgIntValue( + args, clang::driver::options::OPT_pic_level, 0, diags)) { + if (PICLevel > 2) + diags.Report(clang::diag::err_drv_invalid_value) + << args.getLastArg(clang::driver::options::OPT_pic_level) + ->getAsString(args) + << PICLevel; + + opts.PICLevel = PICLevel; + if (args.hasArg(clang::driver::options::OPT_pic_is_pie)) + opts.IsPIE = 1; + } } /// Parses all target input arguments and populates the target diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -529,6 +529,14 @@ llvmModule = mlir::translateModuleToLLVMIR( *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); + // Set PIC/PIE level LLVM module flags. + if (opts.PICLevel > 0) { + llvmModule->setPICLevel(static_cast(opts.PICLevel)); + if (opts.IsPIE) + llvmModule->setPIELevel( + static_cast(opts.PICLevel)); + } + if (!llvmModule) { unsigned diagID = ci.getDiagnostics().getCustomDiagID( clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); @@ -571,11 +579,12 @@ assert(theTarget && "Failed to create Target"); // Create `TargetMachine` - llvm::CodeGenOpt::Level OptLevel = - getCGOptLevel(ci.getInvocation().getCodeGenOpts()); + const auto &CGOpts = ci.getInvocation().getCodeGenOpts(); + llvm::CodeGenOpt::Level OptLevel = getCGOptLevel(CGOpts); tm.reset(theTarget->createTargetMachine( theTriple, /*CPU=*/"", - /*Features=*/"", llvm::TargetOptions(), /*Reloc::Model=*/llvm::None, + /*Features=*/"", llvm::TargetOptions(), + /*Reloc::Model=*/CGOpts.getRelocationModel(), /*CodeModel::Model=*/llvm::None, OptLevel)); assert(tm && "Failed to create TargetMachine"); } diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -130,9 +130,13 @@ ! HELP-FC1-NEXT: -mmlir Additional arguments to forward to MLIR's option processing ! HELP-FC1-NEXT: -module-dir Put MODULE files in ! HELP-FC1-NEXT: -module-suffix Use as the suffix for module files (the default value is `.mod`) +! HELP-FC1-NEXT: -mrelocation-model +! HELP-FC1-NEXT: The relocation model to use ! HELP-FC1-NEXT: -nocpp Disable predefined and command line preprocessor macros ! HELP-FC1-NEXT: -o Write output to ! HELP-FC1-NEXT: -pedantic Warn on language extensions +! HELP-FC1-NEXT: -pic-is-pie File is for a position independent executable +! HELP-FC1-NEXT: -pic-level Value for __PIC__ ! HELP-FC1-NEXT: -plugin Use the named plugin action instead of the default action (use "help" to list available options) ! HELP-FC1-NEXT: -P Disable linemarker output in -E mode ! HELP-FC1-NEXT: -std= Language standard to compile for diff --git a/flang/test/Driver/pic-flags.f90 b/flang/test/Driver/pic-flags.f90 --- a/flang/test/Driver/pic-flags.f90 +++ b/flang/test/Driver/pic-flags.f90 @@ -1,18 +1,75 @@ -! Verify that in contrast to Clang, Flang does not default to generating position independent executables/code +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fno-pie 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-STATIC,CHECK-STATIC-IR -! RUN: %flang -### %s --target=aarch64-linux-gnu 2>&1 | FileCheck %s --check-prefix=CHECK-NOPIE -! RUN: %flang -### %s --target=aarch64-linux-gnu -fno-pie 2>&1 | FileCheck %s --check-prefix=CHECK-NOPIE +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL2,CHECK-PIE-LEVEL2-IR +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fpie 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL1,CHECK-PIE-LEVEL1-IR +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fPIE 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIE-LEVEL2,CHECK-PIE-LEVEL2-IR -! RUN: %flang -### %s --target=aarch64-linux-gnu -fpie 2>&1 | FileCheck %s --check-prefix=CHECK-PIE +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fpic 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIC-LEVEL1,CHECK-PIC-LEVEL1-IR +! RUN: %flang -v -S -emit-llvm -o - %s --target=aarch64-linux-gnu -fPIC 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PIC-LEVEL2,CHECK-PIC-LEVEL2-IR -! CHECK-NOPIE: "-fc1" -! CHECk-NOPIE-NOT: "-fpic" -! CHECK-NOPIE: "{{.*}}ld" -! CHECK-NOPIE-NOT: "-pie" +! RUN: %flang -v -### -o - %s --target=i386-apple-darwin -mdynamic-no-pic 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-DYNAMIC-NO-PIC-32 +! RUN: %flang -v -### -o - %s --target=x86_64-apple-darwin -mdynamic-no-pic 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-DYNAMIC-NO-PIC-64 -! CHECK-PIE: "-fc1" -!! TODO Once Flang supports `-fpie`, it //should// use -fpic when invoking `flang -fc1`. Update the following line once `-fpie` is -! available. -! CHECk-PIE-NOT: "-fpic" -! CHECK-PIE: "{{.*}}ld" -! CHECK-PIE-NOT: "-pie" +! RUN: %flang -v -### -o - %s --target=arm-none-eabi -fropi 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-ROPI +! RUN: %flang -v -### -o - %s --target=arm-none-eabi -frwpi 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-RWPI +! RUN: %flang -v -### -o - %s --target=arm-none-eabi -fropi -frwpi 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-ROPI-RWPI + + +! CHECK: -fc1 + + +!! -fno-pie. +! CHECK-STATIC: -mrelocation-model static +! CHECK-STATIC-NOT: -pic + +! CHECK-STATIC-IR-NOT: {{PIE|PIC}} Level + + +!! -fpic. +! CHECK-PIC-LEVEL1: -mrelocation-model pic -pic-level 1 +! CHECK-PIC-LEVEL1-NOT: -pic-is-pie + +! CHECK-PIC-LEVEL1-IR-NOT: "PIE Level" +! CHECK-PIC-LEVEL1-IR: !"PIC Level", i32 1} +! CHECK-PIC-LEVEL1-IR-NOT: "PIE Level" + + +!! -fPIC. +! CHECK-PIC-LEVEL2: -mrelocation-model pic -pic-level 2 +! CHECK-PIC-LEVEL2-NOT: -pic-is-pie + +! CHECK-PIC-LEVEL2-IR-NOT: "PIE Level" +! CHECK-PIC-LEVEL2-IR: !"PIC Level", i32 2} +! CHECK-PIC-LEVEL2-IR-NOT: "PIE Level" + + +!! -fpie. +! CHECK-PIE-LEVEL1: -mrelocation-model pic -pic-level 1 -pic-is-pie +! CHECK-PIE-LEVEL1-IR: !"PIC Level", i32 1} +! CHECK-PIE-LEVEL1-IR: !"PIE Level", i32 1} + + +!! -fPIE. +! CHECK-PIE-LEVEL2: -mrelocation-model pic -pic-level 2 -pic-is-pie +! CHECK-PIE-LEVEL2-IR: !"PIC Level", i32 2} +! CHECK-PIE-LEVEL2-IR: !"PIE Level", i32 2} + + +!! -mdynamic-no-pic +! CHECK-DYNAMIC-NO-PIC-32: "-mrelocation-model" "dynamic-no-pic" +! CHECK-DYNAMIC-NO-PIC-32-NOT: "-pic-level" +! CHECK-DYNAMIC-NO-PIC-32-NOT: "-pic-is-pie" + +! CHECK-DYNAMIC-NO-PIC-64: "-mrelocation-model" "dynamic-no-pic" "-pic-level" "2" +! CHECK-DYNAMIC-NO-PIC-64-NOT: "-pic-is-pie" + + +!! -fropi -frwpi +! CHECK-ROPI: "-mrelocation-model" "ropi" +! CHECK-ROPI-NOT: "-pic + +! CHECK-RWPI: "-mrelocation-model" "rwpi" +! CHECK-RWPI-NOT: "-pic + +! CHECK-ROPI-RWPI: "-mrelocation-model" "ropi-rwpi" +! CHECK-ROPI-RWPI-NOT: "-pic