MaskRay created this revision. MaskRay added reviewers: jyknight, pcc, phosek. Herald added subscribers: llvm-commits, cfe-commits, dang, steven.zhang, atanasyan, hiraditya, arichardson, sdardis. Herald added a reviewer: rengolin. Herald added projects: clang, LLVM. MaskRay requested review of this revision.
There are two use cases. Assembler We have accrued some code gated on MCAsmInfo::useIntegratedAssembler(). Some features are supported by latest GNU as, but we have to use MCAsmInfo::useIntegratedAs() because the newer versions have not been widely adopted (e.g. SHF_LINK_ORDER 'o' and 'unique' linkage in 2.35, --compress-debug-sections= in 2.26). Linker We want to use features supported only by LLD or very new GNU ld, or don't want to work around older GNU ld. We currently can't represent that "we don't care about old GNU ld". You can find such workarounds in a few other places, e.g. Mips/MipsAsmprinter.cpp PowerPC/PPCTOCRegDeps.cpp X86/X86MCInstrLower.cpp Fuchsia has an immediate use case for mixed SHF_LINK_ORDER and non-SHF_LINK_ORDER components (D76802 <https://reviews.llvm.org/D76802>; will be supported by LLD in D84001 <https://reviews.llvm.org/D84001>; GNU ld feature request https://sourceware.org/bugzilla/show_bug.cgi?id=16833 is pending). This patch adds -fbinutils-version= to clang and -binutils-version to llc. It changes one codegen place in SHF_MERGE to demonstrate its usage. -fbinutils-version=2.35 means the produced object file does not care about GNU ld<2.35 compatibility. When -fno-integrated-as is specified, the produced assembly does not care about GNU as<2.35 compatibility. -fbinutils-version=future means that we can freely use unimplemented GNU as/ld features. Such command line parsing is usually implemented in llvm/lib/CodeGen/CommandFlags.cpp (LLVMCodeGen), however, ClangCodeGen does not depend on LLVMCodeGen. So I add parseBinutilsVersion to llvm/lib/Target/TargetMachine.cpp (LLVMTarget). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D85474 Files: clang/include/clang/Basic/CodeGenOptions.h clang/include/clang/Driver/Options.td clang/lib/CodeGen/BackendUtil.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Frontend/CompilerInvocation.cpp llvm/include/llvm/MC/MCAsmInfo.h llvm/include/llvm/Target/TargetMachine.h llvm/include/llvm/Target/TargetOptions.h llvm/lib/CodeGen/LLVMTargetMachine.cpp llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp llvm/lib/Target/TargetMachine.cpp llvm/test/CodeGen/X86/explicit-section-mergeable.ll llvm/tools/llc/llc.cpp
Index: llvm/tools/llc/llc.cpp =================================================================== --- llvm/tools/llc/llc.cpp +++ llvm/tools/llc/llc.cpp @@ -81,6 +81,14 @@ cl::value_desc("N"), cl::desc("Repeat compilation N times for timing")); +static cl::opt<std::string> BinutilsVersion( + "binutils-version", cl::Hidden, + cl::desc( + "Used ELF features need to be supported by GNU ld " + "from the specified binutils version. 'future' means that " + "features not implemented by any known release can be used. If " + "-no-integrated-as is specified, this also affects assembly output")); + static cl::opt<bool> NoIntegratedAssembler("no-integrated-as", cl::Hidden, cl::desc("Disable integrated assembler")); @@ -425,6 +433,8 @@ } TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(); + Options.BinutilsVersion = + TargetMachine::parseBinutilsVersion(BinutilsVersion); Options.DisableIntegratedAS = NoIntegratedAssembler; Options.MCOptions.ShowMCEncoding = ShowMCEncoding; Options.MCOptions.MCUseDwarfDirectory = EnableDwarfDirectory; Index: llvm/test/CodeGen/X86/explicit-section-mergeable.ll =================================================================== --- llvm/test/CodeGen/X86/explicit-section-mergeable.ll +++ llvm/test/CodeGen/X86/explicit-section-mergeable.ll @@ -282,15 +282,19 @@ ;; --no-integrated-as avoids the use of ",unique," for compatibility with older binutils. ;; Error if an incompatible symbol is explicitly placed into a mergeable section. -; RUN: not llc < %s -mtriple=x86_64 --no-integrated-as 2>&1 \ +; RUN: not llc < %s -mtriple=x86_64 --no-integrated-as -binutils-version=2.34 2>&1 \ ; RUN: | FileCheck %s --check-prefix=NO-I-AS-ERR ; NO-I-AS-ERR: error: Symbol 'explicit_default_1' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.cst16' with entry-size=16: Explicit assignment by pragma or attribute of an incompatible symbol to this section? ; NO-I-AS-ERR: error: Symbol 'explicit_default_4' from module '<stdin>' required a section with entry-size=0 but was placed in section '.debug_str' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section? ; NO-I-AS-ERR: error: Symbol 'explicit_implicit_2' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.str1.1' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section? ; NO-I-AS-ERR: error: Symbol 'explicit_implicit_4' from module '<stdin>' required a section with entry-size=0 but was placed in section '.rodata.str1.1' with entry-size=1: Explicit assignment by pragma or attribute of an incompatible symbol to this section? +;; For GNU as before 2.35, ;; Don't create mergeable sections for globals with an explicit section name. ; RUN: echo '@explicit = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit"' > %t.no_i_as.ll -; RUN: llc < %t.no_i_as.ll -mtriple=x86_64 --no-integrated-as 2>&1 \ -; RUN: | FileCheck %s --check-prefix=NO-I-AS -; NO-I-AS: .section .explicit,"a",@progbits +; RUN: llc < %t.no_i_as.ll -mtriple=x86_64 --no-integrated-as -binutils-version=2.34 2>&1 \ +; RUN: | FileCheck %s --check-prefix=NO-I-AS-OLD +; NO-I-AS-OLD: .section .explicit,"a",@progbits +; RUN: llc < %t.no_i_as.ll -mtriple=x86_64 --no-integrated-as -binutils-version=2.35 2>&1 \ +; RUN: | FileCheck %s --check-prefix=NO-I-AS-NEW +; NO-I-AS-NEW: .section .explicit,"aM",@progbits,4,unique,1 Index: llvm/lib/Target/TargetMachine.cpp =================================================================== --- llvm/lib/Target/TargetMachine.cpp +++ llvm/lib/Target/TargetMachine.cpp @@ -281,3 +281,12 @@ return TargetIRAnalysis( [this](const Function &F) { return this->getTargetTransformInfo(F); }); } + +std::pair<int, int> TargetMachine::parseBinutilsVersion(StringRef Version) { + if (Version == "future") + return {(int)TargetOptions::FutureBinutilsVersion, 0}; + std::pair<int, int> Ret; + if (!Version.consumeInteger(10, Ret.first) && Version.consume_front(".")) + Version.consumeInteger(10, Ret.second); + return Ret; +} Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -684,7 +684,7 @@ UniqueID = NextUniqueID++; Flags |= ELF::SHF_LINK_ORDER; } else { - if (getContext().getAsmInfo()->useIntegratedAssembler()) { + if (getContext().getAsmInfo()->useIntegratedASOrGAS(2, 35)) { // Symbols must be placed into sections with compatible entry // sizes. Generate unique sections for symbols that have not // been assigned to compatible sections. @@ -735,8 +735,8 @@ assert(Section->getLinkedToSymbol() == LinkedToSym && "Associated symbol mismatch between sections"); - if (!getContext().getAsmInfo()->useIntegratedAssembler()) { - // If we are not using the integrated assembler then this symbol might have + if (!getContext().getAsmInfo()->useIntegratedASOrGAS(2, 35)) { + // If we are using GNU as before 2.35, then this symbol might have // been placed in an incompatible mergeable section. Emit an error if this // is the case to avoid creating broken output. if ((Section->getFlags() & ELF::SHF_MERGE) && Index: llvm/lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- llvm/lib/CodeGen/LLVMTargetMachine.cpp +++ llvm/lib/CodeGen/LLVMTargetMachine.cpp @@ -58,6 +58,9 @@ "Make sure you include the correct TargetSelect.h" "and that InitializeAllTargetMCs() is being invoked!"); + if (Options.BinutilsVersion.first > 0) + TmpAsmInfo->setBinutilsVersion(Options.BinutilsVersion); + if (Options.DisableIntegratedAS) TmpAsmInfo->setUseIntegratedAssembler(false); Index: llvm/include/llvm/Target/TargetOptions.h =================================================================== --- llvm/include/llvm/Target/TargetOptions.h +++ llvm/include/llvm/Target/TargetOptions.h @@ -134,6 +134,9 @@ /// optimization should be disabled for the given machine function. bool DisableFramePointerElim(const MachineFunction &MF) const; + enum { FutureBinutilsVersion = 99 }; + std::pair<int, int> BinutilsVersion{0, 0}; + /// UnsafeFPMath - This flag is enabled when the /// -enable-unsafe-fp-math flag is specified on the command line. When /// this flag is off (the default), the code generator is not allowed to Index: llvm/include/llvm/Target/TargetMachine.h =================================================================== --- llvm/include/llvm/Target/TargetMachine.h +++ llvm/include/llvm/Target/TargetMachine.h @@ -332,6 +332,8 @@ /// The integer bit size to use for SjLj based exception handling. static constexpr unsigned DefaultSjLjDataSize = 32; virtual unsigned getSjLjDataSize() const { return DefaultSjLjDataSize; } + + static std::pair<int, int> parseBinutilsVersion(StringRef Version); }; /// This class describes a target machine that is implemented with the LLVM Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -384,6 +384,10 @@ //===--- Integrated Assembler Information ----------------------------===// + // Generated object files can only use features support by GNU ld of this + // binutils version. + std::pair<int, int> BinutilsVersion = {2, 26}; + /// Should we use the integrated assembler? /// The integrated assembler should be enabled by default (by the /// constructors) when failing to parse a valid piece of assembly (inline @@ -649,9 +653,18 @@ return InitialFrameState; } + void setBinutilsVersion(std::pair<int, int> Value) { + BinutilsVersion = Value; + } + /// Return true if assembly (inline or otherwise) should be parsed. bool useIntegratedAssembler() const { return UseIntegratedAssembler; } + bool useIntegratedASOrGAS(int Major, int Minor) const { + return UseIntegratedAssembler || + BinutilsVersion >= std::make_pair(Major, Minor); + } + /// Set whether assembly (inline or otherwise) should be parsed. virtual void setUseIntegratedAssembler(bool Value) { UseIntegratedAssembler = Value; Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -859,6 +859,8 @@ (Opts.OptimizationLevel > 1)); Opts.RerollLoops = Args.hasArg(OPT_freroll_loops); + Opts.BinutilsVersion = + std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ)); Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as); Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.SampleProfileFile = Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4635,6 +4635,21 @@ IsIntegratedAssemblerDefault)) CmdArgs.push_back("-fno-verbose-asm"); + // Parse 'future' or '$major.$minor'. + if (Arg *A = Args.getLastArg(options::OPT_fbinutils_version_EQ)) { + StringRef V = A->getValue(); + int Num; + if (V == "future") + A->render(Args, CmdArgs); + else if (!V.consumeInteger(10, Num) && + (V.empty() || (V.consume_front(".") && + !V.consumeInteger(10, Num) && V.empty()))) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_invalid_argument_to_option) + << A->getValue() << A->getOption().getName(); + } + if (!TC.useIntegratedAs()) CmdArgs.push_back("-no-integrated-as"); Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -464,6 +464,8 @@ break; } + Options.BinutilsVersion = + llvm::TargetMachine::parseBinutilsVersion(CodeGenOpts.BinutilsVersion); Options.UseInitArray = CodeGenOpts.UseInitArray; Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS; Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections(); Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -3304,6 +3304,10 @@ def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<f_Group>; +def fbinutils_version_EQ : Joined<["-"], "fbinutils-version=">, Group<f_Group>, + HelpText<"Produced object files can use ELF features only supported by ld newer than the specified version. If" + "-fno-integrated-as is specified, produced assembly can use newer ELF features. " + "'future' means that features not implemented by any known release can be used">; def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>, Flags<[CoreOption, LinkOption]>; def ld_path_EQ : Joined<["--"], "ld-path=">, Group<Link_Group>; Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -126,6 +126,11 @@ // "none": Disable sections/labels for basic blocks. std::string BBSections; + // If set, overwrite the default value of MCAsmInfo::BinutilsVersion. "future" + // means that features not implemented by any known release can be used. If + // DisableIntegratedAS is specified, this also affects assembly output. + std::string BinutilsVersion; + enum class FramePointerKind { None, // Omit all frame pointers. NonLeaf, // Keep non-leaf frame pointers.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits