diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -2953,6 +2953,10 @@ Enable linker relaxation +.. option:: -msmall-data-limit= + +Put global and static data smaller than the limitation into a special section (RISCV only) + Optimization level ~~~~~~~~~~~~~~~~~~ diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -307,6 +307,9 @@ /// or 0 if unspecified. VALUE_CODEGENOPT(NumRegisterParameters, 32, 0) +/// The threshold to put data into small data section. +VALUE_CODEGENOPT(SmallDataLimit, 32, 0) + /// The lower bound for a buffer to be considered for stack protection. VALUE_CODEGENOPT(SSPBufferSize, 32, 0) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -399,6 +399,12 @@ "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" " usage of }0-mabicalls">, InGroup; +def warn_drv_unsupported_g : Warning< + "ignoring '-G' option as -msmall-data-limit= in the command line">, + InGroup; +def warn_drv_unsupported_sdata : Warning< + "ignoring '-msmall-data-limit=' for -fpic or RV64 with -mcmodel=large">, + InGroup; def warn_drv_unsupported_longcalls : Warning< "ignoring '-mlong-calls' option as it is not currently supported with " "%select{|the implicit usage of }0-mabicalls">, diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -313,6 +313,8 @@ HelpText<"Do not put zero initialized data in the BSS">; def mregparm : Separate<["-"], "mregparm">, HelpText<"Limit the number of registers available for integer arguments">; +def msmall_data_limit : Separate<["-"], "msmall-data-limit">, + HelpText<"Put global and static data smaller than the limitation into a special section">; def munwind_tables : Flag<["-"], "munwind-tables">, HelpText<"Generate unwinding tables for all functions">; def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">, 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 @@ -2298,6 +2298,8 @@ HelpText<"Enable linker relaxation">; def mno_relax : Flag<["-"], "mno-relax">, Group, HelpText<"Disable linker relaxation">; +def msmall_data_limit_EQ : Joined<["-"], "msmall-data-limit=">, Group, + HelpText<"Put global and static data smaller than the limitation into a special section">; def msave_restore : Flag<["-"], "msave-restore">, Group, HelpText<"Enable using library calls for save and restore">; def mno_save_restore : Flag<["-"], "mno-save-restore">, Group, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1515,6 +1515,10 @@ /// Emits target specific Metadata for global declarations. void EmitTargetMetadata(); + /// Emit the module flag metadata used to pass options controlling the + /// the backend to LLVM. + void EmitBackendOptionsMetadata(const CodeGenOptions CodeGenOpts); + /// Emits OpenCL specific Metadata e.g. OpenCL version. void EmitOpenCLMetadata(); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -659,6 +659,8 @@ EmitCommandLineMetadata(); EmitTargetMetadata(); + + EmitBackendOptionsMetadata(getCodeGenOpts()); } void CodeGenModule::EmitOpenCLMetadata() { @@ -678,6 +680,17 @@ OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts)); } +void CodeGenModule::EmitBackendOptionsMetadata(const CodeGenOptions CodeGenOpts) { + switch (getTriple().getArch()) { + default: break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + getModule().addModuleFlag(llvm::Module::ModFlagBehaviorFirstVal, + "SmallDataLimit", CodeGenOpts.SmallDataLimit); + break; + } +} + void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. Types.UpdateCompletedType(TD); 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 @@ -1960,6 +1960,42 @@ } } +static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + const Driver &D = TC.getDriver(); + const llvm::Triple &Triple = TC.getTriple(); + // Default small data limitation is eight. + const char *SmallDataLimit = "8"; + // Get small data limitation. + if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, + options::OPT_fPIC)) { + // Not support linker relaxation for PIC. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_msmall_data_limit_EQ)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } + } else if (Args.getLastArgValue(options::OPT_mcmodel_EQ) + .equals_lower("large") && + (Triple.getArch() == llvm::Triple::riscv64)) { + // Not support linker relaxation for RV64 with large code model. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_msmall_data_limit_EQ)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } + } else if (Arg *A = Args.getLastArg(options::OPT_msmall_data_limit_EQ)) { + SmallDataLimit = A->getValue(); + // Ignore -G because -msmall-data-limit= has higher priority. + if (Args.hasArg(options::OPT_G)) { + D.Diag(diag::warn_drv_unsupported_g); + } + } else if (Arg *A = Args.getLastArg(options::OPT_G)) { + SmallDataLimit = A->getValue(); + } + // Forward the -msmall-data-limit= option. + CmdArgs.push_back("-msmall-data-limit"); + CmdArgs.push_back(SmallDataLimit); +} + void Clang::AddRISCVTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getTriple(); @@ -1967,6 +2003,8 @@ CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); + + SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); } void Clang::AddSparcTargetArgs(const ArgList &Args, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -923,6 +923,8 @@ Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); + Opts.SmallDataLimit = + getLastArgIntValue(Args, OPT_msmall_data_limit, 0, Diags); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn); Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks); diff --git a/clang/test/CodeGen/riscv-sdata-module-flag.c b/clang/test/CodeGen/riscv-sdata-module-flag.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/riscv-sdata-module-flag.c @@ -0,0 +1,31 @@ +// RUN: %clang -target riscv32-unknown-elf %s -S -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=RV32-DEFAULT +// RUN: %clang -target riscv32-unknown-elf %s -S -emit-llvm -G4 -o - \ +// RUN: | FileCheck %s -check-prefix=RV32-G4 +// RUN: %clang -target riscv32-unknown-elf %s -S -emit-llvm -msmall-data-limit=0 -o - \ +// RUN: | FileCheck %s -check-prefix=RV32-S0 +// RUN: %clang -target riscv32-unknown-elf %s -S -emit-llvm -fpic -o - \ +// RUN: | FileCheck %s -check-prefix=RV32-PIC + +// RUN: %clang -target riscv64-unknown-elf %s -S -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=RV64-DEFAULT +// RUN: %clang -target riscv64-unknown-elf %s -S -emit-llvm -G4 -o - \ +// RUN: | FileCheck %s -check-prefix=RV64-G4 +// RUN: %clang -target riscv64-unknown-elf %s -S -emit-llvm -msmall-data-limit=0 -o - \ +// RUN: | FileCheck %s -check-prefix=RV64-S0 +// RUN: %clang -target riscv64-unknown-elf %s -S -emit-llvm -fpic -o - \ +// RUN: | FileCheck %s -check-prefix=RV64-PIC +// RUN: %clang -target riscv64-unknown-elf %s -S -emit-llvm -mcmodel=large -o - \ +// RUN: | FileCheck %s -check-prefix=RV64-LARGE + + +// RV32-DEFAULT: !{i32 1, !"SmallDataLimit", i32 8} +// RV32-G4: !{i32 1, !"SmallDataLimit", i32 4} +// RV32-S0: !{i32 1, !"SmallDataLimit", i32 0} +// RV32-PIC: !{i32 1, !"SmallDataLimit", i32 0} + +// RV64-DEFAULT: !{i32 1, !"SmallDataLimit", i32 8} +// RV64-G4: !{i32 1, !"SmallDataLimit", i32 4} +// RV64-S0: !{i32 1, !"SmallDataLimit", i32 0} +// RV64-PIC: !{i32 1, !"SmallDataLimit", i32 0} +// RV64-LARGE: !{i32 1, !"SmallDataLimit", i32 0} diff --git a/clang/test/Driver/riscv-G-warning.c b/clang/test/Driver/riscv-G-warning.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/riscv-G-warning.c @@ -0,0 +1,4 @@ +// REQUIRES: riscv-registered-target +// RUN: %clang -S -target riscv32-unknown-elf -G4 -msmall-data-limit=8 %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-G %s +// CHECK-G: warning: ignoring '-G' option as -msmall-data-limit= in the command line diff --git a/clang/test/Driver/riscv-sdata-warning.c b/clang/test/Driver/riscv-sdata-warning.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/riscv-sdata-warning.c @@ -0,0 +1,8 @@ +// REQUIRES: riscv-registered-target +// RUN: %clang -S -target riscv32-unknown-elf -fpic -msmall-data-limit=8 %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-PIC-SDATA %s +// CHECK-PIC-SDATA: warning: ignoring '-msmall-data-limit=' for -fpic or RV64 with -mcmodel=large + +// RUN: %clang -S -target riscv64-unknown-elf -mcmodel=large -msmall-data-limit=8 %s 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-RV64-LARGE-SDATA %s +// CHECK-RV64-LARGE-SDATA: warning: ignoring '-msmall-data-limit=' for -fpic or RV64 with -mcmodel=large