aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-02-20 18:46:41 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-02-20 18:46:41 +0000
commite15a4f0a320e3c1248539511adee55a201e9ed2e (patch)
treee74b63e38a51ec5611f79daf5df6b5a2d7102bdb
parent4fdf604ba667503ae582304cebdd3df426778a6b (diff)
downloadsrc-e15a4f0a320e3c1248539511adee55a201e9ed2e.tar.gz
src-e15a4f0a320e3c1248539511adee55a201e9ed2e.zip
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
-rw-r--r--clang/include/clang/Basic/arm_sme.td28
-rw-r--r--clang/include/clang/Driver/Options.td12
-rw-r--r--clang/lib/AST/ASTContext.cpp6
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp9
-rw-r--r--clang/lib/Driver/ToolChains/Arch/Sparc.cpp81
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2
-rw-r--r--clang/tools/clang-format/ClangFormat.cpp49
-rw-r--r--compiler-rt/lib/dfsan/dfsan_custom.cpp203
-rw-r--r--compiler-rt/lib/dfsan/done_abilist.txt6
-rw-r--r--compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt5
-rw-r--r--compiler-rt/lib/profile/InstrProfilingPlatformAIX.c4
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc15
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h1
-rw-r--r--libcxx/include/print14
-rw-r--r--libcxx/modules/CMakeLists.txt.in88
-rw-r--r--libcxx/modules/std/ostream.inc4
-rw-r--r--libcxx/src/print.cpp25
-rw-r--r--lld/COFF/Driver.cpp10
-rw-r--r--lld/ELF/Arch/LoongArch.cpp156
-rw-r--r--lld/ELF/Arch/RISCV.cpp29
-rw-r--r--lld/ELF/Arch/SystemZ.cpp607
-rw-r--r--lld/ELF/Driver.cpp3
-rw-r--r--lld/ELF/InputFiles.cpp2
-rw-r--r--lld/ELF/InputSection.cpp14
-rw-r--r--lld/ELF/InputSection.h24
-rw-r--r--lld/ELF/Relocations.cpp27
-rw-r--r--lld/ELF/Relocations.h3
-rw-r--r--lld/ELF/ScriptParser.cpp1
-rw-r--r--lld/ELF/SyntheticSections.cpp3
-rw-r--r--lld/ELF/Target.cpp2
-rw-r--r--lld/ELF/Target.h4
-rw-r--r--lld/ELF/Writer.cpp4
-rw-r--r--lld/docs/ReleaseNotes.rst53
-rw-r--r--llvm/include/llvm/BinaryFormat/ELF.h1
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp7
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp2
-rw-r--r--llvm/lib/CodeGen/RegisterCoalescer.cpp27
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp2
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp11
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp4
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp5
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp7
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp98
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.cpp3
-rw-r--r--llvm/lib/Target/Sparc/Sparc.td14
-rw-r--r--llvm/lib/Target/Sparc/SparcISelLowering.cpp43
-rw-r--r--llvm/lib/Target/Sparc/SparcRegisterInfo.cpp14
-rw-r--r--llvm/lib/Target/Sparc/SparcRegisterInfo.h1
-rw-r--r--llvm/lib/Target/Sparc/SparcRegisterInfo.td4
-rw-r--r--llvm/lib/Target/Sparc/SparcSubtarget.cpp1
-rw-r--r--llvm/lib/Target/Sparc/SparcSubtarget.h10
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp10
-rw-r--r--llvm/lib/Transforms/IPO/LowerTypeTests.cpp28
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp14
-rw-r--r--openmp/runtime/src/kmp.h7
-rw-r--r--openmp/runtime/src/kmp_csupport.cpp5
-rw-r--r--openmp/runtime/src/kmp_gsupport.cpp2
-rw-r--r--openmp/runtime/src/kmp_lock.cpp6
-rw-r--r--openmp/runtime/src/kmp_lock.h17
-rw-r--r--openmp/runtime/src/kmp_settings.cpp5
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 &target;
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)