diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2024-02-20 18:46:41 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-02-20 18:46:41 +0000 |
commit | e15a4f0a320e3c1248539511adee55a201e9ed2e (patch) | |
tree | e74b63e38a51ec5611f79daf5df6b5a2d7102bdb | |
parent | 4fdf604ba667503ae582304cebdd3df426778a6b (diff) |
Vendor import of llvm-project branch release/18.x llvmorg-18.1.0-rc2-53-gc7b0a6ecd442.vendor/llvm-project/llvmorg-18.1.0-rc2-53-gc7b0a6ecd442
61 files changed, 1480 insertions, 364 deletions
diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index 695e1bddf9ff..2da0e8d2aba9 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -44,6 +44,7 @@ defm SVLD1_ZA32 : ZALoad<"za32", "i", "aarch64_sme_ld1w", [ImmCheck<0, ImmCheck0 defm SVLD1_ZA64 : ZALoad<"za64", "l", "aarch64_sme_ld1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVLD1_ZA128 : ZALoad<"za128", "q", "aarch64_sme_ld1q", [ImmCheck<0, ImmCheck0_15>]>; +let TargetGuard = "sme" in { def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], MemEltTyDefault, "aarch64_sme_ldr">; @@ -51,6 +52,7 @@ def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "", def SVLDR_ZA : MInst<"svldr_za", "vmQ", "", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], MemEltTyDefault, "aarch64_sme_ldr", []>; +} //////////////////////////////////////////////////////////////////////////////// // Stores @@ -81,6 +83,7 @@ defm SVST1_ZA32 : ZAStore<"za32", "i", "aarch64_sme_st1w", [ImmCheck<0, ImmCheck defm SVST1_ZA64 : ZAStore<"za64", "l", "aarch64_sme_st1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVST1_ZA128 : ZAStore<"za128", "q", "aarch64_sme_st1q", [ImmCheck<0, ImmCheck0_15>]>; +let TargetGuard = "sme" in { def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "", [IsOverloadNone, IsStreamingCompatible, IsInZA], MemEltTyDefault, "aarch64_sme_str">; @@ -88,6 +91,7 @@ def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "", def SVSTR_ZA : MInst<"svstr_za", "vm%", "", [IsOverloadNone, IsStreamingCompatible, IsInZA], MemEltTyDefault, "aarch64_sme_str", []>; +} //////////////////////////////////////////////////////////////////////////////// // Read horizontal/vertical ZA slices @@ -277,22 +281,22 @@ multiclass ZAAddSub<string n_suffix> { def NAME # _ZA32_VG1x2_I32 : Inst<"sv" # n_suffix # "_za32[_{d}]_vg1x2", "vm2", "iUif", MergeNone, "aarch64_sme_" # n_suffix # "_za32_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _ZA32_VG1X4_I32 : Inst<"sv" # n_suffix # "_za32[_{d}]_vg1x4", "vm4", "iUif", MergeNone, "aarch64_sme_" # n_suffix # "_za32_vg1x4", [IsStreaming, IsInOutZA], []>; + } - let TargetGuard = "sme-i16i64" in { - def NAME # _WRITE_SINGLE_ZA64_VG1X2_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x2", "vm2d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x2", [IsStreaming, IsInOutZA], []>; - def NAME # _WRITE_SINGLE_ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x4", "vm4d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x4", [IsStreaming, IsInOutZA], []>; + let TargetGuard = "sme2,sme-i16i64" in { + def NAME # _WRITE_SINGLE_ZA64_VG1X2_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x2", "vm2d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x2", [IsStreaming, IsInOutZA], []>; + def NAME # _WRITE_SINGLE_ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x4", "vm4d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x4", [IsStreaming, IsInOutZA], []>; - def NAME # _WRITE_ZA64_VG1x2_I64 : Inst<"sv" # n_suffix # "_write_za64[_{d}]_vg1x2", "vm22", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_za_vg1x2", [IsStreaming, IsInOutZA], []>; - def NAME # _WRITE_ZA64_VG1x4_I64 : Inst<"sv" # n_suffix # "_write_za64[_{d}]_vg1x4", "vm44", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_za_vg1x4", [IsStreaming, IsInOutZA], []>; + def NAME # _WRITE_ZA64_VG1x2_I64 : Inst<"sv" # n_suffix # "_write_za64[_{d}]_vg1x2", "vm22", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_za_vg1x2", [IsStreaming, IsInOutZA], []>; + def NAME # _WRITE_ZA64_VG1x4_I64 : Inst<"sv" # n_suffix # "_write_za64[_{d}]_vg1x4", "vm44", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_za_vg1x4", [IsStreaming, IsInOutZA], []>; - def NAME # _ZA64_VG1X2_I64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x2", "vm2", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x2", [IsStreaming, IsInOutZA], []>; - def NAME # _ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; - } + def NAME # _ZA64_VG1X2_I64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x2", "vm2", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x2", [IsStreaming, IsInOutZA], []>; + def NAME # _ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; + } - let TargetGuard = "sme-f64f64" in { - def NAME # _ZA64_VG1X2_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x2", "vm2", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x2", [IsStreaming, IsInOutZA], []>; - def NAME # _ZA64_VG1X4_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; - } + let TargetGuard = "sme2,sme-f64f64" in { + def NAME # _ZA64_VG1X2_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x2", "vm2", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x2", [IsStreaming, IsInOutZA], []>; + def NAME # _ZA64_VG1X4_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; } } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e8d03fc26902..175bedbfb4d0 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5815,6 +5815,18 @@ def mvis3 : Flag<["-"], "mvis3">, Group<m_sparc_Features_Group>; def mno_vis3 : Flag<["-"], "mno-vis3">, Group<m_sparc_Features_Group>; def mhard_quad_float : Flag<["-"], "mhard-quad-float">, Group<m_sparc_Features_Group>; def msoft_quad_float : Flag<["-"], "msoft-quad-float">, Group<m_sparc_Features_Group>; +foreach i = 1 ... 7 in + def ffixed_g#i : Flag<["-"], "ffixed-g"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the G"#i#" register (SPARC only)">; +foreach i = 0 ... 5 in + def ffixed_o#i : Flag<["-"], "ffixed-o"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the O"#i#" register (SPARC only)">; +foreach i = 0 ... 7 in + def ffixed_l#i : Flag<["-"], "ffixed-l"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the L"#i#" register (SPARC only)">; +foreach i = 0 ... 5 in + def ffixed_i#i : Flag<["-"], "ffixed-i"#i>, Group<m_sparc_Features_Group>, + HelpText<"Reserve the I"#i#" register (SPARC only)">; } // let Flags = [TargetSpecific] // M68k features flags diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index ab16ca10395f..cc5de9a6295e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -498,7 +498,11 @@ void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls, return; FileID File; - for (Decl *D : Decls) { + for (const Decl *D : Decls) { + if (D->isInvalidDecl()) + continue; + + D = &adjustDeclToTemplate(*D); SourceLocation Loc = D->getLocation(); if (Loc.isValid()) { // See if there are any new comments that are not attached to a decl. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 336b7a5e3d72..3036f461c1de 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1187,6 +1187,8 @@ TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const { } const char *const AArch64TargetInfo::GCCRegNames[] = { + // clang-format off + // 32-bit Integer registers "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", @@ -1223,7 +1225,12 @@ const char *const AArch64TargetInfo::GCCRegNames[] = { // SVE predicate-as-counter registers "pn0", "pn1", "pn2", "pn3", "pn4", "pn5", "pn6", "pn7", "pn8", - "pn9", "pn10", "pn11", "pn12", "pn13", "pn14", "pn15" + "pn9", "pn10", "pn11", "pn12", "pn13", "pn14", "pn15", + + // SME registers + "za", "zt0", + + // clang-format on }; ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp index 22e583021515..ae1a4ba78826 100644 --- a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -178,4 +178,85 @@ void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args, else Features.push_back("-hard-quad-float"); } + + if (Args.hasArg(options::OPT_ffixed_g1)) + Features.push_back("+reserve-g1"); + + if (Args.hasArg(options::OPT_ffixed_g2)) + Features.push_back("+reserve-g2"); + + if (Args.hasArg(options::OPT_ffixed_g3)) + Features.push_back("+reserve-g3"); + + if (Args.hasArg(options::OPT_ffixed_g4)) + Features.push_back("+reserve-g4"); + + if (Args.hasArg(options::OPT_ffixed_g5)) + Features.push_back("+reserve-g5"); + + if (Args.hasArg(options::OPT_ffixed_g6)) + Features.push_back("+reserve-g6"); + + if (Args.hasArg(options::OPT_ffixed_g7)) + Features.push_back("+reserve-g7"); + + if (Args.hasArg(options::OPT_ffixed_o0)) + Features.push_back("+reserve-o0"); + + if (Args.hasArg(options::OPT_ffixed_o1)) + Features.push_back("+reserve-o1"); + + if (Args.hasArg(options::OPT_ffixed_o2)) + Features.push_back("+reserve-o2"); + + if (Args.hasArg(options::OPT_ffixed_o3)) + Features.push_back("+reserve-o3"); + + if (Args.hasArg(options::OPT_ffixed_o4)) + Features.push_back("+reserve-o4"); + + if (Args.hasArg(options::OPT_ffixed_o5)) + Features.push_back("+reserve-o5"); + + if (Args.hasArg(options::OPT_ffixed_l0)) + Features.push_back("+reserve-l0"); + + if (Args.hasArg(options::OPT_ffixed_l1)) + Features.push_back("+reserve-l1"); + + if (Args.hasArg(options::OPT_ffixed_l2)) + Features.push_back("+reserve-l2"); + + if (Args.hasArg(options::OPT_ffixed_l3)) + Features.push_back("+reserve-l3"); + + if (Args.hasArg(options::OPT_ffixed_l4)) + Features.push_back("+reserve-l4"); + + if (Args.hasArg(options::OPT_ffixed_l5)) + Features.push_back("+reserve-l5"); + + if (Args.hasArg(options::OPT_ffixed_l6)) + Features.push_back("+reserve-l6"); + + if (Args.hasArg(options::OPT_ffixed_l7)) + Features.push_back("+reserve-l7"); + + if (Args.hasArg(options::OPT_ffixed_i0)) + Features.push_back("+reserve-i0"); + + if (Args.hasArg(options::OPT_ffixed_i1)) + Features.push_back("+reserve-i1"); + + if (Args.hasArg(options::OPT_ffixed_i2)) + Features.push_back("+reserve-i2"); + + if (Args.hasArg(options::OPT_ffixed_i3)) + Features.push_back("+reserve-i3"); + + if (Args.hasArg(options::OPT_ffixed_i4)) + Features.push_back("+reserve-i4"); + + if (Args.hasArg(options::OPT_ffixed_i5)) + Features.push_back("+reserve-i5"); } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index b904e0e56d9e..573919798870 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2515,7 +2515,7 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { parseChildBlock(); break; case tok::r_paren: - if (!MightBeStmtExpr && + if (!MightBeStmtExpr && !Line->InMacroBody && Style.RemoveParentheses > FormatStyle::RPS_Leave) { const auto *Prev = LeftParen->Previous; const auto *Next = Tokens->peekNextToken(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4efcb3590355..0d9c087ed0cd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14062,7 +14062,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, Expr::EvalResult EVResult; if (RHS.get()->EvaluateAsInt(EVResult, Context)) { llvm::APSInt Result = EVResult.Val.getInt(); - if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() && + if ((getLangOpts().CPlusPlus && !RHS.get()->getType()->isBooleanType() && !RHS.get()->getExprLoc().isMacroID()) || (Result != 0 && Result != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 5ee6092bb9bb..e122cea50f72 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -399,7 +399,8 @@ class ClangFormatDiagConsumer : public DiagnosticConsumer { }; // Returns true on error. -static bool format(StringRef FileName, bool IsSTDIN) { +static bool format(StringRef FileName) { + const bool IsSTDIN = FileName == "-"; if (!OutputXML && Inplace && IsSTDIN) { errs() << "error: cannot use -i when reading from stdin.\n"; return false; @@ -545,24 +546,25 @@ static void PrintVersion(raw_ostream &OS) { } // Dump the configuration. -static int dumpConfig(bool IsSTDIN) { +static int dumpConfig() { std::unique_ptr<llvm::MemoryBuffer> Code; - - // `FileNames` must have at least "-" in it even if no file was specified. - assert(!FileNames.empty()); - - // Read in the code in case the filename alone isn't enough to detect the - // language. - ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = - MemoryBuffer::getFileOrSTDIN(FileNames[0]); - if (std::error_code EC = CodeOrErr.getError()) { - llvm::errs() << EC.message() << "\n"; - return 1; + // We can't read the code to detect the language if there's no file name. + if (!FileNames.empty()) { + // Read in the code in case the filename alone isn't enough to detect the + // language. + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(FileNames[0]); + if (std::error_code EC = CodeOrErr.getError()) { + llvm::errs() << EC.message() << "\n"; + return 1; + } + Code = std::move(CodeOrErr.get()); } - Code = std::move(CodeOrErr.get()); - llvm::Expected<clang::format::FormatStyle> FormatStyle = - clang::format::getStyle(Style, IsSTDIN ? AssumeFileName : FileNames[0], + clang::format::getStyle(Style, + FileNames.empty() || FileNames[0] == "-" + ? AssumeFileName + : FileNames[0], FallbackStyle, Code ? Code->getBuffer() : ""); if (!FormatStyle) { llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; @@ -682,11 +684,8 @@ int main(int argc, const char **argv) { return 0; } - if (FileNames.empty()) - FileNames.push_back("-"); - if (DumpConfig) - return dumpConfig(FileNames[0] == "-"); + return dumpConfig(); if (!Files.empty()) { std::ifstream ExternalFileOfFiles{std::string(Files)}; @@ -699,7 +698,10 @@ int main(int argc, const char **argv) { errs() << "Clang-formating " << LineNo << " files\n"; } - if (FileNames.size() != 1 && + if (FileNames.empty()) + return clang::format::format("-"); + + if (FileNames.size() > 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { errs() << "error: -offset, -length and -lines can only be used for " "single file.\n"; @@ -709,14 +711,13 @@ int main(int argc, const char **argv) { unsigned FileNo = 1; bool Error = false; for (const auto &FileName : FileNames) { - const bool IsSTDIN = FileName == "-"; - if (!IsSTDIN && isIgnored(FileName)) + if (isIgnored(FileName)) continue; if (Verbose) { errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] " << FileName << "\n"; } - Error |= clang::format::format(FileName, IsSTDIN); + Error |= clang::format::format(FileName); } return Error ? 1 : 0; } diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp index 85b796bd6349..3af26e9f64c9 100644 --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -55,6 +55,10 @@ using namespace __dfsan; #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); +#define WRAPPER_ALIAS(fun, real) \ + SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_##fun() ALIAS(__dfsw_##real); \ + SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real); + // Async-safe, non-reentrant spin lock. class SignalSpinLocker { public: @@ -1197,16 +1201,20 @@ char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label, *ret_origin = dst_origin; return ret; } +} -static long int dfsan_strtol(const char *nptr, char **endptr, int base, - char **tmp_endptr) { +template <typename Fn> +static ALWAYS_INLINE auto dfsan_strtol_impl( + Fn real, const char *nptr, char **endptr, int base, + char **tmp_endptr) -> decltype(real(nullptr, nullptr, 0)) { assert(tmp_endptr); - long int ret = strtol(nptr, tmp_endptr, base); + auto ret = real(nptr, tmp_endptr, base); if (endptr) *endptr = *tmp_endptr; return ret; } +extern "C" { static void dfsan_strtolong_label(const char *nptr, const char *tmp_endptr, dfsan_label base_label, dfsan_label *ret_label) { @@ -1236,30 +1244,6 @@ static void dfsan_strtolong_origin(const char *nptr, const char *tmp_endptr, } } -SANITIZER_INTERFACE_ATTRIBUTE -long int __dfsw_strtol(const char *nptr, char **endptr, int base, - dfsan_label nptr_label, dfsan_label endptr_label, - dfsan_label base_label, dfsan_label *ret_label) { - char *tmp_endptr; - long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -long int __dfso_strtol(const char *nptr, char **endptr, int base, - dfsan_label nptr_label, dfsan_label endptr_label, - dfsan_label base_label, dfsan_label *ret_label, - dfsan_origin nptr_origin, dfsan_origin endptr_origin, - dfsan_origin base_origin, dfsan_origin *ret_origin) { - char *tmp_endptr; - long int ret = dfsan_strtol(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin, - ret_origin); - return ret; -} - static double dfsan_strtod(const char *nptr, char **endptr, char **tmp_endptr) { assert(tmp_endptr); double ret = strtod(nptr, tmp_endptr); @@ -1307,108 +1291,40 @@ double __dfso_strtod(const char *nptr, char **endptr, dfsan_label nptr_label, return ret; } -static long long int dfsan_strtoll(const char *nptr, char **endptr, int base, - char **tmp_endptr) { - assert(tmp_endptr); - long long int ret = strtoll(nptr, tmp_endptr, base); - if (endptr) - *endptr = *tmp_endptr; - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -long long int __dfsw_strtoll(const char *nptr, char **endptr, int base, - dfsan_label nptr_label, dfsan_label endptr_label, - dfsan_label base_label, dfsan_label *ret_label) { - char *tmp_endptr; - long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -long long int __dfso_strtoll(const char *nptr, char **endptr, int base, - dfsan_label nptr_label, dfsan_label endptr_label, - dfsan_label base_label, dfsan_label *ret_label, - dfsan_origin nptr_origin, - dfsan_origin endptr_origin, - dfsan_origin base_origin, - dfsan_origin *ret_origin) { - char *tmp_endptr; - long long int ret = dfsan_strtoll(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin, - ret_origin); - return ret; -} - -static unsigned long int dfsan_strtoul(const char *nptr, char **endptr, - int base, char **tmp_endptr) { - assert(tmp_endptr); - unsigned long int ret = strtoul(nptr, tmp_endptr, base); - if (endptr) - *endptr = *tmp_endptr; - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base, - dfsan_label nptr_label, dfsan_label endptr_label, - dfsan_label base_label, dfsan_label *ret_label) { - char *tmp_endptr; - unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -unsigned long int __dfso_strtoul( - const char *nptr, char **endptr, int base, dfsan_label nptr_label, - dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label, - dfsan_origin nptr_origin, dfsan_origin endptr_origin, - dfsan_origin base_origin, dfsan_origin *ret_origin) { - char *tmp_endptr; - unsigned long int ret = dfsan_strtoul(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin, - ret_origin); - return ret; -} - -static long long unsigned int dfsan_strtoull(const char *nptr, char **endptr, - int base, char **tmp_endptr) { - assert(tmp_endptr); - long long unsigned int ret = strtoull(nptr, tmp_endptr, base); - if (endptr) - *endptr = *tmp_endptr; - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr, - int base, dfsan_label nptr_label, - dfsan_label endptr_label, - dfsan_label base_label, - dfsan_label *ret_label) { - char *tmp_endptr; - long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -long long unsigned int __dfso_strtoull( - const char *nptr, char **endptr, int base, dfsan_label nptr_label, - dfsan_label endptr_label, dfsan_label base_label, dfsan_label *ret_label, - dfsan_origin nptr_origin, dfsan_origin endptr_origin, - dfsan_origin base_origin, dfsan_origin *ret_origin) { - char *tmp_endptr; - long long unsigned int ret = dfsan_strtoull(nptr, endptr, base, &tmp_endptr); - dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); - dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, base_origin, - ret_origin); - return ret; -} +WRAPPER_ALIAS(__isoc23_strtod, strtod) + +#define WRAPPER_STRTO(ret_type, fun) \ + SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfsw_##fun( \ + const char *nptr, char **endptr, int base, dfsan_label nptr_label, \ + dfsan_label endptr_label, dfsan_label base_label, \ + dfsan_label *ret_label) { \ + char *tmp_endptr; \ + auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr); \ + dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); \ + return ret; \ + } \ + SANITIZER_INTERFACE_ATTRIBUTE ret_type __dfso_##fun( \ + const char *nptr, char **endptr, int base, dfsan_label nptr_label, \ + dfsan_label endptr_label, dfsan_label base_label, \ + dfsan_label *ret_label, dfsan_origin nptr_origin, \ + dfsan_origin endptr_origin, dfsan_origin base_origin, \ + dfsan_origin *ret_origin) { \ + char *tmp_endptr; \ + auto ret = dfsan_strtol_impl(fun, nptr, endptr, base, &tmp_endptr); \ + dfsan_strtolong_label(nptr, tmp_endptr, base_label, ret_label); \ + dfsan_strtolong_origin(nptr, tmp_endptr, base_label, ret_label, \ + base_origin, ret_origin); \ + return ret; \ + } + +WRAPPER_STRTO(long, strtol) +WRAPPER_STRTO(long long, strtoll) +WRAPPER_STRTO(unsigned long, strtoul) +WRAPPER_STRTO(unsigned long long, strtoull) +WRAPPER_ALIAS(__isoc23_strtol, strtol) +WRAPPER_ALIAS(__isoc23_strtoll, strtoll) +WRAPPER_ALIAS(__isoc23_strtoul, strtoul) +WRAPPER_ALIAS(__isoc23_strtoull, strtoull) SANITIZER_INTERFACE_ATTRIBUTE time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) { @@ -2231,7 +2147,7 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write( *ret_label = 0; return write(fd, buf, count); } -} // namespace __dfsan +} // namespace __dfsan // Type used to extract a dfsan_label with va_arg() typedef int dfsan_label_va; @@ -2866,31 +2782,8 @@ int __dfso_sscanf(char *str, const char *format, dfsan_label str_label, return ret; } -SANITIZER_INTERFACE_ATTRIBUTE -int __dfsw___isoc99_sscanf(char *str, const char *format, dfsan_label str_label, - dfsan_label format_label, dfsan_label *va_labels, - dfsan_label *ret_label, ...) { - va_list ap; - va_start(ap, ret_label); - int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, nullptr, - nullptr, ap); - va_end(ap); - return ret; -} - -SANITIZER_INTERFACE_ATTRIBUTE -int __dfso___isoc99_sscanf(char *str, const char *format, dfsan_label str_label, - dfsan_label format_label, dfsan_label *va_labels, - dfsan_label *ret_label, dfsan_origin str_origin, - dfsan_origin format_origin, dfsan_origin *va_origins, - dfsan_origin *ret_origin, ...) { - va_list ap; - va_start(ap, ret_origin); - int ret = scan_buffer(str, ~0ul, format, va_labels, ret_label, &str_origin, - ret_origin, ap); - va_end(ap); - return ret; -} +WRAPPER_ALIAS(__isoc99_sscanf, sscanf) +WRAPPER_ALIAS(__isoc23_sscanf, sscanf) static void BeforeFork() { StackDepotLockBeforeFork(); diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt index c582584d77e4..86a42ee1b4dc 100644 --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -270,6 +270,11 @@ fun:strtoul=custom fun:strtoull=custom fun:strcat=custom fun:strncat=custom +fun:__isoc23_strtod=custom +fun:__isoc23_strtol=custom +fun:__isoc23_strtoll=custom +fun:__isoc23_strtoul=custom +fun:__isoc23_strtoull=custom # Functions that produce an output that is computed from the input, but is not # necessarily data dependent. @@ -311,6 +316,7 @@ fun:snprintf=custom # scanf-like fun:sscanf=custom fun:__isoc99_sscanf=custom +fun:__isoc23_sscanf=custom # TODO: custom fun:asprintf=discard diff --git a/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt index 433092e2b27b..9ffa56a23818 100644 --- a/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt +++ b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt @@ -1,3 +1,8 @@ +fun:__isoc23_sscanf=uninstrumented +fun:__isoc23_strtol=uninstrumented +fun:__isoc23_strtoll=uninstrumented +fun:__isoc23_strtoul=uninstrumented +fun:__isoc23_strtoull=uninstrumented fun:_Exit=uninstrumented fun:_IO_adjust_column=uninstrumented fun:_IO_adjust_wcolumn=uninstrumented diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c index 9f46a98d78ac..002bec164d7e 100644 --- a/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c @@ -195,6 +195,8 @@ static const int dummy_name[0] COMPILER_RT_SECTION( COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME); static int dummy_vnds[0] COMPILER_RT_SECTION( COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME); +static int dummy_orderfile[0] COMPILER_RT_SECTION( + COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME); // To avoid GC'ing of the dummy variables by the linker, reference them in an // array and reference the array in the runtime registration code @@ -206,7 +208,7 @@ static int dummy_vnds[0] COMPILER_RT_SECTION( COMPILER_RT_VISIBILITY void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits, (void *)&dummy_data, (void *)&dummy_name, - (void *)&dummy_vnds}; + (void *)&dummy_vnds, (void *)&dummy_orderfile}; #ifdef __GNUC__ #pragma GCC diagnostic pop #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 1b56bebac64e..3ecdb55cdbf7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -10218,20 +10218,6 @@ INTERCEPTOR(int, __xuname, int size, void *utsname) { #define INIT___XUNAME #endif -#if SANITIZER_INTERCEPT_HEXDUMP -INTERCEPTOR(void, hexdump, const void *ptr, int length, const char *header, int flags) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, hexdump, ptr, length, header, flags); - COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, length); - COMMON_INTERCEPTOR_READ_RANGE(ctx, header, internal_strlen(header) + 1); - REAL(hexdump)(ptr, length, header, flags); -} - -#define INIT_HEXDUMP COMMON_INTERCEPT_FUNCTION(hexdump); -#else -#define INIT_HEXDUMP -#endif - #if SANITIZER_INTERCEPT_ARGP_PARSE INTERCEPTOR(int, argp_parse, const struct argp *argp, int argc, char **argv, unsigned flags, int *arg_index, void *input) { @@ -10581,7 +10567,6 @@ static void InitializeCommonInterceptors() { INIT_PROCCTL INIT_UNAME; INIT___XUNAME; - INIT_HEXDUMP; INIT_ARGP_PARSE; INIT_CPUSET_GETAFFINITY; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 0ce4e9351bc1..de55c736d0e1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -596,7 +596,6 @@ #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD #define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD #define SANITIZER_INTERCEPT_PROCCTL SI_FREEBSD -#define SANITIZER_INTERCEPT_HEXDUMP SI_FREEBSD #define SANITIZER_INTERCEPT_ARGP_PARSE SI_GLIBC #define SANITIZER_INTERCEPT_CPUSET_GETAFFINITY SI_FREEBSD diff --git a/libcxx/include/print b/libcxx/include/print index 7f2b5bac3dcf..543a540ee4f2 100644 --- a/libcxx/include/print +++ b/libcxx/include/print @@ -32,6 +32,7 @@ namespace std { */ #include <__assert> // all public C++ headers provide the assertion handler +#include <__availability> #include <__concepts/same_as.h> #include <__config> #include <__system_error/system_error.h> @@ -43,10 +44,6 @@ namespace std { #include <string_view> #include <version> -#if __has_include(<unistd.h>) -# include <unistd.h> -#endif - #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif @@ -68,7 +65,8 @@ _LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream); // Note the function is only implemented on the Windows platform. _LIBCPP_EXPORTED_FROM_ABI void __write_to_windows_console(FILE* __stream, wstring_view __view); # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS - +#elif __has_include(<unistd.h>) +_LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream); #endif // _LIBCPP_WIN32API #if _LIBCPP_STD_VER >= 23 @@ -195,15 +193,17 @@ inline constexpr bool __use_unicode_execution_charset = _MSVC_EXECUTION_CHARACTE inline constexpr bool __use_unicode_execution_charset = true; # endif -_LIBCPP_HIDE_FROM_ABI inline bool __is_terminal(FILE* __stream) { +_LIBCPP_HIDE_FROM_ABI inline bool __is_terminal([[maybe_unused]] FILE* __stream) { // The macro _LIBCPP_TESTING_PRINT_IS_TERMINAL is used to change // the behavior in the test. This is not part of the public API. # ifdef _LIBCPP_TESTING_PRINT_IS_TERMINAL return _LIBCPP_TESTING_PRINT_IS_TERMINAL(__stream); +# elif _LIBCPP_AVAILABILITY_HAS_PRINT == 0 + return false; # elif defined(_LIBCPP_WIN32API) return std::__is_windows_terminal(__stream); # elif __has_include(<unistd.h>) - return isatty(fileno(__stream)); + return std::__is_posix_terminal(__stream); # else # error "Provide a way to determine whether a FILE* is a terminal" # endif diff --git a/libcxx/modules/CMakeLists.txt.in b/libcxx/modules/CMakeLists.txt.in new file mode 100644 index 000000000000..e332d70cc163 --- /dev/null +++ b/libcxx/modules/CMakeLists.txt.in @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 3.26) + +project(libc++-modules LANGUAGES CXX) + +# Enable CMake's module support +if(CMAKE_VERSION VERSION_LESS "3.28.0") + if(CMAKE_VERSION VERSION_LESS "3.27.0") + set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") + else() + set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7") + endif() + set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +else() + cmake_policy(VERSION 3.28) +endif() + +# Default to C++ extensions being off. Libc++'s modules support have trouble +# with extensions right now. +set(CMAKE_CXX_EXTENSIONS OFF) + +# Propagates the CMake options to the modules. +# +# This uses the std module hard-coded since the std.compat module does not +# depend on these flags. +macro(compile_define_if_not condition def) + if (NOT ${condition}) + target_compile_definitions(std PRIVATE ${def}) + endif() +endmacro() +macro(compile_define_if condition def) + if (${condition}) + target_compile_definitions(std PRIVATE ${def}) + endif() +endmacro() + +### STD + +add_library(std) +target_sources(std + PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES + std.cppm +) + +target_include_directories(std SYSTEM PRIVATE @LIBCXX_CONFIGURED_INCLUDE_DIRS@) + +if (NOT @LIBCXX_ENABLE_EXCEPTIONS@) + target_compile_options(std PUBLIC -fno-exceptions) +endif() + +target_compile_options(std + PUBLIC + -nostdinc++ + -Wno-reserved-module-identifier + -Wno-reserved-user-defined-literal + @LIBCXX_COMPILE_FLAGS@ +) +set_target_properties(std + PROPERTIES + OUTPUT_NAME "c++std" +) + +### STD.COMPAT + +add_library(std.compat) +target_sources(std.compat + PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES + std.compat.cppm +) + +target_include_directories(std.compat SYSTEM PRIVATE @LIBCXX_CONFIGURED_INCLUDE_DIRS@) + +if (NOT @LIBCXX_ENABLE_EXCEPTIONS@) + target_compile_options(std.compat PUBLIC -fno-exceptions) +endif() + +target_compile_options(std.compat + PUBLIC + -nostdinc++ + -Wno-reserved-module-identifier + -Wno-reserved-user-defined-literal + -fmodule-file=std=${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/std.dir/std.pcm + @LIBCXX_COMPILE_FLAGS@ +) +set_target_properties(std.compat + PROPERTIES + OUTPUT_NAME "c++std.compat" +) +add_dependencies(std.compat std) diff --git a/libcxx/modules/std/ostream.inc b/libcxx/modules/std/ostream.inc index 8fcbfb4bdc18..0e0e2d54fe6b 100644 --- a/libcxx/modules/std/ostream.inc +++ b/libcxx/modules/std/ostream.inc @@ -33,8 +33,10 @@ export namespace std { using std::println; using std::vprint_nonunicode; +# ifndef _LIBCPP_HAS_NO_UNICODE using std::vprint_unicode; -# endif // _LIBCPP_STD_VER >= 23 +# endif // _LIBCPP_HAS_NO_UNICODE +# endif // _LIBCPP_STD_VER >= 23 #endif // _LIBCPP_HAS_NO_LOCALIZATION } // namespace std diff --git a/libcxx/src/print.cpp b/libcxx/src/print.cpp index 3692187a5954..8fa59fdd097b 100644 --- a/libcxx/src/print.cpp +++ b/libcxx/src/print.cpp @@ -8,22 +8,26 @@ #include <__config> -#if defined(_LIBCPP_WIN32API) +#include <cstdlib> +#include <print> + +#include <__system_error/system_error.h> -# include <cstdlib> -# include <print> +#include "filesystem/error.h" +#if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include <io.h> # include <windows.h> - -# include <__system_error/system_error.h> - -# include "filesystem/error.h" +#elif __has_include(<unistd.h>) +# include <unistd.h> +#endif _LIBCPP_BEGIN_NAMESPACE_STD +#if defined(_LIBCPP_WIN32API) + _LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream) { // Note the Standard does this in one call, but it's unclear whether // an invalid handle is allowed when calling GetConsoleMode. @@ -52,6 +56,9 @@ __write_to_windows_console([[maybe_unused]] FILE* __stream, [[maybe_unused]] wst } # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS -_LIBCPP_END_NAMESPACE_STD +#elif __has_include(<unistd.h>) // !_LIBCPP_WIN32API -#endif // !_LIBCPP_WIN32API +_LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream) { return isatty(fileno(__stream)); } +#endif + +_LIBCPP_END_NAMESPACE_STD diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index e0afb6b18805..22ee2f133be9 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1825,7 +1825,15 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { } } else { config->repro = false; - config->timestamp = time(nullptr); + if (std::optional<std::string> epoch = + Process::GetEnv("SOURCE_DATE_EPOCH")) { + StringRef value(*epoch); + if (value.getAsInteger(0, config->timestamp)) + fatal(Twine("invalid SOURCE_DATE_EPOCH timestamp: ") + value + + ". Expected 32-bit integer"); + } else { + config->timestamp = time(nullptr); + } } // Handle /alternatename diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index ab2ec5b447d0..05fd38fb753f 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -36,6 +36,8 @@ public: bool usesOnlyLowPageBits(RelType type) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; + bool relaxOnce(int pass) const override; + void finalizeRelax(int passes) const override; }; } // end anonymous namespace @@ -465,8 +467,9 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s, case R_LARCH_TLS_GD_HI20: return R_TLSGD_GOT; case R_LARCH_RELAX: - // LoongArch linker relaxation is not implemented yet. - return R_NONE; + return config->relax ? R_RELAX_HINT : R_NONE; + case R_LARCH_ALIGN: + return R_RELAX_HINT; // Other known relocs that are explicitly unimplemented: // @@ -659,6 +662,155 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel, } } +static bool relax(InputSection &sec) { + const uint64_t secAddr = sec.getVA(); + const MutableArrayRef<Relocation> relocs = sec.relocs(); + auto &aux = *sec.relaxAux; + bool changed = false; + ArrayRef<SymbolAnchor> sa = ArrayRef(aux.anchors); + uint64_t delta = 0; + + std::fill_n(aux.relocTypes.get(), relocs.size(), R_LARCH_NONE); + aux.writes.clear(); + for (auto [i, r] : llvm::enumerate(relocs)) { + const uint64_t loc = secAddr + r.offset - delta; + uint32_t &cur = aux.relocDeltas[i], remove = 0; + switch (r.type) { + case R_LARCH_ALIGN: { + const uint64_t addend = + r.sym->isUndefined() ? Log2_64(r.addend) + 1 : r.addend; + const uint64_t allBytes = (1 << (addend & 0xff)) - 4; + const uint64_t align = 1 << (addend & 0xff); + const uint64_t maxBytes = addend >> 8; + const uint64_t off = loc & (align - 1); + const uint64_t curBytes = off == 0 ? 0 : align - off; + // All bytes beyond the alignment boundary should be removed. + // If emit bytes more than max bytes to emit, remove all. + if (maxBytes != 0 && curBytes > maxBytes) + remove = allBytes; + else + remove = allBytes - curBytes; + // If we can't satisfy this alignment, we've found a bad input. + if (LLVM_UNLIKELY(static_cast<int32_t>(remove) < 0)) { + errorOrWarn(getErrorLocation((const uint8_t *)loc) + + "insufficient padding bytes for " + lld::toString(r.type) + + ": " + Twine(allBytes) + " bytes available for " + + "requested alignment of " + Twine(align) + " bytes"); + remove = 0; + } + break; + } + } + + // For all anchors whose offsets are <= r.offset, they are preceded by + // the previous relocation whose `relocDeltas` value equals `delta`. + // Decrease their st_value and update their st_size. + for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) { + if (sa[0].end) + sa[0].d->size = sa[0].offset - delta - sa[0].d->value; + else + sa[0].d->value = sa[0].offset - delta; + } + delta += remove; + if (delta != cur) { + cur = delta; + changed = true; + } + } + + for (const SymbolAnchor &a : sa) { + if (a.end) + a.d->size = a.offset - delta - a.d->value; + else + a.d->value = a.offset - delta; + } + // Inform assignAddresses that the size has changed. + if (!isUInt<32>(delta)) + fatal("section size decrease is too large: " + Twine(delta)); + sec.bytesDropped = delta; + return changed; +} + +// When relaxing just R_LARCH_ALIGN, relocDeltas is usually changed only once in +// the absence of a linker script. For call and load/store R_LARCH_RELAX, code +// shrinkage may reduce displacement and make more relocations eligible for +// relaxation. Code shrinkage may increase displacement to a call/load/store +// target at a higher fixed address, invalidating an earlier relaxation. Any +// change in section sizes can have cascading effect and require another +// relaxation pass. +bool LoongArch::relaxOnce(int pass) const { + if (config->relocatable) + return false; + + if (pass == 0) + initSymbolAnchors(); + + SmallVector<InputSection *, 0> storage; + bool changed = false; + for (OutputSection *osec : outputSections) { + if (!(osec->flags & SHF_EXECINSTR)) + continue; + for (InputSection *sec : getInputSections(*osec, storage)) + changed |= relax(*sec); + } + return changed; +} + +void LoongArch::finalizeRelax(int passes) const { + log("relaxation passes: " + Twine(passes)); + SmallVector<InputSection *, 0> storage; + for (OutputSection *osec : outputSections) { + if (!(osec->flags & SHF_EXECINSTR)) + continue; + for (InputSection *sec : getInputSections(*osec, storage)) { + RelaxAux &aux = *sec->relaxAux; + if (!aux.relocDeltas) + continue; + + MutableArrayRef<Relocation> rels = sec->relocs(); + ArrayRef<uint8_t> old = sec->content(); + size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1]; + uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize); + uint64_t offset = 0; + int64_t delta = 0; + sec->content_ = p; + sec->size = newSize; + sec->bytesDropped = 0; + + // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite + // instructions for relaxed relocations. + for (size_t i = 0, e = rels.size(); i != e; ++i) { + uint32_t remove = aux.relocDeltas[i] - delta; + delta = aux.relocDeltas[i]; + if (remove == 0 && aux.relocTypes[i] == R_LARCH_NONE) + continue; + + // Copy from last location to the current relocated location. + const Relocation &r = rels[i]; + uint64_t size = r.offset - offset; + memcpy(p, old.data() + offset, size); + p += size; + offset = r.offset + remove; + } + memcpy(p, old.data() + offset, old.size() - offset); + + // Subtract the previous relocDeltas value from the relocation offset. + // For a pair of R_LARCH_XXX/R_LARCH_RELAX with the same offset, decrease + // their r_offset by the same delta. + delta = 0; + for (size_t i = 0, e = rels.size(); i != e;) { + uint64_t cur = rels[i].offset; + do { + rels[i].offset -= delta; + if (aux.relocTypes[i] != R_LARCH_NONE) + rels[i].type = aux.relocTypes[i]; + } while (++i != e && rels[i].offset == cur); + delta = aux.relocDeltas[i - 1]; + } + } + } +} + TargetInfo *elf::getLoongArchTargetInfo() { static LoongArch target; return ⌖ diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 8ce92b4badfb..5fcab4d39d43 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -45,6 +45,7 @@ public: uint64_t val) const override; void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; bool relaxOnce(int pass) const override; + void finalizeRelax(int passes) const override; }; } // end anonymous namespace @@ -104,26 +105,6 @@ static uint32_t setLO12_S(uint32_t insn, uint32_t imm) { (extractBits(imm, 4, 0) << 7); } -namespace { -struct SymbolAnchor { - uint64_t offset; - Defined *d; - bool end; // true for the anchor of st_value+st_size -}; -} // namespace - -struct elf::RISCVRelaxAux { - // This records symbol start and end offsets which will be adjusted according - // to the nearest relocDeltas element. - SmallVector<SymbolAnchor, 0> anchors; - // For relocations[i], the actual offset is - // r_offset - (i ? relocDeltas[i-1] : 0). - std::unique_ptr<uint32_t[]> relocDeltas; - // For relocations[i], the actual type is relocTypes[i]. - std::unique_ptr<RelType[]> relocTypes; - SmallVector<uint32_t, 0> writes; -}; - RISCV::RISCV() { copyRel = R_RISCV_COPY; pltRel = R_RISCV_JUMP_SLOT; @@ -695,13 +676,13 @@ void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { } } -static void initSymbolAnchors() { +void elf::initSymbolAnchors() { SmallVector<InputSection *, 0> storage; for (OutputSection *osec : outputSections) { if (!(osec->flags & SHF_EXECINSTR)) continue; for (InputSection *sec : getInputSections(*osec, storage)) { - sec->relaxAux = make<RISCVRelaxAux>(); + sec->relaxAux = make<RelaxAux>(); if (sec->relocs().size()) { sec->relaxAux->relocDeltas = std::make_unique<uint32_t[]>(sec->relocs().size()); @@ -948,7 +929,7 @@ bool RISCV::relaxOnce(int pass) const { return changed; } -void elf::riscvFinalizeRelax(int passes) { +void RISCV::finalizeRelax(int passes) const { llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation"); log("relaxation passes: " + Twine(passes)); SmallVector<InputSection *, 0> storage; @@ -956,7 +937,7 @@ void elf::riscvFinalizeRelax(int passes) { if (!(osec->flags & SHF_EXECINSTR)) continue; for (InputSection *sec : getInputSections(*osec, storage)) { - RISCVRelaxAux &aux = *sec->relaxAux; + RelaxAux &aux = *sec->relaxAux; if (!aux.relocDeltas) continue; diff --git a/lld/ELF/Arch/SystemZ.cpp b/lld/ELF/Arch/SystemZ.cpp new file mode 100644 index 000000000000..d37db6877559 --- /dev/null +++ b/lld/ELF/Arch/SystemZ.cpp @@ -0,0 +1,607 @@ +//===- SystemZ.cpp --------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "OutputSections.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class SystemZ : public TargetInfo { +public: + SystemZ(); + int getTlsGdRelaxSkip(RelType type) const override; + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + RelType getDynRel(RelType type) const override; + void writeGotHeader(uint8_t *buf) const override; + void writeGotPlt(uint8_t *buf, const Symbol &s) const override; + void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; + void writePltHeader(uint8_t *buf) const override; + void addPltHeaderSymbols(InputSection &isd) const override; + void writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const override; + RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; + RelExpr adjustGotPcExpr(RelType type, int64_t addend, + const uint8_t *loc) const override; + bool relaxOnce(int pass) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; + +private: + void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const; + void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; + void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; + void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; +}; +} // namespace + +SystemZ::SystemZ() { + copyRel = R_390_COPY; + gotRel = R_390_GLOB_DAT; + pltRel = R_390_JMP_SLOT; + relativeRel = R_390_RELATIVE; + iRelativeRel = R_390_IRELATIVE; + symbolicRel = R_390_64; + tlsGotRel = R_390_TLS_TPOFF; + tlsModuleIndexRel = R_390_TLS_DTPMOD; + tlsOffsetRel = R_390_TLS_DTPOFF; + gotHeaderEntriesNum = 3; + gotPltHeaderEntriesNum = 0; + gotEntrySize = 8; + pltHeaderSize = 32; + pltEntrySize = 32; + ipltEntrySize = 32; + + // This "trap instruction" is used to fill gaps between sections. + // On SystemZ, the behavior of the GNU ld is to fill those gaps + // with nop instructions instead - and unfortunately the default + // glibc crt object files (used to) rely on that behavior since + // they use an alignment on the .init section fragments that causes + // gaps which must be filled with nops as they are being executed. + // Therefore, we provide a nop instruction as "trapInstr" here. + trapInstr = {0x07, 0x07, 0x07, 0x07}; + + defaultImageBase = 0x1000000; +} + +RelExpr SystemZ::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_390_NONE: + return R_NONE; + // Relocations targeting the symbol value. + case R_390_8: + case R_390_12: + case R_390_16: + case R_390_20: + case R_390_32: + case R_390_64: + return R_ABS; + case R_390_PC16: + case R_390_PC32: + case R_390_PC64: + case R_390_PC12DBL: + case R_390_PC16DBL: + case R_390_PC24DBL: + case R_390_PC32DBL: + return R_PC; + case R_390_GOTOFF16: + case R_390_GOTOFF: // a.k.a. R_390_GOTOFF32 + case R_390_GOTOFF64: + return R_GOTREL; + // Relocations targeting the PLT associated with the symbol. + case R_390_PLT32: + case R_390_PLT64: + case R_390_PLT12DBL: + case R_390_PLT16DBL: + case R_390_PLT24DBL: + case R_390_PLT32DBL: + return R_PLT_PC; + case R_390_PLTOFF16: + case R_390_PLTOFF32: + case R_390_PLTOFF64: + return R_PLT_GOTREL; + // Relocations targeting the GOT entry associated with the symbol. + case R_390_GOTENT: + return R_GOT_PC; + case R_390_GOT12: + case R_390_GOT16: + case R_390_GOT20: + case R_390_GOT32: + case R_390_GOT64: + return R_GOT_OFF; + // Relocations targeting the GOTPLT entry associated with the symbol. + case R_390_GOTPLTENT: + return R_GOTPLT_PC; + case R_390_GOTPLT12: + case R_390_GOTPLT16: + case R_390_GOTPLT20: + case R_390_GOTPLT32: + case R_390_GOTPLT64: + return R_GOTPLT_GOTREL; + // Relocations targeting _GLOBAL_OFFSET_TABLE_. + case R_390_GOTPC: + case R_390_GOTPCDBL: + return R_GOTONLY_PC; + // TLS-related relocations. + case R_390_TLS_LOAD: + return R_NONE; + case R_390_TLS_GDCALL: + return R_TLSGD_PC; + case R_390_TLS_LDCALL: + return R_TLSLD_PC; + case R_390_TLS_GD32: + case R_390_TLS_GD64: + return R_TLSGD_GOT; + case R_390_TLS_LDM32: + case R_390_TLS_LDM64: + return R_TLSLD_GOT; + case R_390_TLS_LDO32: + case R_390_TLS_LDO64: + return R_DTPREL; + case R_390_TLS_LE32: + case R_390_TLS_LE64: + return R_TPREL; + case R_390_TLS_IE32: + case R_390_TLS_IE64: + return R_GOT; + case R_390_TLS_GOTIE12: + case R_390_TLS_GOTIE20: + case R_390_TLS_GOTIE32: + case R_390_TLS_GOTIE64: + return R_GOT_OFF; + case R_390_TLS_IEENT: + return R_GOT_PC; + + default: + error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + + ") against symbol " + toString(s)); + return R_NONE; + } +} + +void SystemZ::writeGotHeader(uint8_t *buf) const { + // _GLOBAL_OFFSET_TABLE_[0] holds the value of _DYNAMIC. + // _GLOBAL_OFFSET_TABLE_[1] and [2] are reserved. + write64be(buf, mainPart->dynamic->getVA()); +} + +void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const { + write64be(buf, s.getPltVA() + 14); +} + +void SystemZ::writeIgotPlt(uint8_t *buf, const Symbol &s) const { + if (config->writeAddends) + write64be(buf, s.getVA()); +} + +void SystemZ::writePltHeader(uint8_t *buf) const { + const uint8_t pltData[] = { + 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1,56(%r15) + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,_GLOBAL_OFFSET_TABLE_ + 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15),8(%r1) + 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1,16(%r1) + 0x07, 0xf1, // br %r1 + 0x07, 0x00, // nopr + 0x07, 0x00, // nopr + 0x07, 0x00, // nopr + }; + memcpy(buf, pltData, sizeof(pltData)); + uint64_t got = in.got->getVA(); + uint64_t plt = in.plt->getVA(); + write32be(buf + 8, (got - plt - 6) >> 1); +} + +void SystemZ::addPltHeaderSymbols(InputSection &isec) const { + // The PLT header needs a reference to _GLOBAL_OFFSET_TABLE_, so we + // must ensure the .got section is created even if otherwise unused. + in.got->hasGotOffRel.store(true, std::memory_order_relaxed); +} + +void SystemZ::writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const { + const uint8_t inst[] = { + 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1,<.got.plt slot> + 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, // lg %r1,0(%r1) + 0x07, 0xf1, // br %r1 + 0x0d, 0x10, // basr %r1,%r0 + 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, // lgf %r1,12(%r1) + 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, // jg <plt header> + 0x00, 0x00, 0x00, 0x00, // <relocation offset> + }; + memcpy(buf, inst, sizeof(inst)); + + write32be(buf + 2, (sym.getGotPltVA() - pltEntryAddr) >> 1); + write32be(buf + 24, (in.plt->getVA() - pltEntryAddr - 22) >> 1); + write32be(buf + 28, in.relaPlt->entsize * sym.getPltIdx()); +} + +int64_t SystemZ::getImplicitAddend(const uint8_t *buf, RelType type) const { + switch (type) { + case R_390_8: + return SignExtend64<8>(*buf); + case R_390_16: + case R_390_PC16: + return SignExtend64<16>(read16be(buf)); + case R_390_PC16DBL: + return SignExtend64<16>(read16be(buf)) << 1; + case R_390_32: + case R_390_PC32: + return SignExtend64<32>(read32be(buf)); + case R_390_PC32DBL: + return SignExtend64<32>(read32be(buf)) << 1; + case R_390_64: + case R_390_PC64: + case R_390_TLS_DTPMOD: + case R_390_TLS_DTPOFF: + case R_390_TLS_TPOFF: + case R_390_GLOB_DAT: + case R_390_RELATIVE: + case R_390_IRELATIVE: + return read64be(buf); + case R_390_COPY: + case R_390_JMP_SLOT: + case R_390_NONE: + // These relocations are defined as not having an implicit addend. + return 0; + default: + internalLinkerError(getErrorLocation(buf), + "cannot read addend for relocation " + toString(type)); + return 0; + } +} + +RelType SystemZ::getDynRel(RelType type) const { + if (type == R_390_64 || type == R_390_PC64) + return type; + return R_390_NONE; +} + +RelExpr SystemZ::adjustTlsExpr(RelType type, RelExpr expr) const { + if (expr == R_RELAX_TLS_GD_TO_IE) + return R_RELAX_TLS_GD_TO_IE_GOT_OFF; + return expr; +} + +int SystemZ::getTlsGdRelaxSkip(RelType type) const { + // A __tls_get_offset call instruction is marked with 2 relocations: + // + // R_390_TLS_GDCALL / R_390_TLS_LDCALL: marker relocation + // R_390_PLT32DBL: __tls_get_offset + // + // After the relaxation we no longer call __tls_get_offset and should skip + // both relocations to not create a false dependence on __tls_get_offset + // being defined. + // + // Note that this mechanism only works correctly if the R_390_TLS_[GL]DCALL + // is seen immediately *before* the R_390_PLT32DBL. Unfortunately, current + // compilers on the platform will typically generate the inverse sequence. + // To fix this, we sort relocations by offset in RelocationScanner::scan; + // this ensures the correct sequence as the R_390_TLS_[GL]DCALL applies to + // the first byte of the brasl instruction, while the R_390_PLT32DBL applies + // to its third byte (the relative displacement). + + if (type == R_390_TLS_GDCALL || type == R_390_TLS_LDCALL) + return 2; + return 1; +} + +void SystemZ::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + // The general-dynamic code sequence for a global `x`: + // + // Instruction Relocation Symbol + // ear %rX,%a0 + // sllg %rX,%rX,32 + // ear %rX,%a1 + // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ + // lgrl %r2,.LC0 R_390_PC32DBL .LC0 + // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x + // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset + // la %r2,0(%r2,%rX) + // + // .LC0: + // .quad x@TLSGD R_390_TLS_GD64 x + // + // Relaxing to initial-exec entails: + // 1) Replacing the call by a load from the GOT. + // 2) Replacing the relocation on the constant LC0 by R_390_TLS_GOTIE64. + + switch (rel.type) { + case R_390_TLS_GDCALL: + // brasl %r14,__tls_get_offset@plt -> lg %r2,0(%r2,%r12) + write16be(loc, 0xe322); + write32be(loc + 2, 0xc0000004); + break; + case R_390_TLS_GD64: + relocateNoSym(loc, R_390_TLS_GOTIE64, val); + break; + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); + } +} + +void SystemZ::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + // The general-dynamic code sequence for a global `x`: + // + // Instruction Relocation Symbol + // ear %rX,%a0 + // sllg %rX,%rX,32 + // ear %rX,%a1 + // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ + // lgrl %r2,.LC0 R_390_PC32DBL .LC0 + // brasl %r14,__tls_get_offset@plt R_390_TLS_GDCALL x + // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset + // la %r2,0(%r2,%rX) + // + // .LC0: + // .quad x@tlsgd R_390_TLS_GD64 x + // + // Relaxing to local-exec entails: + // 1) Replacing the call by a nop. + // 2) Replacing the relocation on the constant LC0 by R_390_TLS_LE64. + + switch (rel.type) { + case R_390_TLS_GDCALL: + // brasl %r14,__tls_get_offset@plt -> brcl 0,. + write16be(loc, 0xc004); + write32be(loc + 2, 0x00000000); + break; + case R_390_TLS_GD64: + relocateNoSym(loc, R_390_TLS_LE64, val); + break; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} + +void SystemZ::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + // The local-dynamic code sequence for a global `x`: + // + // Instruction Relocation Symbol + // ear %rX,%a0 + // sllg %rX,%rX,32 + // ear %rX,%a1 + // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_ + // lgrl %r2,.LC0 R_390_PC32DBL .LC0 + // brasl %r14,__tls_get_offset@plt R_390_TLS_LDCALL <sym> + // :tls_ldcall:<sym> R_390_PLT32DBL __tls_get_offset + // la %r2,0(%r2,%rX) + // lgrl %rY,.LC1 R_390_PC32DBL .LC1 + // la %r2,0(%r2,%rY) + // + // .LC0: + // .quad <sym>@tlsldm R_390_TLS_LDM64 <sym> + // .LC1: + // .quad x@dtpoff R_390_TLS_LDO64 x + // + // Relaxing to local-exec entails: + // 1) Replacing the call by a nop. + // 2) Replacing the constant LC0 by 0 (i.e. ignoring the relocation). + // 3) Replacing the relocation on the constant LC1 by R_390_TLS_LE64. + + switch (rel.type) { + case R_390_TLS_LDCALL: + // brasl %r14,__tls_get_offset@plt -> brcl 0,. + write16be(loc, 0xc004); + write32be(loc + 2, 0x00000000); + break; + case R_390_TLS_LDM64: + break; + case R_390_TLS_LDO64: + relocateNoSym(loc, R_390_TLS_LE64, val); + break; + default: + llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); + } +} + +RelExpr SystemZ::adjustGotPcExpr(RelType type, int64_t addend, + const uint8_t *loc) const { + // Only R_390_GOTENT with addend 2 can be relaxed. + if (!config->relax || addend != 2 || type != R_390_GOTENT) + return R_GOT_PC; + const uint16_t op = read16be(loc - 2); + + // lgrl rx,sym@GOTENT -> larl rx, sym + // This relaxation is legal if "sym" binds locally (which was already + // verified by our caller) and is in-range and properly aligned for a + // LARL instruction. We cannot verify the latter constraint here, so + // we assume it is true and revert the decision later on in relaxOnce + // if necessary. + if ((op & 0xff0f) == 0xc408) + return R_RELAX_GOT_PC; + + return R_GOT_PC; +} + +bool SystemZ::relaxOnce(int pass) const { + // If we decided in adjustGotPcExpr to relax a R_390_GOTENT, + // we need to validate the target symbol is in-range and aligned. + SmallVector<InputSection *, 0> storage; + bool changed = false; + for (OutputSection *osec : outputSections) { + if (!(osec->flags & SHF_EXECINSTR)) + continue; + for (InputSection *sec : getInputSections(*osec, storage)) { + for (Relocation &rel : sec->relocs()) { + if (rel.expr != R_RELAX_GOT_PC) + continue; + + uint64_t v = sec->getRelocTargetVA( + sec->file, rel.type, rel.addend, + sec->getOutputSection()->addr + rel.offset, *rel.sym, rel.expr); + if (isInt<33>(v) && !(v & 1)) + continue; + if (rel.sym->auxIdx == 0) { + rel.sym->allocateAux(); + addGotEntry(*rel.sym); + changed = true; + } + rel.expr = R_GOT_PC; + } + } + } + return changed; +} + +void SystemZ::relaxGot(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + assert(isInt<33>(val) && + "R_390_GOTENT should not have been relaxed if it overflows"); + assert(!(val & 1) && + "R_390_GOTENT should not have been relaxed if it is misaligned"); + const uint16_t op = read16be(loc - 2); + + // lgrl rx,sym@GOTENT -> larl rx, sym + if ((op & 0xff0f) == 0xc408) { + write16be(loc - 2, 0xc000 | (op & 0x00f0)); + write32be(loc, val >> 1); + } +} + +void SystemZ::relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.expr) { + case R_RELAX_GOT_PC: + return relaxGot(loc, rel, val); + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: + return relaxTlsGdToIe(loc, rel, val); + case R_RELAX_TLS_GD_TO_LE: + return relaxTlsGdToLe(loc, rel, val); + case R_RELAX_TLS_LD_TO_LE: + return relaxTlsLdToLe(loc, rel, val); + default: + break; + } + switch (rel.type) { + case R_390_8: + checkIntUInt(loc, val, 8, rel); + *loc = val; + break; + case R_390_12: + case R_390_GOT12: + case R_390_GOTPLT12: + case R_390_TLS_GOTIE12: + checkUInt(loc, val, 12, rel); + write16be(loc, (read16be(loc) & 0xF000) | val); + break; + case R_390_PC12DBL: + case R_390_PLT12DBL: + checkInt(loc, val, 13, rel); + checkAlignment(loc, val, 2, rel); + write16be(loc, (read16be(loc) & 0xF000) | ((val >> 1) & 0x0FFF)); + break; + case R_390_16: + case R_390_GOT16: + case R_390_GOTPLT16: + case R_390_GOTOFF16: + case R_390_PLTOFF16: + checkIntUInt(loc, val, 16, rel); + write16be(loc, val); + break; + case R_390_PC16: + checkInt(loc, val, 16, rel); + write16be(loc, val); + break; + case R_390_PC16DBL: + case R_390_PLT16DBL: + checkInt(loc, val, 17, rel); + checkAlignment(loc, val, 2, rel); + write16be(loc, val >> 1); + break; + case R_390_20: + case R_390_GOT20: + case R_390_GOTPLT20: + case R_390_TLS_GOTIE20: + checkInt(loc, val, 20, rel); + write32be(loc, (read32be(loc) & 0xF00000FF) | ((val & 0xFFF) << 16) | + ((val & 0xFF000) >> 4)); + break; + case R_390_PC24DBL: + case R_390_PLT24DBL: + checkInt(loc, val, 25, rel); + checkAlignment(loc, val, 2, rel); + loc[0] = val >> 17; + loc[1] = val >> 9; + loc[2] = val >> 1; + break; + case R_390_32: + case R_390_GOT32: + case R_390_GOTPLT32: + case R_390_GOTOFF: + case R_390_PLTOFF32: + case R_390_TLS_IE32: + case R_390_TLS_GOTIE32: + case R_390_TLS_GD32: + case R_390_TLS_LDM32: + case R_390_TLS_LDO32: + case R_390_TLS_LE32: + checkIntUInt(loc, val, 32, rel); + write32be(loc, val); + break; + case R_390_PC32: + case R_390_PLT32: + checkInt(loc, val, 32, rel); + write32be(loc, val); + break; + case R_390_PC32DBL: + case R_390_PLT32DBL: + case R_390_GOTPCDBL: + case R_390_GOTENT: + case R_390_GOTPLTENT: + case R_390_TLS_IEENT: + checkInt(loc, val, 33, rel); + checkAlignment(loc, val, 2, rel); + write32be(loc, val >> 1); + break; + case R_390_64: + case R_390_PC64: + case R_390_PLT64: + case R_390_GOT64: + case R_390_GOTPLT64: + case R_390_GOTOFF64: + case R_390_PLTOFF64: + case R_390_GOTPC: + case R_390_TLS_IE64: + case R_390_TLS_GOTIE64: + case R_390_TLS_GD64: + case R_390_TLS_LDM64: + case R_390_TLS_LDO64: + case R_390_TLS_LE64: + case R_390_TLS_DTPMOD: + case R_390_TLS_DTPOFF: + case R_390_TLS_TPOFF: + write64be(loc, val); + break; + case R_390_TLS_LOAD: + case R_390_TLS_GDCALL: + case R_390_TLS_LDCALL: + break; + default: + llvm_unreachable("unknown relocation"); + } +} + +TargetInfo *elf::getSystemZTargetInfo() { + static SystemZ t; + return &t; +} diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index f4b7d1c9d5b9..8b2c32b15348 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -200,6 +200,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { .Case("msp430elf", {ELF32LEKind, EM_MSP430}) .Case("elf64_amdgpu", {ELF64LEKind, EM_AMDGPU}) .Case("elf64loongarch", {ELF64LEKind, EM_LOONGARCH}) + .Case("elf64_s390", {ELF64BEKind, EM_S390}) .Default({ELFNoneKind, EM_NONE}); if (ret.first == ELFNoneKind) @@ -1137,7 +1138,7 @@ static SmallVector<StringRef, 0> getSymbolOrderingFile(MemoryBufferRef mb) { static bool getIsRela(opt::InputArgList &args) { // The psABI specifies the default relocation entry format. bool rela = is_contained({EM_AARCH64, EM_AMDGPU, EM_HEXAGON, EM_LOONGARCH, - EM_PPC, EM_PPC64, EM_RISCV, EM_X86_64}, + EM_PPC, EM_PPC64, EM_RISCV, EM_S390, EM_X86_64}, config->emachine); // If -z rel or -z rela is specified, use the last option. for (auto *arg : args.filtered(OPT_z)) { diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index a292e873e72f..6c7ef27cbd49 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1614,6 +1614,8 @@ static uint16_t getBitcodeMachineKind(StringRef path, const Triple &t) { return EM_RISCV; case Triple::sparcv9: return EM_SPARCV9; + case Triple::systemz: + return EM_S390; case Triple::x86: return t.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 0e0b9783bd88..e033a715b592 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -354,9 +354,10 @@ InputSectionBase *InputSection::getRelocatedSection() const { template <class ELFT, class RelTy> void InputSection::copyRelocations(uint8_t *buf) { - if (config->relax && !config->relocatable && config->emachine == EM_RISCV) { - // On RISC-V, relaxation might change relocations: copy from internal ones - // that are updated by relaxation. + if (config->relax && !config->relocatable && + (config->emachine == EM_RISCV || config->emachine == EM_LOONGARCH)) { + // On LoongArch and RISC-V, relaxation might change relocations: copy + // from internal ones that are updated by relaxation. InputSectionBase *sec = getRelocatedSection(); copyRelocations<ELFT, RelTy>(buf, llvm::make_range(sec->relocations.begin(), sec->relocations.end())); @@ -654,6 +655,7 @@ static int64_t getTlsTpOffset(const Symbol &s) { // Variant 2. case EM_HEXAGON: + case EM_S390: case EM_SPARCV9: case EM_386: case EM_X86_64: @@ -716,6 +718,10 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: return sym.getGotVA() + a - p; + case R_GOTPLT_GOTREL: + return sym.getGotPltVA() + a - in.got->getVA(); + case R_GOTPLT_PC: + return sym.getGotPltVA() + a - p; case R_LOONGARCH_GOT_PAGE_PC: if (sym.hasFlag(NEEDS_TLSGD)) return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p, type); @@ -807,6 +813,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, return getLoongArchPageDelta(sym.getPltVA() + a, p, type); case R_PLT_GOTPLT: return sym.getPltVA() + a - in.gotPlt->getVA(); + case R_PLT_GOTREL: + return sym.getPltVA() + a - in.got->getVA(); case R_PPC32_PLTREL: // R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30 // stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index dda4242d8be1..243b28d90bb4 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -102,7 +102,23 @@ protected: link(link), info(info) {} }; -struct RISCVRelaxAux; +struct SymbolAnchor { + uint64_t offset; + Defined *d; + bool end; // true for the anchor of st_value+st_size +}; + +struct RelaxAux { + // This records symbol start and end offsets which will be adjusted according + // to the nearest relocDeltas element. + SmallVector<SymbolAnchor, 0> anchors; + // For relocations[i], the actual offset is + // r_offset - (i ? relocDeltas[i-1] : 0). + std::unique_ptr<uint32_t[]> relocDeltas; + // For relocations[i], the actual type is relocTypes[i]. + std::unique_ptr<RelType[]> relocTypes; + SmallVector<uint32_t, 0> writes; +}; // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { @@ -226,9 +242,9 @@ public: // basic blocks. JumpInstrMod *jumpInstrMod = nullptr; - // Auxiliary information for RISC-V linker relaxation. RISC-V does not use - // jumpInstrMod. - RISCVRelaxAux *relaxAux; + // Auxiliary information for RISC-V and LoongArch linker relaxation. + // They do not use jumpInstrMod. + RelaxAux *relaxAux; // The compressed content size when `compressed` is true. size_t compressedSize; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 79c8230724ad..619fbaf5dc54 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -203,8 +203,9 @@ static bool isAbsoluteValue(const Symbol &sym) { // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr expr) { - return oneof<R_PLT, R_PLT_PC, R_PLT_GOTPLT, R_LOONGARCH_PLT_PAGE_PC, - R_PPC32_PLTREL, R_PPC64_CALL_PLT>(expr); + return oneof<R_PLT, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, + R_GOTPLT_PC, R_LOONGARCH_PLT_PAGE_PC, R_PPC32_PLTREL, + R_PPC64_CALL_PLT>(expr); } bool lld::elf::needsGot(RelExpr expr) { @@ -233,6 +234,8 @@ static RelExpr toPlt(RelExpr expr) { return R_PLT_PC; case R_ABS: return R_PLT; + case R_GOTREL: + return R_PLT_GOTREL; default: return expr; } @@ -253,6 +256,8 @@ static RelExpr fromPlt(RelExpr expr) { return R_ABS; case R_PLT_GOTPLT: return R_GOTPLTREL; + case R_PLT_GOTREL: + return R_GOTREL; default: return expr; } @@ -935,7 +940,7 @@ void elf::addGotEntry(Symbol &sym) { static void addTpOffsetGotEntry(Symbol &sym) { in.got->addEntry(sym); uint64_t off = sym.getGotOffset(); - if (!sym.isPreemptible && !config->isPic) { + if (!sym.isPreemptible && !config->shared) { in.got->addConstant({R_TPREL, target->symbolicRel, off, 0, &sym}); return; } @@ -979,10 +984,10 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, - R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT, - R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE, - R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>( - e)) + R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC, + R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, + R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, + R_LOONGARCH_GOT_PAGE_PC>(e)) return true; // These never do, except if the entire file is position dependent or if @@ -1374,8 +1379,8 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, R_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF, R_TLSIE_HINT>(expr)) { ctx.hasTlsIe.store(true, std::memory_order_relaxed); // Initial-Exec relocs can be optimized to Local-Exec if the symbol is - // locally defined. - if (execOptimize && isLocalInExecutable) { + // locally defined. This is not supported on SystemZ. + if (execOptimize && isLocalInExecutable && config->emachine != EM_S390) { c.addReloc({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym}); } else if (expr != R_TLSIE_HINT) { sym.setFlags(NEEDS_TLSIE); @@ -1534,8 +1539,10 @@ void RelocationScanner::scan(ArrayRef<RelTy> rels) { // For EhInputSection, OffsetGetter expects the relocations to be sorted by // r_offset. In rare cases (.eh_frame pieces are reordered by a linker // script), the relocations may be unordered. + // On SystemZ, all sections need to be sorted by r_offset, to allow TLS + // relaxation to be handled correctly - see SystemZ::getTlsGdRelaxSkip. SmallVector<RelTy, 0> storage; - if (isa<EhInputSection>(sec)) + if (isa<EhInputSection>(sec) || config->emachine == EM_S390) rels = sortRels(rels, storage); end = static_cast<const void *>(rels.end()); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index cfb9092149f3..7eb8a811e693 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -40,11 +40,14 @@ enum RelExpr { R_GOTPLT, R_GOTPLTREL, R_GOTREL, + R_GOTPLT_GOTREL, + R_GOTPLT_PC, R_NONE, R_PC, R_PLT, R_PLT_PC, R_PLT_GOTPLT, + R_PLT_GOTREL, R_RELAX_HINT, R_RELAX_GOT_PC, R_RELAX_GOT_PC_NOPIC, diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index dd69916d6b05..f0ede1f43bbd 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -445,6 +445,7 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { .Case("elf32-msp430", {ELF32LEKind, EM_MSP430}) .Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH}) .Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH}) + .Case("elf64-s390", {ELF64BEKind, EM_S390}) .Default({ELFNoneKind, EM_NONE}); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 4b413163314b..bada394aa30d 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1419,6 +1419,9 @@ DynamicSection<ELFT>::computeContents() { case EM_MIPS: addInSec(DT_MIPS_PLTGOT, *in.gotPlt); break; + case EM_S390: + addInSec(DT_PLTGOT, *in.got); + break; case EM_SPARCV9: addInSec(DT_PLTGOT, *in.plt); break; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 671d22cc66a0..b7922425a34e 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -87,6 +87,8 @@ TargetInfo *elf::getTarget() { return getRISCVTargetInfo(); case EM_SPARCV9: return getSPARCV9TargetInfo(); + case EM_S390: + return getSystemZTargetInfo(); case EM_X86_64: return getX86_64TargetInfo(); } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index ab6b6b9c013b..0cefa3181356 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -95,6 +95,8 @@ public: // Do a linker relaxation pass and return true if we changed something. virtual bool relaxOnce(int pass) const { return false; } + // Do finalize relaxation after collecting relaxation infos. + virtual void finalizeRelax(int passes) const {} virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type, JumpModType val) const {} @@ -186,6 +188,7 @@ TargetInfo *getPPC64TargetInfo(); TargetInfo *getPPCTargetInfo(); TargetInfo *getRISCVTargetInfo(); TargetInfo *getSPARCV9TargetInfo(); +TargetInfo *getSystemZTargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); template <class ELFT> TargetInfo *getMipsTargetInfo(); @@ -236,6 +239,7 @@ void addArmSyntheticSectionMappingSymbol(Defined *); void sortArmMappingSymbols(); void convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf); void createTaggedSymbols(const SmallVector<ELFFileBase *, 0> &files); +void initSymbolAnchors(); LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target; TargetInfo *getTarget(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 501c10f35849..6df43a34be01 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1752,8 +1752,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { } } } - if (!config->relocatable && config->emachine == EM_RISCV) - riscvFinalizeRelax(pass); + if (!config->relocatable) + target->finalizeRelax(pass); if (config->relocatable) for (OutputSection *sec : outputSections) diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index fa0e7f2bc0b3..56ba3463aead 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -82,9 +82,46 @@ COFF Improvements * Added support for ``--time-trace`` and associated ``--time-trace-granularity``. This generates a .json profile trace of the linker execution. + (`#68236 <https://github.com/llvm/llvm-project/pull/68236>`_) + +* The ``-dependentloadflag`` option was implemented. + (`#71537 <https://github.com/llvm/llvm-project/pull/71537>`_) * LLD now prefers library paths specified with ``-libpath:`` over the implicitly detected toolchain paths. + (`#78039 <https://github.com/llvm/llvm-project/pull/78039>`_) + +* Added new options ``-lldemit:llvm`` and ``-lldemit:asm`` for getting + the output of LTO compilation as LLVM bitcode or assembly. + (`#66964 <https://github.com/llvm/llvm-project/pull/66964>`_) + (`#67079 <https://github.com/llvm/llvm-project/pull/67079>`_) + +* Added a new option ``-build-id`` for generating a ``.buildid`` section + when not generating a PDB. A new symbol ``__buildid`` is generated by + the linker, allowing code to reference the build ID of the binary. + (`#71433 <https://github.com/llvm/llvm-project/pull/71433>`_) + (`#74652 <https://github.com/llvm/llvm-project/pull/74652>`_) + +* A new, LLD specific option, ``-lld-allow-duplicate-weak``, was added + for allowing duplicate weak symbols. + (`#68077 <https://github.com/llvm/llvm-project/pull/68077>`_) + +* More correctly handle LTO of files that define ``__imp_`` prefixed dllimport + redirections. + (`#70777 <https://github.com/llvm/llvm-project/pull/70777>`_) + (`#71376 <https://github.com/llvm/llvm-project/pull/71376>`_) + (`#72989 <https://github.com/llvm/llvm-project/pull/72989>`_) + +* Linking undefined references to weak symbols with LTO now works. + (`#70430 <https://github.com/llvm/llvm-project/pull/70430>`_) + +* Use the ``SOURCE_DATE_EPOCH`` environment variable for the PE header and + debug directory timestamps, if neither the ``/Brepro`` nor ``/timestamp:`` + options have been specified. This makes the linker output reproducible by + setting this environment variable. + (`#81326 <https://github.com/llvm/llvm-project/pull/81326>`_) + +* Lots of incremental work towards supporting linking ARM64EC binaries. MinGW Improvements ------------------ @@ -92,19 +129,29 @@ MinGW Improvements * Added support for many LTO and ThinLTO options (most LTO options supported by the ELF driver, that are implemented by the COFF backend as well, should be supported now). + (`D158412 <https://reviews.llvm.org/D158412>`_) + (`D158887 <https://reviews.llvm.org/D158887>`_) + (`#77387 <https://github.com/llvm/llvm-project/pull/77387>`_) + (`#81475 <https://github.com/llvm/llvm-project/pull/81475>`_) * LLD no longer tries to autodetect and use library paths from MSVC/WinSDK installations when run in MinGW mode; that mode of operation shouldn't ever be needed in MinGW mode, and could be a source of unexpected behaviours. + (`D144084 <https://reviews.llvm.org/D144084>`_) * The ``--icf=safe`` option now works as expected; it was previously a no-op. - -* More correctly handle LTO of files that define ``__imp_`` prefixed dllimport - redirections. + (`#70037 <https://github.com/llvm/llvm-project/pull/70037>`_) * The strip flags ``-S`` and ``-s`` now can be used to strip out DWARF debug info and symbol tables while emitting a PDB debug info file. + (`#75181 <https://github.com/llvm/llvm-project/pull/75181>`_) + +* The option ``--dll`` is handled as an alias for the ``--shared`` option. + (`#68575 <https://github.com/llvm/llvm-project/pull/68575>`_) + +* The option ``--sort-common`` is ignored now. + (`#66336 <https://github.com/llvm/llvm-project/pull/66336>`_) MachO Improvements ------------------ diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 81cdd39afc6b..f17ba75e3efa 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1464,6 +1464,7 @@ enum { PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data. PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations. PT_OPENBSD_NOBTCFI = 0x65a3dbe8, // Do not enforce branch target CFI. + PT_OPENBSD_SYSCALLS = 0x65a3dbe9, // System call sites. PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. // ARM program header types. diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 5d6c3465a0c3..412115eb649c 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -5083,8 +5083,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts, Op->getOperand(0)->getType()->getScalarType()->getFltSemantics(); // All subnormal inputs should be in the normal range in the result type. - if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) + if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) { + if (Known.KnownFPClasses & fcPosSubnormal) + Known.KnownFPClasses |= fcPosNormal; + if (Known.KnownFPClasses & fcNegSubnormal) + Known.KnownFPClasses |= fcNegNormal; Known.knownNot(fcSubnormal); + } // Sign bit of a nan isn't guaranteed. if (!Known.isKnownNeverNaN()) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 3b2cf3191092..c0c22e36004f 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -596,6 +596,8 @@ llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, LostDebugLocObserver &LocObserver, MachineInstr *MI) { auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); const char *Name = TLI.getLibcallName(Libcall); + if (!Name) + return LegalizerHelper::UnableToLegalize; const CallingConv::ID CC = TLI.getLibcallCallingConv(Libcall); return createLibcall(MIRBuilder, Name, Result, Args, CC, LocObserver, MI); } diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp index cbb1a74049fb..7e9c992031f8 100644 --- a/llvm/lib/CodeGen/RegisterCoalescer.cpp +++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp @@ -236,7 +236,8 @@ namespace { /// was successfully coalesced away. If it is not currently possible to /// coalesce this interval, but it may be possible if other things get /// coalesced, then it returns true by reference in 'Again'. - bool joinCopy(MachineInstr *CopyMI, bool &Again); + bool joinCopy(MachineInstr *CopyMI, bool &Again, + SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs); /// Attempt to join these two intervals. On failure, this /// returns false. The output "SrcInt" will not have been modified, so we @@ -1964,7 +1965,9 @@ void RegisterCoalescer::setUndefOnPrunedSubRegUses(LiveInterval &LI, LIS->shrinkToUses(&LI); } -bool RegisterCoalescer::joinCopy(MachineInstr *CopyMI, bool &Again) { +bool RegisterCoalescer::joinCopy( + MachineInstr *CopyMI, bool &Again, + SmallPtrSetImpl<MachineInstr *> &CurrentErasedInstrs) { Again = false; LLVM_DEBUG(dbgs() << LIS->getInstructionIndex(*CopyMI) << '\t' << *CopyMI); @@ -2156,7 +2159,9 @@ bool RegisterCoalescer::joinCopy(MachineInstr *CopyMI, bool &Again) { // CopyMI has been erased by joinIntervals at this point. Remove it from // ErasedInstrs since copyCoalesceWorkList() won't add a successful join back // to the work list. This keeps ErasedInstrs from growing needlessly. - ErasedInstrs.erase(CopyMI); + if (ErasedInstrs.erase(CopyMI)) + // But we may encounter the instruction again in this iteration. + CurrentErasedInstrs.insert(CopyMI); // Rewrite all SrcReg operands to DstReg. // Also update DstReg operands to include DstIdx if it is set. @@ -3982,21 +3987,33 @@ void RegisterCoalescer::lateLiveIntervalUpdate() { bool RegisterCoalescer:: copyCoalesceWorkList(MutableArrayRef<MachineInstr*> CurrList) { bool Progress = false; + SmallPtrSet<MachineInstr *, 4> CurrentErasedInstrs; for (MachineInstr *&MI : CurrList) { if (!MI) continue; // Skip instruction pointers that have already been erased, for example by // dead code elimination. - if (ErasedInstrs.count(MI)) { + if (ErasedInstrs.count(MI) || CurrentErasedInstrs.count(MI)) { MI = nullptr; continue; } bool Again = false; - bool Success = joinCopy(MI, Again); + bool Success = joinCopy(MI, Again, CurrentErasedInstrs); Progress |= Success; if (Success || !Again) MI = nullptr; } + // Clear instructions not recorded in `ErasedInstrs` but erased. + if (!CurrentErasedInstrs.empty()) { + for (MachineInstr *&MI : CurrList) { + if (MI && CurrentErasedInstrs.count(MI)) + MI = nullptr; + } + for (MachineInstr *&MI : WorkList) { + if (MI && CurrentErasedInstrs.count(MI)) + MI = nullptr; + } + } return Progress; } diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 98d8a6d9409f..3135ec73a99e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -9253,7 +9253,7 @@ SDValue DAGCombiner::MatchLoadCombine(SDNode *N) { // Transfer chain users from old loads to the new load. for (LoadSDNode *L : Loads) - DAG.ReplaceAllUsesOfValueWith(SDValue(L, 1), SDValue(NewLoad.getNode(), 1)); + DAG.makeEquivalentMemoryOrdering(L, NewLoad); if (!NeedsBswap) return NewLoad; diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index e97f5e322014..0287856560e9 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10718,6 +10718,14 @@ AArch64TargetLowering::getRegForInlineAsmConstraint( parseConstraintCode(Constraint) != AArch64CC::Invalid) return std::make_pair(unsigned(AArch64::NZCV), &AArch64::CCRRegClass); + if (Constraint == "{za}") { + return std::make_pair(unsigned(AArch64::ZA), &AArch64::MPRRegClass); + } + + if (Constraint == "{zt0}") { + return std::make_pair(unsigned(AArch64::ZT0), &AArch64::ZTRRegClass); + } + // Use the default implementation in TargetLowering to convert the register // constraint into a member of a register class. std::pair<unsigned, const TargetRegisterClass *> Res; @@ -24419,7 +24427,8 @@ void AArch64TargetLowering::ReplaceBITCASTResults( return; } - if (SrcVT.isVector() && SrcVT.getVectorElementType() == MVT::i1) + if (SrcVT.isVector() && SrcVT.getVectorElementType() == MVT::i1 && + !VT.isVector()) return replaceBoolVectorBitcast(N, Results, DAG); if (VT != MVT::i16 || (SrcVT != MVT::f16 && SrcVT != MVT::bf16)) diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp index f86e6947c9cd..48e1c1bc7302 100644 --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -507,6 +507,10 @@ bool AArch64RegisterInfo::isAsmClobberable(const MachineFunction &MF, MCRegisterInfo::regsOverlap(PhysReg, AArch64::X16)) return true; + // ZA/ZT0 registers are reserved but may be permitted in the clobber list. + if (PhysReg == AArch64::ZA || PhysReg == AArch64::ZT0) + return true; + return !isReservedReg(MF, PhysReg); } diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp index fd69a7d6c33d..4b9d549e7911 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -622,9 +622,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) .lowerIf([=](const LegalityQuery &Query) { LLT DstTy = Query.Types[0]; LLT SrcTy = Query.Types[1]; - return DstTy.isVector() && (SrcTy.getSizeInBits() > 128 || - (DstTy.getScalarSizeInBits() * 2 < - SrcTy.getScalarSizeInBits())); + return DstTy.isVector() && SrcTy.getSizeInBits() > 128 && + DstTy.getScalarSizeInBits() * 2 <= SrcTy.getScalarSizeInBits(); }) .alwaysLegal(); diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 3c673ae938fd..36aab383da68 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -2920,6 +2920,11 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr, (Res.getSymA()->getSymbol().isELF() && cast<MCSymbolELF>(Res.getSymA()->getSymbol()).getBinding() == ELF::STB_LOCAL); + // For O32, "$"-prefixed symbols are recognized as temporary while + // .L-prefixed symbols are not (PrivateGlobalPrefix is "$"). Recognize ".L" + // manually. + if (ABI.IsO32() && Res.getSymA()->getSymbol().getName().starts_with(".L")) + IsLocalSym = true; bool UseXGOT = STI->hasFeature(Mips::FeatureXGOT) && !IsLocalSym; // The case where the result register is $25 is somewhat special. If the @@ -6359,7 +6364,7 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - MCSymbol *Sym = getContext().getOrCreateSymbol("$" + Identifier); + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); // Otherwise create a symbol reference. const MCExpr *SymRef = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 7895d74f06d1..80447d03c000 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -5033,60 +5033,56 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG, MVT IndexContainerVT = ContainerVT.changeVectorElementType(IndexVT.getScalarType()); - // Base case for the recursion just below - handle the worst case - // single source permutation. Note that all the splat variants - // are handled above. - if (V2.isUndef()) { + SDValue Gather; + // TODO: This doesn't trigger for i64 vectors on RV32, since there we + // encounter a bitcasted BUILD_VECTOR with low/high i32 values. + if (SDValue SplatValue = DAG.getSplatValue(V1, /*LegalTypes*/ true)) { + Gather = lowerScalarSplat(SDValue(), SplatValue, VL, ContainerVT, DL, DAG, + Subtarget); + } else { V1 = convertToScalableVector(ContainerVT, V1, DAG, Subtarget); - SDValue LHSIndices = DAG.getBuildVector(IndexVT, DL, GatherIndicesLHS); - LHSIndices = convertToScalableVector(IndexContainerVT, LHSIndices, DAG, - Subtarget); - SDValue Gather = DAG.getNode(GatherVVOpc, DL, ContainerVT, V1, LHSIndices, - DAG.getUNDEF(ContainerVT), TrueMask, VL); - return convertFromScalableVector(VT, Gather, DAG, Subtarget); - } - - // Translate the gather index we computed above (and possibly swapped) - // back to a shuffle mask. This step should disappear once we complete - // the migration to recursive design. - SmallVector<int> ShuffleMaskLHS; - ShuffleMaskLHS.reserve(GatherIndicesLHS.size()); - for (SDValue GatherIndex : GatherIndicesLHS) { - if (GatherIndex.isUndef()) { - ShuffleMaskLHS.push_back(-1); - continue; + // If only one index is used, we can use a "splat" vrgather. + // TODO: We can splat the most-common index and fix-up any stragglers, if + // that's beneficial. + if (LHSIndexCounts.size() == 1) { + int SplatIndex = LHSIndexCounts.begin()->getFirst(); + Gather = DAG.getNode(GatherVXOpc, DL, ContainerVT, V1, + DAG.getConstant(SplatIndex, DL, XLenVT), + DAG.getUNDEF(ContainerVT), TrueMask, VL); + } else { + SDValue LHSIndices = DAG.getBuildVector(IndexVT, DL, GatherIndicesLHS); + LHSIndices = + convertToScalableVector(IndexContainerVT, LHSIndices, DAG, Subtarget); + + Gather = DAG.getNode(GatherVVOpc, DL, ContainerVT, V1, LHSIndices, + DAG.getUNDEF(ContainerVT), TrueMask, VL); } - auto *IdxC = cast<ConstantSDNode>(GatherIndex); - ShuffleMaskLHS.push_back(IdxC->getZExtValue()); } - // Recursively invoke lowering for the LHS as if there were no RHS. - // This allows us to leverage all of our single source permute tricks. - SDValue Gather = - DAG.getVectorShuffle(VT, DL, V1, DAG.getUNDEF(VT), ShuffleMaskLHS); - Gather = convertToScalableVector(ContainerVT, Gather, DAG, Subtarget); + // If a second vector operand is used by this shuffle, blend it in with an + // additional vrgather. + if (!V2.isUndef()) { + V2 = convertToScalableVector(ContainerVT, V2, DAG, Subtarget); - // Blend in second vector source with an additional vrgather. - V2 = convertToScalableVector(ContainerVT, V2, DAG, Subtarget); + MVT MaskContainerVT = ContainerVT.changeVectorElementType(MVT::i1); + SelectMask = + convertToScalableVector(MaskContainerVT, SelectMask, DAG, Subtarget); - MVT MaskContainerVT = ContainerVT.changeVectorElementType(MVT::i1); - SelectMask = - convertToScalableVector(MaskContainerVT, SelectMask, DAG, Subtarget); - - // If only one index is used, we can use a "splat" vrgather. - // TODO: We can splat the most-common index and fix-up any stragglers, if - // that's beneficial. - if (RHSIndexCounts.size() == 1) { - int SplatIndex = RHSIndexCounts.begin()->getFirst(); - Gather = DAG.getNode(GatherVXOpc, DL, ContainerVT, V2, - DAG.getConstant(SplatIndex, DL, XLenVT), Gather, - SelectMask, VL); - } else { - SDValue RHSIndices = DAG.getBuildVector(IndexVT, DL, GatherIndicesRHS); - RHSIndices = - convertToScalableVector(IndexContainerVT, RHSIndices, DAG, Subtarget); - Gather = DAG.getNode(GatherVVOpc, DL, ContainerVT, V2, RHSIndices, Gather, - SelectMask, VL); + // If only one index is used, we can use a "splat" vrgather. + // TODO: We can splat the most-common index and fix-up any stragglers, if + // that's beneficial. + if (RHSIndexCounts.size() == 1) { + int SplatIndex = RHSIndexCounts.begin()->getFirst(); + Gather = DAG.getNode(GatherVXOpc, DL, ContainerVT, V2, + DAG.getConstant(SplatIndex, DL, XLenVT), Gather, + SelectMask, VL); + } else { + SDValue RHSIndices = DAG.getBuildVector(IndexVT, DL, GatherIndicesRHS); + RHSIndices = + convertToScalableVector(IndexContainerVT, RHSIndices, DAG, Subtarget); + Gather = DAG.getNode(GatherVVOpc, DL, ContainerVT, V2, RHSIndices, Gather, + SelectMask, VL); + } } return convertFromScalableVector(VT, Gather, DAG, Subtarget); @@ -14658,8 +14654,8 @@ static SDValue useInversedSetcc(SDNode *N, SelectionDAG &DAG, ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get(); if (CC == ISD::SETEQ && LHS.getOpcode() == ISD::AND && isa<ConstantSDNode>(LHS.getOperand(1)) && isNullConstant(RHS)) { - uint64_t MaskVal = LHS.getConstantOperandVal(1); - if (isPowerOf2_64(MaskVal) && !isInt<12>(MaskVal)) + const APInt &MaskVal = LHS.getConstantOperandAPInt(1); + if (MaskVal.isPowerOf2() && !MaskVal.isSignedIntN(12)) return DAG.getSelect(DL, VT, DAG.getSetCC(DL, CondVT, LHS, RHS, ISD::SETNE), False, True); @@ -15565,7 +15561,7 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, MGN->getMemOperand(), IndexType, MGN->getExtensionType()); if (Index.getOpcode() == ISD::BUILD_VECTOR && - MGN->getExtensionType() == ISD::NON_EXTLOAD) { + MGN->getExtensionType() == ISD::NON_EXTLOAD && isTypeLegal(VT)) { if (std::optional<VIDSequence> SimpleVID = isSimpleVIDSequence(Index); SimpleVID && SimpleVID->StepDenominator == 1) { const int64_t StepNumerator = SimpleVID->StepNumerator; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 592962cebe89..d5b1ddfbeb3d 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1229,7 +1229,8 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const { MachineBasicBlock::reverse_iterator II(&MI), E = MBB->rend(); auto DefC1 = std::find_if(++II, E, [&](const MachineInstr &I) -> bool { int64_t Imm; - return isLoadImm(&I, Imm) && Imm == C1; + return isLoadImm(&I, Imm) && Imm == C1 && + I.getOperand(0).getReg().isVirtual(); }); if (DefC1 != E) return DefC1->getOperand(0).getReg(); diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index 7b1033956524..38a59e650f33 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -72,6 +72,20 @@ def TuneSlowRDPC : SubtargetFeature<"slow-rdpc", "HasSlowRDPC", "true", //==== Features added predmoninantly for LEON subtarget support include "LeonFeatures.td" +//==== Register allocation tweaks needed by some low-level software +foreach i = 1 ... 7 in + def FeatureReserveG#i : SubtargetFeature<"reserve-g"#i, "ReserveRegister["#i#" + SP::G0]", "true", + "Reserve G"#i#", making it unavailable as a GPR">; +foreach i = 0 ... 5 in + def FeatureReserveO#i : SubtargetFeature<"reserve-o"#i, "ReserveRegister["#i#" + SP::O0]", "true", + "Reserve O"#i#", making it unavailable as a GPR">; +foreach i = 0 ... 7 in + def FeatureReserveL#i : SubtargetFeature<"reserve-l"#i, "ReserveRegister["#i#" + SP::L0]", "true", + "Reserve L"#i#", making it unavailable as a GPR">; +foreach i = 0 ... 5 in + def FeatureReserveI#i : SubtargetFeature<"reserve-i"#i, "ReserveRegister["#i#" + SP::I0]", "true", + "Reserve I"#i#", making it unavailable as a GPR">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 78bdf3ae9a84..bdefb0841a12 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -13,6 +13,7 @@ #include "SparcISelLowering.h" #include "MCTargetDesc/SparcMCExpr.h" +#include "MCTargetDesc/SparcMCTargetDesc.h" #include "SparcMachineFunctionInfo.h" #include "SparcRegisterInfo.h" #include "SparcTargetMachine.h" @@ -28,6 +29,7 @@ #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" @@ -729,6 +731,30 @@ SDValue SparcTargetLowering::LowerFormalArguments_64( return Chain; } +// Check whether any of the argument registers are reserved +static bool isAnyArgRegReserved(const SparcRegisterInfo *TRI, + const MachineFunction &MF) { + // The register window design means that outgoing parameters at O* + // will appear in the callee as I*. + // Be conservative and check both sides of the register names. + bool Outgoing = + llvm::any_of(SP::GPROutgoingArgRegClass, [TRI, &MF](MCPhysReg r) { + return TRI->isReservedReg(MF, r); + }); + bool Incoming = + llvm::any_of(SP::GPRIncomingArgRegClass, [TRI, &MF](MCPhysReg r) { + return TRI->isReservedReg(MF, r); + }); + return Outgoing || Incoming; +} + +static void emitReservedArgRegCallError(const MachineFunction &MF) { + const Function &F = MF.getFunction(); + F.getContext().diagnose(DiagnosticInfoUnsupported{ + F, ("SPARC doesn't support" + " function calls if any of the argument registers is reserved.")}); +} + SDValue SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const { @@ -805,6 +831,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, bool &isTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool isVarArg = CLI.IsVarArg; + MachineFunction &MF = DAG.getMachineFunction(); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -1055,6 +1082,10 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, ((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CallConv) : TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv)); + + if (isAnyArgRegReserved(TRI, MF)) + emitReservedArgRegCallError(MF); + assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); @@ -1125,6 +1156,13 @@ Register SparcTargetLowering::getRegisterByName(const char* RegName, LLT VT, .Case("g4", SP::G4).Case("g5", SP::G5).Case("g6", SP::G6).Case("g7", SP::G7) .Default(0); + // If we're directly referencing register names + // (e.g in GCC C extension `register int r asm("g1");`), + // make sure that said register is in the reserve list. + const SparcRegisterInfo *TRI = Subtarget->getRegisterInfo(); + if (!TRI->isReservedReg(MF, Reg)) + Reg = 0; + if (Reg) return Reg; @@ -1189,6 +1227,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, SDLoc DL = CLI.DL; SDValue Chain = CLI.Chain; auto PtrVT = getPointerTy(DAG.getDataLayout()); + MachineFunction &MF = DAG.getMachineFunction(); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -1372,6 +1411,10 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, ((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CLI.CallConv) : TRI->getCallPreservedMask(DAG.getMachineFunction(), CLI.CallConv)); + + if (isAnyArgRegReserved(TRI, MF)) + emitReservedArgRegCallError(MF); + assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index f97bf57627d1..71a27f77d2c6 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -12,10 +12,8 @@ #include "SparcRegisterInfo.h" #include "Sparc.h" -#include "SparcMachineFunctionInfo.h" #include "SparcSubtarget.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -98,9 +96,21 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const { for (unsigned n = 0; n < 31; n++) Reserved.set(SP::ASR1 + n); + for (TargetRegisterClass::iterator i = SP::IntRegsRegClass.begin(); + i != SP::IntRegsRegClass.end(); ++i) { + if (MF.getSubtarget<SparcSubtarget>().isRegisterReserved(*i)) + markSuperRegs(Reserved, *i); + } + + assert(checkAllSuperRegsMarked(Reserved)); return Reserved; } +bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF, + MCRegister Reg) const { + return getReservedRegs(MF)[Reg]; +} + const TargetRegisterClass* SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind) const { diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.h b/llvm/lib/Target/Sparc/SparcRegisterInfo.h index 5b3c1a7ad07d..58c85f33635f 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.h +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.h @@ -30,6 +30,7 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const; BitVector getReservedRegs(const MachineFunction &MF) const override; + bool isReservedReg(const MachineFunction &MF, MCRegister Reg) const; const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, unsigned Kind) const override; diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.td b/llvm/lib/Target/Sparc/SparcRegisterInfo.td index d5ba7464695c..d8319a8d41dd 100644 --- a/llvm/lib/Target/Sparc/SparcRegisterInfo.td +++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.td @@ -370,6 +370,10 @@ def LowQFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 7)>; // Floating point control register classes. def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>; +// GPR argument registers. +def GPROutgoingArg : RegisterClass<"SP", [i32, i64], 32, (sequence "O%u", 0, 5)>; +def GPRIncomingArg : RegisterClass<"SP", [i32, i64], 32, (sequence "I%u", 0, 5)>; + let isAllocatable = 0 in { // Ancillary state registers // FIXME: TICK is special-cased here as it can be accessed diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp index 6b09904ca5e8..5b65e34e0f8a 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -50,6 +50,7 @@ SparcSubtarget::SparcSubtarget(const StringRef &CPU, const StringRef &TuneCPU, const StringRef &FS, const TargetMachine &TM, bool is64Bit) : SparcGenSubtargetInfo(TM.getTargetTriple(), CPU, TuneCPU, FS), + ReserveRegister(TM.getMCRegisterInfo()->getNumRegs()), TargetTriple(TM.getTargetTriple()), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, TuneCPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index cdb210f67482..fe4aca519530 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -13,12 +13,14 @@ #ifndef LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H #define LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H +#include "MCTargetDesc/SparcMCTargetDesc.h" #include "SparcFrameLowering.h" #include "SparcISelLowering.h" #include "SparcInstrInfo.h" #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/TargetParser/Triple.h" #include <string> @@ -29,6 +31,10 @@ namespace llvm { class StringRef; class SparcSubtarget : public SparcGenSubtargetInfo { + // ReserveRegister[i] - Register #i is not available as a general purpose + // register. + BitVector ReserveRegister; + Triple TargetTriple; virtual void anchor(); @@ -82,6 +88,10 @@ public: return is64Bit() ? 2047 : 0; } + bool isRegisterReserved(MCPhysReg PhysReg) const { + return ReserveRegister[PhysReg]; + } + /// Given a actual stack size as determined by FrameInfo, this function /// returns adjusted framesize which includes space for register window /// spills and arguments. diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index e158312caffd..a071c5a3ca03 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -18703,16 +18703,18 @@ X86TargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { if (Subtarget.isTargetDarwin()) { // Darwin only has one model of TLS. Lower to that. unsigned char OpFlag = 0; - unsigned WrapperKind = Subtarget.isPICStyleRIPRel() ? - X86ISD::WrapperRIP : X86ISD::Wrapper; + unsigned WrapperKind = 0; // In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the // global base reg. bool PIC32 = PositionIndependent && !Subtarget.is64Bit(); - if (PIC32) + if (PIC32) { OpFlag = X86II::MO_TLVP_PIC_BASE; - else + WrapperKind = X86ISD::Wrapper; + } else { OpFlag = X86II::MO_TLVP; + WrapperKind = X86ISD::WrapperRIP; + } SDLoc DL(Op); SDValue Result = DAG.getTargetGlobalAddress(GA->getGlobal(), DL, GA->getValueType(0), diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 733f290b1bc9..633fcb3314c4 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -470,6 +470,9 @@ class LowerTypeTestsModule { Function *WeakInitializerFn = nullptr; + GlobalVariable *GlobalAnnotation; + DenseSet<Value *> FunctionAnnotations; + bool shouldExportConstantsAsAbsoluteSymbols(); uint8_t *exportTypeId(StringRef TypeId, const TypeIdLowering &TIL); TypeIdLowering importTypeId(StringRef TypeId); @@ -531,6 +534,10 @@ class LowerTypeTestsModule { /// replace each use, which is a direct function call. void replaceDirectCalls(Value *Old, Value *New); + bool isFunctionAnnotation(Value *V) const { + return FunctionAnnotations.contains(V); + } + public: LowerTypeTestsModule(Module &M, ModuleAnalysisManager &AM, ModuleSummaryIndex *ExportSummary, @@ -1377,8 +1384,11 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr( // (all?) targets. Switch to a runtime initializer. SmallSetVector<GlobalVariable *, 8> GlobalVarUsers; findGlobalVariableUsersOf(F, GlobalVarUsers); - for (auto *GV : GlobalVarUsers) + for (auto *GV : GlobalVarUsers) { + if (GV == GlobalAnnotation) + continue; moveInitializerToModuleConstructor(GV); + } // Can not RAUW F with an expression that uses F. Replace with a temporary // placeholder first. @@ -1837,6 +1847,16 @@ LowerTypeTestsModule::LowerTypeTestsModule( } OS = TargetTriple.getOS(); ObjectFormat = TargetTriple.getObjectFormat(); + + // Function annotation describes or applies to function itself, and + // shouldn't be associated with jump table thunk generated for CFI. + GlobalAnnotation = M.getGlobalVariable("llvm.global.annotations"); + if (GlobalAnnotation && GlobalAnnotation->hasInitializer()) { + const ConstantArray *CA = + cast<ConstantArray>(GlobalAnnotation->getInitializer()); + for (Value *Op : CA->operands()) + FunctionAnnotations.insert(Op); + } } bool LowerTypeTestsModule::runForTesting(Module &M, ModuleAnalysisManager &AM) { @@ -1896,10 +1916,14 @@ void LowerTypeTestsModule::replaceCfiUses(Function *Old, Value *New, if (isa<BlockAddress, NoCFIValue>(U.getUser())) continue; - // Skip direct calls to externally defined or non-dso_local functions + // Skip direct calls to externally defined or non-dso_local functions. if (isDirectCall(U) && (Old->isDSOLocal() || !IsJumpTableCanonical)) continue; + // Skip function annotation. + if (isFunctionAnnotation(U.getUser())) + continue; + // Must handle Constants specially, we cannot call replaceUsesOfWith on a // constant because they are uniqued. if (auto *C = dyn_cast<Constant>(U.getUser())) { diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 601d2454c1e1..0a9e2c7f49f5 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -10215,8 +10215,18 @@ public: UniqueBases.insert(VecBase); // If the only one use is vectorized - can delete the extractelement // itself. - if (!EI->hasOneUse() || any_of(EI->users(), [&](User *U) { - return !R.ScalarToTreeEntry.count(U); + if (!EI->hasOneUse() || (NumParts != 1 && count(E->Scalars, EI) > 1) || + any_of(EI->users(), [&](User *U) { + const TreeEntry *UTE = R.getTreeEntry(U); + return !UTE || R.MultiNodeScalars.contains(U) || + count_if(R.VectorizableTree, + [&](const std::unique_ptr<TreeEntry> &TE) { + return any_of(TE->UserTreeIndices, + [&](const EdgeInfo &Edge) { + return Edge.UserTE == UTE; + }) && + is_contained(TE->Scalars, EI); + }) != 1; })) continue; R.eraseInstruction(EI); diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h index c287a31e0b1b..259c57b5afbc 100644 --- a/openmp/runtime/src/kmp.h +++ b/openmp/runtime/src/kmp.h @@ -1181,7 +1181,11 @@ extern void __kmp_init_target_task(); #define KMP_MIN_STKSIZE ((size_t)(32 * 1024)) #endif +#if KMP_OS_AIX && KMP_ARCH_PPC +#define KMP_MAX_STKSIZE 0x10000000 /* 256Mb max size on 32-bit AIX */ +#else #define KMP_MAX_STKSIZE (~((size_t)1 << ((sizeof(size_t) * (1 << 3)) - 1))) +#endif #if KMP_ARCH_X86 #define KMP_DEFAULT_STKSIZE ((size_t)(2 * 1024 * 1024)) @@ -2494,7 +2498,8 @@ typedef struct kmp_dephash_entry kmp_dephash_entry_t; #define KMP_DEP_MTX 0x4 #define KMP_DEP_SET 0x8 #define KMP_DEP_ALL 0x80 -// Compiler sends us this info: +// Compiler sends us this info. Note: some test cases contain an explicit copy +// of this struct and should be in sync with any changes here. typedef struct kmp_depend_info { kmp_intptr_t base_addr; size_t len; diff --git a/openmp/runtime/src/kmp_csupport.cpp b/openmp/runtime/src/kmp_csupport.cpp index 9eeaeb88fb9e..878e78b5c7ad 100644 --- a/openmp/runtime/src/kmp_csupport.cpp +++ b/openmp/runtime/src/kmp_csupport.cpp @@ -1533,8 +1533,9 @@ void __kmpc_critical_with_hint(ident_t *loc, kmp_int32 global_tid, kmp_dyna_lockseq_t lockseq = __kmp_map_hint_to_lock(hint); if (*lk == 0) { if (KMP_IS_D_LOCK(lockseq)) { - KMP_COMPARE_AND_STORE_ACQ32((volatile kmp_int32 *)crit, 0, - KMP_GET_D_TAG(lockseq)); + KMP_COMPARE_AND_STORE_ACQ32( + (volatile kmp_int32 *)&((kmp_base_tas_lock_t *)crit)->poll, 0, + KMP_GET_D_TAG(lockseq)); } else { __kmp_init_indirect_csptr(crit, loc, global_tid, KMP_GET_I_TAG(lockseq)); } diff --git a/openmp/runtime/src/kmp_gsupport.cpp b/openmp/runtime/src/kmp_gsupport.cpp index 88189659a234..4dc8a90f83b4 100644 --- a/openmp/runtime/src/kmp_gsupport.cpp +++ b/openmp/runtime/src/kmp_gsupport.cpp @@ -144,7 +144,7 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_BARRIER)(void) { // Mutual exclusion -// The symbol that icc/ifort generates for unnamed for unnamed critical sections +// The symbol that icc/ifort generates for unnamed critical sections // - .gomp_critical_user_ - is defined using .comm in any objects reference it. // We can't reference it directly here in C code, as the symbol contains a ".". // diff --git a/openmp/runtime/src/kmp_lock.cpp b/openmp/runtime/src/kmp_lock.cpp index 85c54f4cdc7e..0ad14f862bcb 100644 --- a/openmp/runtime/src/kmp_lock.cpp +++ b/openmp/runtime/src/kmp_lock.cpp @@ -2689,7 +2689,7 @@ void __kmp_spin_backoff(kmp_backoff_t *boff) { // lock word. static void __kmp_init_direct_lock(kmp_dyna_lock_t *lck, kmp_dyna_lockseq_t seq) { - TCW_4(*lck, KMP_GET_D_TAG(seq)); + TCW_4(((kmp_base_tas_lock_t *)lck)->poll, KMP_GET_D_TAG(seq)); KA_TRACE( 20, ("__kmp_init_direct_lock: initialized direct lock with type#%d\n", seq)); @@ -3180,8 +3180,8 @@ kmp_indirect_lock_t *__kmp_allocate_indirect_lock(void **user_lock, lck->type = tag; if (OMP_LOCK_T_SIZE < sizeof(void *)) { - *((kmp_lock_index_t *)user_lock) = idx - << 1; // indirect lock word must be even + *(kmp_lock_index_t *)&(((kmp_base_tas_lock_t *)user_lock)->poll) = + idx << 1; // indirect lock word must be even } else { *((kmp_indirect_lock_t **)user_lock) = lck; } diff --git a/openmp/runtime/src/kmp_lock.h b/openmp/runtime/src/kmp_lock.h index f21179b4eb68..e2a0cda01a97 100644 --- a/openmp/runtime/src/kmp_lock.h +++ b/openmp/runtime/src/kmp_lock.h @@ -50,7 +50,7 @@ typedef struct ident ident_t; // recent versions), but we are bounded by the pointer-sized chunks that // the Intel compiler allocates. -#if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT) +#if (KMP_OS_LINUX || KMP_OS_AIX) && defined(KMP_GOMP_COMPAT) #define OMP_LOCK_T_SIZE sizeof(int) #define OMP_NEST_LOCK_T_SIZE sizeof(void *) #else @@ -120,8 +120,15 @@ extern void __kmp_validate_locks(void); struct kmp_base_tas_lock { // KMP_LOCK_FREE(tas) => unlocked; locked: (gtid+1) of owning thread +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __LP64__ + // Flip the ordering of the high and low 32-bit member to be consistent + // with the memory layout of the address in 64-bit big-endian. + kmp_int32 depth_locked; // depth locked, for nested locks only + std::atomic<kmp_int32> poll; +#else std::atomic<kmp_int32> poll; kmp_int32 depth_locked; // depth locked, for nested locks only +#endif }; typedef struct kmp_base_tas_lock kmp_base_tas_lock_t; @@ -1138,11 +1145,13 @@ extern int (**__kmp_indirect_test)(kmp_user_lock_p, kmp_int32); // Extracts direct lock tag from a user lock pointer #define KMP_EXTRACT_D_TAG(l) \ - (*((kmp_dyna_lock_t *)(l)) & ((1 << KMP_LOCK_SHIFT) - 1) & \ - -(*((kmp_dyna_lock_t *)(l)) & 1)) + ((kmp_dyna_lock_t)((kmp_base_tas_lock_t *)(l))->poll & \ + ((1 << KMP_LOCK_SHIFT) - 1) & \ + -((kmp_dyna_lock_t)((kmp_tas_lock_t *)(l))->lk.poll & 1)) // Extracts indirect lock index from a user lock pointer -#define KMP_EXTRACT_I_INDEX(l) (*(kmp_lock_index_t *)(l) >> 1) +#define KMP_EXTRACT_I_INDEX(l) \ + ((kmp_lock_index_t)((kmp_base_tas_lock_t *)(l))->poll >> 1) // Returns function pointer to the direct lock function with l (kmp_dyna_lock_t // *) and op (operation type). diff --git a/openmp/runtime/src/kmp_settings.cpp b/openmp/runtime/src/kmp_settings.cpp index d2157b10b781..ec86ee07472c 100644 --- a/openmp/runtime/src/kmp_settings.cpp +++ b/openmp/runtime/src/kmp_settings.cpp @@ -255,8 +255,13 @@ static void __kmp_stg_parse_bool(char const *name, char const *value, // placed here in order to use __kmp_round4k static function void __kmp_check_stksize(size_t *val) { // if system stack size is too big then limit the size for worker threads +#if KMP_OS_AIX + if (*val > KMP_DEFAULT_STKSIZE * 2) // Use 2 times, 16 is too large for AIX. + *val = KMP_DEFAULT_STKSIZE * 2; +#else if (*val > KMP_DEFAULT_STKSIZE * 16) // just a heuristics... *val = KMP_DEFAULT_STKSIZE * 16; +#endif if (*val < __kmp_sys_min_stksize) *val = __kmp_sys_min_stksize; if (*val > KMP_MAX_STKSIZE) |