mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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:
parent
b9d9368bac
commit
4b8be30b44
62 changed files with 1485 additions and 356 deletions
|
|
@ -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], []>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
88
contrib/llvm-project/libcxx/modules/CMakeLists.txt.in
Normal file
88
contrib/llvm-project/libcxx/modules/CMakeLists.txt.in
Normal 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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ⌖
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
607
contrib/llvm-project/lld/ELF/Arch/SystemZ.cpp
Normal file
607
contrib/llvm-project/lld/ELF/Arch/SystemZ.cpp
Normal 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;
|
||||
}
|
||||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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())) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ".".
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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) ")"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue