Merge llvm-project release/18.x llvmorg-18.1.0-rc2-53-gc7b0a6ecd442

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvm-project release/18.x llvmorg-18.1.0-rc2-53-gc7b0a6ecd442.

PR:		276104
MFC after:	1 month

(cherry picked from commit 74626c16ff489c0d64cf2843dfd522e7c544f3ce)
This commit is contained in:
Dimitry Andric 2024-02-20 19:57:23 +01:00
parent b9d9368bac
commit 4b8be30b44
62 changed files with 1485 additions and 356 deletions

View file

@ -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], []>;
}
}

View file

@ -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

View file

@ -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 {

View file

@ -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");
}

View file

@ -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();

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}
WRAPPER_ALIAS(__isoc23_strtod, strtod)
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;
}
#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; \
}
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_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();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -8,22 +8,26 @@
#include <__config>
#include <cstdlib>
#include <print>
#include <__system_error/system_error.h>
#include "filesystem/error.h"
#if defined(_LIBCPP_WIN32API)
# include <cstdlib>
# include <print>
# 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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -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());

View file

@ -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,

View file

@ -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});
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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();

View file

@ -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)

View file

@ -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
------------------

View file

@ -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.

View file

@ -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())

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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))

View file

@ -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);
}

View file

@ -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();

View file

@ -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());

View file

@ -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()) {
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;
}
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);
// 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);
// 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);
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 {
SDValue RHSIndices = DAG.getBuildVector(IndexVT, DL, GatherIndicesRHS);
RHSIndices =
convertToScalableVector(IndexContainerVT, RHSIndices, DAG, Subtarget);
Gather = DAG.getNode(GatherVVOpc, DL, ContainerVT, V2, RHSIndices, Gather,
SelectMask, VL);
V1 = convertToScalableVector(ContainerVT, V1, 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 (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);
}
}
// 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);
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);
}
}
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;

View file

@ -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();

View file

@ -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
//===----------------------------------------------------------------------===//

View file

@ -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));

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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) {}

View file

@ -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.

View file

@ -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),

View file

@ -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())) {

View file

@ -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);

View file

@ -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;

View file

@ -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));
}

View file

@ -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 ".".
//

View file

@ -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;
}

View file

@ -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).

View file

@ -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)

View file

@ -1,8 +1,8 @@
#define LLVM_REVISION "llvmorg-18.1.0-rc2-0-gc6c86965d967"
#define LLVM_REVISION "llvmorg-18.1.0-rc2-53-gc7b0a6ecd442"
#define LLVM_REPOSITORY "https://github.com/llvm/llvm-project.git"
#define CLANG_REVISION "llvmorg-18.1.0-rc2-0-gc6c86965d967"
#define CLANG_REVISION "llvmorg-18.1.0-rc2-53-gc7b0a6ecd442"
#define CLANG_REPOSITORY "https://github.com/llvm/llvm-project.git"
#define LLDB_REVISION "llvmorg-18.1.0-rc2-0-gc6c86965d967"
#define LLDB_REVISION "llvmorg-18.1.0-rc2-53-gc7b0a6ecd442"
#define LLDB_REPOSITORY "https://github.com/llvm/llvm-project.git"

View file

@ -1,4 +1,4 @@
// Local identifier in __FreeBSD_version style
#define LLD_FREEBSD_VERSION 1400006
#define LLD_VERSION_STRING "18.1.0 (FreeBSD llvmorg-18.1.0-rc2-0-gc6c86965d967-" __XSTRING(LLD_FREEBSD_VERSION) ")"
#define LLD_VERSION_STRING "18.1.0 (FreeBSD llvmorg-18.1.0-rc2-53-gc7b0a6ecd442-" __XSTRING(LLD_FREEBSD_VERSION) ")"

View file

@ -1,2 +1,2 @@
#define LLVM_REVISION "llvmorg-18.1.0-rc2-0-gc6c86965d967"
#define LLVM_REVISION "llvmorg-18.1.0-rc2-53-gc7b0a6ecd442"
#define LLVM_REPOSITORY "https://github.com/llvm/llvm-project.git"

View file

@ -50,6 +50,7 @@ SRCS+= ELF/Arch/PPC.cpp
SRCS+= ELF/Arch/PPC64.cpp
SRCS+= ELF/Arch/RISCV.cpp
SRCS+= ELF/Arch/SPARCV9.cpp
SRCS+= ELF/Arch/SystemZ.cpp
SRCS+= ELF/Arch/X86.cpp
SRCS+= ELF/Arch/X86_64.cpp
SRCS+= ELF/CallGraphSort.cpp