diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -757,6 +757,12 @@ return true; } +static StringRef getAliasSpelling(llvm::opt::Arg *arg) { + if (const llvm::opt::Arg *alias = arg->getAlias()) + return alias->getSpelling(); + return arg->getSpelling(); +} + static std::pair getOldNewOptions(opt::InputArgList &args, unsigned id) { auto *arg = args.getLastArg(id); @@ -766,7 +772,7 @@ StringRef s = arg->getValue(); std::pair ret = s.split(';'); if (ret.second.empty()) - error(arg->getSpelling() + " expects 'old;new' format, but got " + s); + error(getAliasSpelling(arg) + " expects 'old;new' format, but got " + s); return ret; } @@ -858,7 +864,7 @@ config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); config->ltoo = args::getInteger(args, OPT_lto_O, 2); - config->ltoObjPath = args.getLastArgValue(OPT_plugin_opt_obj_path_eq); + config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq); config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); config->mapFile = args.getLastArgValue(OPT_Map); @@ -903,17 +909,15 @@ config->thinLTOCachePolicy = CHECK( parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); - config->thinLTOEmitImportsFiles = - args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); - config->thinLTOIndexOnly = args.hasArg(OPT_plugin_opt_thinlto_index_only) || - args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); - config->thinLTOIndexOnlyArg = - args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); + config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); + config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || + args.hasArg(OPT_thinlto_index_only_eq); + config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq); config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u); config->thinLTOObjectSuffixReplace = - getOldNewOptions(args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); + getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq); config->thinLTOPrefixReplace = - getOldNewOptions(args, OPT_plugin_opt_thinlto_prefix_replace_eq); + getOldNewOptions(args, OPT_thinlto_prefix_replace_eq); config->trace = args.hasArg(OPT_trace); config->undefined = args::getStrings(args, OPT_undefined); config->undefinedVersion = diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -481,6 +481,7 @@ HelpText<"Perform context senstive PGO instrumentation">; def lto_cs_profile_file: J<"lto-cs-profile-file=">, HelpText<"Context sensitive profile file path">; +def lto_obj_path_eq: J<"lto-obj-path=">; def lto_sample_profile: J<"lto-sample-profile=">, HelpText<"Sample profile file path">; def disable_verify: F<"disable-verify">; @@ -498,7 +499,12 @@ def thinlto_cache_dir: J<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">; +def thinlto_emit_imports_files: F<"thinlto-emit-imports-files">; +def thinlto_index_only: F<"thinlto-index-only">; +def thinlto_index_only_eq: J<"thinlto-index-only=">; def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; +def thinlto_object_suffix_replace_eq: J<"thinlto-object-suffix-replace=">; +def thinlto_prefix_replace_eq: J<"thinlto-prefix-replace=">; def: J<"plugin-opt=O">, Alias, HelpText<"Alias for -lto-O">; def: F<"plugin-opt=debug-pass-manager">, @@ -512,19 +518,31 @@ def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; def: F<"plugin-opt=new-pass-manager">, Alias, HelpText<"Alias for -lto-new-pass-manager">; -def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">; def: F<"plugin-opt=cs-profile-generate">, Alias, HelpText<"Alias for -lto-cs-profile-generate">; def: J<"plugin-opt=cs-profile-path=">, Alias, HelpText<"Alias for -lto-cs-profile-file">; +def: J<"plugin-opt=obj-path=">, + Alias, + HelpText<"Alias for -lto-obj-path=">; def: J<"plugin-opt=sample-profile=">, Alias, HelpText<"Alias for -lto-sample-profile">; def: F<"plugin-opt=save-temps">, Alias, HelpText<"Alias for -save-temps">; -def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">; -def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">; -def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">; -def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">; -def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">; +def: F<"plugin-opt=thinlto-emit-imports-files">, + Alias, + HelpText<"Alias for -thinlto-emit-imports-files">; +def: F<"plugin-opt=thinlto-index-only">, + Alias, + HelpText<"Alias for -thinlto-index-only">; +def: J<"plugin-opt=thinlto-index-only=">, + Alias, + HelpText<"Alias for -thinlto-index-only=">; +def: J<"plugin-opt=thinlto-object-suffix-replace=">, + Alias, + HelpText<"Alias for -thinlto-object-suffix-replace=">; +def: J<"plugin-opt=thinlto-prefix-replace=">, + Alias, + HelpText<"Alias for -thinlto-prefix-replace=">; // Ignore LTO plugin-related options. // clang -flto passes -plugin and -plugin-opt to the linker. This is required diff --git a/lld/test/ELF/lto/thinlto-emit-imports.ll b/lld/test/ELF/lto/thinlto-emit-imports.ll --- a/lld/test/ELF/lto/thinlto-emit-imports.ll +++ b/lld/test/ELF/lto/thinlto-emit-imports.ll @@ -14,15 +14,15 @@ ; The imports file for this module contains the bitcode file for ; Inputs/thinlto.ll -; RUN: cat %t1.o.imports | count 1 -; RUN: cat %t1.o.imports | FileCheck %s --check-prefix=IMPORTS1 +; RUN: count 1 < %t1.o.imports +; RUN: FileCheck %s --check-prefix=IMPORTS1 < %t1.o.imports ; IMPORTS1: thinlto-emit-imports.ll.tmp2.o ; The imports file for Input/thinlto.ll is empty as it does not import anything. -; RUN: cat %t2.o.imports | count 0 +; RUN: count 0 < %t2.o.imports ; The imports file for Input/thinlto_empty.ll is empty but should exist. -; RUN: cat %t3.o.imports | count 0 +; RUN: count 0 < %t3.o.imports ; The index file should be created even for the input with an empty summary. ; RUN: ls %t3.o.thinlto.bc @@ -43,6 +43,13 @@ ; RUN: not ls %t2.o.imports ; RUN: not ls %t3.o.imports +; Check that imports files are generated also when -thinlto-index-only +; is specified without --plugin-opt=. +; RUN: rm -f %t1.o.imports +; RUN: ld.lld -thinlto-index-only -thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 +; RUN: count 1 < %t1.o.imports +; RUN: FileCheck %s --check-prefix=IMPORTS1 < %t1.o.imports + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/lld/test/ELF/lto/thinlto-index-file.ll b/lld/test/ELF/lto/thinlto-index-file.ll --- a/lld/test/ELF/lto/thinlto-index-file.ll +++ b/lld/test/ELF/lto/thinlto-index-file.ll @@ -6,12 +6,16 @@ ; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o ; Ensure lld writes linked files to linked objects file -; RUN: ld.lld --plugin-opt=thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o %t4 +; RUN: ld.lld --plugin-opt=thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o /dev/null ; RUN: FileCheck %s < %t.idx ; CHECK: {{.*}}thinlto-index-file.ll.tmp1.o ; CHECK: {{.*}}thinlto-index-file.ll.tmp2.o ; CHECK: {{.*}}thinlto-index-file.ll.tmp3.o +; Check that this also works without the --plugin-opt= prefix. +; RUN: ld.lld -thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o /dev/null +; RUN: FileCheck %s < %t.idx + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/lld/test/ELF/lto/thinlto-obj-path.ll b/lld/test/ELF/lto/thinlto-obj-path.ll --- a/lld/test/ELF/lto/thinlto-obj-path.ll +++ b/lld/test/ELF/lto/thinlto-obj-path.ll @@ -5,11 +5,16 @@ ; Test to ensure that thinlto-index-only with obj-path creates the file. ; RUN: rm -f %t4.o -; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t3 +; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o /dev/null ; RUN: llvm-readobj -h %t4.o | FileCheck %s ; RUN: llvm-nm %t4.o 2>&1 | FileCheck %s -check-prefix=NO-SYMBOLS ; NO-SYMBOLS: no symbols +; Check that this also works without the --plugin-opt= prefix. +; RUN: rm -f %t4.o +; RUN: ld.lld -thinlto-index-only -lto-obj-path=%t4.o -shared %t1.o %t2.o -o /dev/null +; RUN: llvm-readobj -h %t4.o | FileCheck %s + ; CHECK: Format: ELF64-x86-64 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/lld/test/ELF/lto/thinlto-object-suffix-replace.ll b/lld/test/ELF/lto/thinlto-object-suffix-replace.ll --- a/lld/test/ELF/lto/thinlto-object-suffix-replace.ll +++ b/lld/test/ELF/lto/thinlto-object-suffix-replace.ll @@ -21,6 +21,11 @@ ; RUN: --plugin-opt=thinlto-object-suffix-replace=".thinlink.bc;.o" \ ; RUN: -shared %t1.thinlink.bc -o %t3 ; RUN: diff %t1.o.thinlto.bc.orig %t1.o.thinlto.bc +; Also check that this works without the --plugin-opt= prefix. +; RUN: ld.lld -thinlto-index-only \ +; RUN: -thinlto-object-suffix-replace=".thinlink.bc;.o" \ +; RUN: -shared %t1.thinlink.bc -o %t3 +; RUN: diff %t1.o.thinlto.bc.orig %t1.o.thinlto.bc ; Ensure lld generates error if object suffix replace option does not have 'old;new' format ; RUN: rm -f %t1.o.thinlto.bc diff --git a/lld/test/ELF/lto/thinlto-prefix-replace.ll b/lld/test/ELF/lto/thinlto-prefix-replace.ll --- a/lld/test/ELF/lto/thinlto-prefix-replace.ll +++ b/lld/test/ELF/lto/thinlto-prefix-replace.ll @@ -9,6 +9,11 @@ ; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace="%t/oldpath/;%t/newpath/" -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace ; RUN: ls %t/newpath/thinlto_prefix_replace.o.thinlto.bc +; Check that this also works without the --plugin-opt= prefix. +; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc +; RUN: ld.lld -thinlto-index-only -thinlto-prefix-replace="%t/oldpath/;%t/newpath/" -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace +; RUN: ls %t/newpath/thinlto_prefix_replace.o.thinlto.bc + ; Ensure that lld generates error if prefix replace option does not have 'old;new' format ; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc ; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace=abc:def -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace 2>&1 | FileCheck %s --check-prefix=ERR