Merge llvm-project release/18.x llvmorg-18.1.3-0-gc13b7485b879

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvm-project release/18.x llvmorg-18.1.3-0-gc13b7485b879.

PR:		276104
MFC after:	1 month
This commit is contained in:
Dimitry Andric 2024-04-06 00:02:56 +02:00
commit 439352ac82
107 changed files with 1268 additions and 433 deletions

View file

@ -673,6 +673,16 @@ class alignas(8) Decl {
/// fragment. See [module.global.frag]p3,4 for details.
bool isDiscardedInGlobalModuleFragment() const { return false; }
/// Check if we should skip checking ODRHash for declaration \param D.
///
/// The existing ODRHash mechanism seems to be not stable enough and
/// the false positive ODR violation reports are annoying and we rarely see
/// true ODR violation reports. Also we learned that MSVC disabled ODR checks
/// for declarations in GMF. So we try to disable ODR checks in the GMF to
/// get better user experiences before we make the ODR violation checks stable
/// enough.
bool shouldSkipCheckingODR() const;
/// Return true if this declaration has an attribute which acts as
/// definition of the entity, such as 'alias' or 'ifunc'.
bool hasDefiningAttr() const;

View file

@ -925,8 +925,8 @@ class LambdaScopeInfo final :
/// that were defined in parent contexts. Used to avoid warnings when the
/// shadowed variables are uncaptured by this lambda.
struct ShadowedOuterDecl {
const VarDecl *VD;
const VarDecl *ShadowedDecl;
const NamedDecl *VD;
const NamedDecl *ShadowedDecl;
};
llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls;

View file

@ -2451,13 +2451,6 @@ class BitsUnpacker {
uint32_t Value;
uint32_t CurrentBitsIndex = ~0;
};
inline bool shouldSkipCheckingODR(const Decl *D) {
return D->getOwningModule() &&
D->getASTContext().getLangOpts().SkipODRCheckInGMF &&
D->getOwningModule()->isExplicitGlobalModule();
}
} // namespace clang
#endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H

View file

@ -4476,7 +4476,7 @@ unsigned FunctionDecl::getODRHash() {
}
class ODRHash Hash;
Hash.AddFunctionDecl(this);
Hash.AddFunctionDecl(this, /*SkipBody=*/shouldSkipCheckingODR());
setHasODRHash(true);
ODRHash = Hash.CalculateHash();
return ODRHash;

View file

@ -1102,6 +1102,11 @@ bool Decl::isInAnotherModuleUnit() const {
return M != getASTContext().getCurrentNamedModule();
}
bool Decl::shouldSkipCheckingODR() const {
return getASTContext().getLangOpts().SkipODRCheckInGMF && getOwningModule() &&
getOwningModule()->isExplicitGlobalModule();
}
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }

View file

@ -301,10 +301,9 @@ bool Module::directlyUses(const Module *Requested) {
if (Requested->isSubModuleOf(Use))
return true;
// Anyone is allowed to use our builtin stdarg.h and stddef.h and their
// accompanying modules.
if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" ||
Requested->getTopLevelModuleName() == "_Builtin_stddef")
// Anyone is allowed to use our builtin stddef.h and its accompanying modules.
if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) ||
Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"}))
return true;
if (NoUndeclaredIncludes)

View file

@ -186,6 +186,14 @@ class EmitAssemblyHelper {
TargetTriple.getVendor() != llvm::Triple::Apple;
}
/// Check whether we should emit a flag for UnifiedLTO.
/// The UnifiedLTO module flag should be set when UnifiedLTO is enabled for
/// ThinLTO or Full LTO with module summaries.
bool shouldEmitUnifiedLTOModueFlag() const {
return CodeGenOpts.UnifiedLTO &&
(CodeGenOpts.PrepareForThinLTO || shouldEmitRegularLTOSummary());
}
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
const HeaderSearchOptions &HeaderSearchOpts,
@ -1029,7 +1037,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (!actionRequiresCodeGen(Action) && CodeGenOpts.VerifyModule)
MPM.addPass(VerifierPass());
if (Action == Backend_EmitBC || Action == Backend_EmitLL) {
if (Action == Backend_EmitBC || Action == Backend_EmitLL ||
CodeGenOpts.FatLTO) {
if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) {
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
@ -1040,11 +1049,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (!ThinLinkOS)
return;
}
if (CodeGenOpts.UnifiedLTO)
TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1));
MPM.addPass(ThinLTOBitcodeWriterPass(
*OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr));
} else {
} else if (Action == Backend_EmitLL) {
MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists,
/*EmitLTOSummary=*/true));
}
@ -1058,24 +1065,17 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
uint32_t(1));
if (CodeGenOpts.UnifiedLTO)
TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1));
}
if (Action == Backend_EmitBC)
if (Action == Backend_EmitBC) {
MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
EmitLTOSummary));
else
} else if (Action == Backend_EmitLL) {
MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists,
EmitLTOSummary));
}
}
}
if (CodeGenOpts.FatLTO) {
// Set the EnableSplitLTOUnit and UnifiedLTO module flags, since FatLTO
// uses a different action than Backend_EmitBC or Backend_EmitLL.
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
uint32_t(CodeGenOpts.EnableSplitLTOUnit));
if (CodeGenOpts.UnifiedLTO && !TheModule->getModuleFlag("UnifiedLTO"))
if (shouldEmitUnifiedLTOModueFlag())
TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1));
}

View file

@ -1241,27 +1241,38 @@ static void emitStoresForConstant(CodeGenModule &CGM, const VarDecl &D,
return;
}
// If the initializer is small, use a handful of stores.
// If the initializer is small or trivialAutoVarInit is set, use a handful of
// stores.
bool IsTrivialAutoVarInitPattern =
CGM.getContext().getLangOpts().getTrivialAutoVarInit() ==
LangOptions::TrivialAutoVarInitKind::Pattern;
if (shouldSplitConstantStore(CGM, ConstantSize)) {
if (auto *STy = dyn_cast<llvm::StructType>(Ty)) {
const llvm::StructLayout *Layout =
CGM.getDataLayout().getStructLayout(STy);
for (unsigned i = 0; i != constant->getNumOperands(); i++) {
CharUnits CurOff = CharUnits::fromQuantity(Layout->getElementOffset(i));
Address EltPtr = Builder.CreateConstInBoundsByteGEP(
Loc.withElementType(CGM.Int8Ty), CurOff);
emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
constant->getAggregateElement(i), IsAutoInit);
if (STy == Loc.getElementType() ||
(STy != Loc.getElementType() && IsTrivialAutoVarInitPattern)) {
const llvm::StructLayout *Layout =
CGM.getDataLayout().getStructLayout(STy);
for (unsigned i = 0; i != constant->getNumOperands(); i++) {
CharUnits CurOff =
CharUnits::fromQuantity(Layout->getElementOffset(i));
Address EltPtr = Builder.CreateConstInBoundsByteGEP(
Loc.withElementType(CGM.Int8Ty), CurOff);
emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
constant->getAggregateElement(i), IsAutoInit);
}
return;
}
return;
} else if (auto *ATy = dyn_cast<llvm::ArrayType>(Ty)) {
for (unsigned i = 0; i != ATy->getNumElements(); i++) {
Address EltPtr = Builder.CreateConstGEP(
Loc.withElementType(ATy->getElementType()), i);
emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
constant->getAggregateElement(i), IsAutoInit);
if (ATy == Loc.getElementType() ||
(ATy != Loc.getElementType() && IsTrivialAutoVarInitPattern)) {
for (unsigned i = 0; i != ATy->getNumElements(); i++) {
Address EltPtr = Builder.CreateConstGEP(
Loc.withElementType(ATy->getElementType()), i);
emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
constant->getAggregateElement(i), IsAutoInit);
}
return;
}
return;
}
}

View file

@ -44,8 +44,15 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const {
llvm::sys::fs::can_execute(UseLinker))
return std::string(UseLinker);
// Accept 'lld', and 'ld' as aliases for the default linker
if (UseLinker != "lld" && UseLinker != "ld")
// Interpret 'lld' as explicitly requesting `wasm-ld`, so look for that
// linker. Note that for `wasm32-wasip2` this overrides the default linker
// of `wasm-component-ld`.
if (UseLinker == "lld") {
return ToolChain.GetProgramPath("wasm-ld");
}
// Allow 'ld' as an alias for the default linker
if (UseLinker != "ld")
ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
<< A->getAsString(Args);
}
@ -73,6 +80,16 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("--strip-all");
// On `wasip2` the default linker is `wasm-component-ld` which wraps the
// execution of `wasm-ld`. Find `wasm-ld` and pass it as an argument of where
// to find it to avoid it needing to hunt and rediscover or search `PATH` for
// where it is.
if (llvm::sys::path::stem(Linker).ends_with_insensitive(
"wasm-component-ld")) {
CmdArgs.push_back("--wasm-ld-path");
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetProgramPath("wasm-ld")));
}
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
@ -221,6 +238,12 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
}
}
const char *WebAssembly::getDefaultLinker() const {
if (getOS() == "wasip2")
return "wasm-component-ld";
return "wasm-ld";
}
bool WebAssembly::IsMathErrnoDefault() const { return false; }
bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }

View file

@ -67,7 +67,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain {
llvm::opt::ArgStringList &CmdArgs) const override;
SanitizerMask getSupportedSanitizers() const override;
const char *getDefaultLinker() const override { return "wasm-ld"; }
const char *getDefaultLinker() const override;
CXXStdlibType GetDefaultCXXStdlibType() const override {
return ToolChain::CST_Libcxx;

View file

@ -7,7 +7,7 @@
*===-----------------------------------------------------------------------===
*/
#if !defined(NULL) || !__has_feature(modules)
#if !defined(NULL) || !__building_module(_Builtin_stddef)
/* linux/stddef.h will define NULL to 0. glibc (and other) headers then define
* __need_NULL and rely on stddef.h to redefine NULL to the correct value again.

View file

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _NULLPTR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_NULLPTR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _NULLPTR_T
#ifdef __cplusplus

View file

@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/
#ifndef offsetof
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(offsetof) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define offsetof(t, d) __builtin_offsetof(t, d)
#endif

View file

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _PTRDIFF_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_PTRDIFF_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _PTRDIFF_T
typedef __PTRDIFF_TYPE__ ptrdiff_t;

View file

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _RSIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_RSIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _RSIZE_T
typedef __SIZE_TYPE__ rsize_t;

View file

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _SIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_SIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _SIZE_T
typedef __SIZE_TYPE__ size_t;

View file

@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/
#ifndef unreachable
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(unreachable) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define unreachable() __builtin_unreachable()
#endif

View file

@ -9,7 +9,12 @@
#if !defined(__cplusplus) || (defined(_MSC_VER) && !_NATIVE_WCHAR_T_DEFINED)
#ifndef _WCHAR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_WCHAR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _WCHAR_T
#ifdef _MSC_EXTENSIONS

View file

@ -156,7 +156,7 @@ extern __inline unsigned char
return (unsigned char)__builtin_loongarch_iocsrrd_b((unsigned int)_1);
}
extern __inline unsigned char
extern __inline unsigned short
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
__iocsrrd_h(unsigned int _1) {
return (unsigned short)__builtin_loongarch_iocsrrd_h((unsigned int)_1);

View file

@ -155,9 +155,9 @@ module _Builtin_intrinsics [system] [extern_c] {
// Start -fbuiltin-headers-in-system-modules affected modules
// The following modules all ignore their top level headers
// when -fbuiltin-headers-in-system-modules is passed, and
// most of those headers join system modules when present.
// The following modules all ignore their headers when
// -fbuiltin-headers-in-system-modules is passed, and many of
// those headers join system modules when present.
// e.g. if -fbuiltin-headers-in-system-modules is passed, then
// float.h will not be in the _Builtin_float module (that module
@ -190,11 +190,6 @@ module _Builtin_stdalign [system] {
export *
}
// When -fbuiltin-headers-in-system-modules is passed, only
// the top level headers are removed, the implementation headers
// will always be in their submodules. That means when stdarg.h
// is included, it will still import this module and make the
// appropriate submodules visible.
module _Builtin_stdarg [system] {
textual header "stdarg.h"
@ -237,6 +232,8 @@ module _Builtin_stdbool [system] {
module _Builtin_stddef [system] {
textual header "stddef.h"
// __stddef_max_align_t.h is always in this module, even if
// -fbuiltin-headers-in-system-modules is passed.
explicit module max_align_t {
header "__stddef_max_align_t.h"
export *
@ -283,9 +280,10 @@ module _Builtin_stddef [system] {
}
}
/* wint_t is provided by <wchar.h> and not <stddef.h>. It's here
* for compatibility, but must be explicitly requested. Therefore
* __stddef_wint_t.h is not part of _Builtin_stddef. */
// wint_t is provided by <wchar.h> and not <stddef.h>. It's here
// for compatibility, but must be explicitly requested. Therefore
// __stddef_wint_t.h is not part of _Builtin_stddef. It is always in
// this module even if -fbuiltin-headers-in-system-modules is passed.
module _Builtin_stddef_wint_t [system] {
header "__stddef_wint_t.h"
export *

View file

@ -2498,9 +2498,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
}
bool NeedsFramework = false;
// Don't add the top level headers to the builtin modules if the builtin headers
// belong to the system modules.
if (!Map.LangOpts.BuiltinHeadersInSystemModules || ActiveModule->isSubModule() || !isBuiltInModuleName(ActiveModule->Name))
// Don't add headers to the builtin modules if the builtin headers belong to
// the system modules, with the exception of __stddef_max_align_t.h which
// always had its own module.
if (!Map.LangOpts.BuiltinHeadersInSystemModules ||
!isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) ||
ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}))
Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);
if (NeedsFramework)

View file

@ -8396,28 +8396,40 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
unsigned WarningDiag = diag::warn_decl_shadow;
SourceLocation CaptureLoc;
if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
isa<CXXMethodDecl>(NewDC)) {
if (isa<VarDecl>(D) && NewDC && isa<CXXMethodDecl>(NewDC)) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
if (RD->getLambdaCaptureDefault() == LCD_None) {
// Try to avoid warnings for lambdas with an explicit capture list.
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
// Warn only when the lambda captures the shadowed decl explicitly.
CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
if (CaptureLoc.isInvalid())
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
} else {
// Remember that this was shadowed so we can avoid the warning if the
// shadowed decl isn't captured and the warning settings allow it.
if (RD->getLambdaCaptureDefault() == LCD_None) {
// Try to avoid warnings for lambdas with an explicit capture
// list. Warn only when the lambda captures the shadowed decl
// explicitly.
CaptureLoc = getCaptureLocation(LSI, VD);
if (CaptureLoc.isInvalid())
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
} else {
// Remember that this was shadowed so we can avoid the warning if
// the shadowed decl isn't captured and the warning settings allow
// it.
cast<LambdaScopeInfo>(getCurFunction())
->ShadowingDecls.push_back({D, VD});
return;
}
}
if (isa<FieldDecl>(ShadowedDecl)) {
// If lambda can capture this, then emit default shadowing warning,
// Otherwise it is not really a shadowing case since field is not
// available in lambda's body.
// At this point we don't know that lambda can capture this, so
// remember that this was shadowed and delay until we know.
cast<LambdaScopeInfo>(getCurFunction())
->ShadowingDecls.push_back(
{cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
->ShadowingDecls.push_back({D, ShadowedDecl});
return;
}
}
if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl);
VD && VD->hasLocalStorage()) {
// A variable can't shadow a local variable in an enclosing scope, if
// they are separated by a non-capturing declaration context.
for (DeclContext *ParentDC = NewDC;
@ -8468,19 +8480,28 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
/// when these variables are captured by the lambda.
void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
for (const auto &Shadow : LSI->ShadowingDecls) {
const VarDecl *ShadowedDecl = Shadow.ShadowedDecl;
const NamedDecl *ShadowedDecl = Shadow.ShadowedDecl;
// Try to avoid the warning when the shadowed decl isn't captured.
SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl);
const DeclContext *OldDC = ShadowedDecl->getDeclContext();
Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid()
? diag::warn_decl_shadow_uncaptured_local
: diag::warn_decl_shadow)
<< Shadow.VD->getDeclName()
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
if (!CaptureLoc.isInvalid())
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
if (const auto *VD = dyn_cast<VarDecl>(ShadowedDecl)) {
SourceLocation CaptureLoc = getCaptureLocation(LSI, VD);
Diag(Shadow.VD->getLocation(),
CaptureLoc.isInvalid() ? diag::warn_decl_shadow_uncaptured_local
: diag::warn_decl_shadow)
<< Shadow.VD->getDeclName()
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
if (CaptureLoc.isValid())
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
} else if (isa<FieldDecl>(ShadowedDecl)) {
Diag(Shadow.VD->getLocation(),
LSI->isCXXThisCaptured() ? diag::warn_decl_shadow
: diag::warn_decl_shadow_uncaptured_local)
<< Shadow.VD->getDeclName()
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
}
}

View file

@ -14470,6 +14470,23 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
CurFPFeatureOverrides());
}
// If this is the .* operator, which is not overloadable, just
// create a built-in binary operator.
if (Opc == BO_PtrMemD) {
auto CheckPlaceholder = [&](Expr *&Arg) {
ExprResult Res = CheckPlaceholderExpr(Arg);
if (Res.isUsable())
Arg = Res.get();
return !Res.isUsable();
};
// CreateBuiltinBinOp() doesn't like it if we tell it to create a '.*'
// expression that contains placeholders (in either the LHS or RHS).
if (CheckPlaceholder(Args[0]) || CheckPlaceholder(Args[1]))
return ExprError();
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
// Always do placeholder-like conversions on the RHS.
if (checkPlaceholderForOverload(*this, Args[1]))
return ExprError();
@ -14489,11 +14506,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_Assign && !Args[0]->getType()->isOverloadableType())
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// If this is the .* operator, which is not overloadable, just
// create a built-in binary operator.
if (Opc == BO_PtrMemD)
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build the overload set.
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(

View file

@ -1830,7 +1830,27 @@ static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
// Make sure we get the template parameter list from the most
// recent declaration, since that is the only one that is guaranteed to
// have all the default template argument information.
return cast<TemplateDecl>(TD->getMostRecentDecl())->getTemplateParameters();
Decl *D = TD->getMostRecentDecl();
// C++11 [temp.param]p12:
// A default template argument shall not be specified in a friend class
// template declaration.
//
// Skip past friend *declarations* because they are not supposed to contain
// default template arguments. Moreover, these declarations may introduce
// template parameters living in different template depths than the
// corresponding template parameters in TD, causing unmatched constraint
// substitution.
//
// FIXME: Diagnose such cases within a class template:
// template <class T>
// struct S {
// template <class = void> friend struct C;
// };
// template struct S<int>;
while (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None &&
D->getPreviousDecl())
D = D->getPreviousDecl();
return cast<TemplateDecl>(D)->getTemplateParameters();
}
DeclResult Sema::CheckClassTemplate(

View file

@ -9745,7 +9745,7 @@ void ASTReader::finishPendingActions() {
!NonConstDefn->isLateTemplateParsed() &&
// We only perform ODR checks for decls not in the explicit
// global module fragment.
!shouldSkipCheckingODR(FD) &&
!FD->shouldSkipCheckingODR() &&
FD->getODRHash() != NonConstDefn->getODRHash()) {
if (!isa<CXXMethodDecl>(FD)) {
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);

View file

@ -832,7 +832,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
Reader.mergeDefinitionVisibility(OldDef, ED);
// We don't want to check the ODR hash value for declarations from global
// module fragment.
if (!shouldSkipCheckingODR(ED) &&
if (!ED->shouldSkipCheckingODR() &&
OldDef->getODRHash() != ED->getODRHash())
Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
} else {
@ -874,7 +874,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
VisitRecordDeclImpl(RD);
// We should only reach here if we're in C/Objective-C. There is no
// global module fragment.
assert(!shouldSkipCheckingODR(RD));
assert(!RD->shouldSkipCheckingODR());
RD->setODRHash(Record.readInt());
// Maintain the invariant of a redeclaration chain containing only
@ -2152,7 +2152,7 @@ void ASTDeclReader::MergeDefinitionData(
}
// We don't want to check ODR for decls in the global module fragment.
if (shouldSkipCheckingODR(MergeDD.Definition))
if (MergeDD.Definition->shouldSkipCheckingODR())
return;
if (D->getODRHash() != MergeDD.ODRHash) {
@ -3526,7 +3526,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// same template specialization into the same CXXRecordDecl.
auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
if (MergedDCIt != Reader.MergedDeclContexts.end() &&
!shouldSkipCheckingODR(D) && MergedDCIt->second == D->getDeclContext())
!D->shouldSkipCheckingODR() && MergedDCIt->second == D->getDeclContext())
Reader.PendingOdrMergeChecks.push_back(D);
return FindExistingResult(Reader, D, /*Existing=*/nullptr,

View file

@ -6010,7 +6010,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
BitsPacker DefinitionBits;
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
DefinitionBits.addBit(ShouldSkipCheckingODR);
#define FIELD(Name, Width, Merge) \

View file

@ -488,7 +488,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
BitsPacker EnumDeclBits;
EnumDeclBits.addBits(D->getNumPositiveBits(), /*BitWidth=*/8);
EnumDeclBits.addBits(D->getNumNegativeBits(), /*BitWidth=*/8);
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
EnumDeclBits.addBit(ShouldSkipCheckingODR);
EnumDeclBits.addBit(D->isScoped());
EnumDeclBits.addBit(D->isScopedUsingClassTag());
@ -514,7 +514,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isTopLevelDeclInObjCContainer() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
!needsAnonymousDeclarationNumber(D) && !shouldSkipCheckingODR(D) &&
!needsAnonymousDeclarationNumber(D) && !D->shouldSkipCheckingODR() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();
@ -680,7 +680,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: stable encoding
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
FunctionDeclBits.addBit(ShouldSkipCheckingODR);
FunctionDeclBits.addBit(D->isInlineSpecified());
FunctionDeclBits.addBit(D->isInlined());
@ -1514,7 +1514,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!shouldSkipCheckingODR(D) && !D->hasExtInfo() &&
!D->shouldSkipCheckingODR() && !D->hasExtInfo() &&
!D->isExplicitlyDefaulted()) {
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||

View file

@ -1409,7 +1409,7 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
if (MD->isInstance())
if (MD->isImplicitObjectMemberFunction())
return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
} else if (CE->getCallee()->getType()->isBlockPointerType()) {

View file

@ -13,7 +13,7 @@
#define QUAD_PRECISION
#include "fp_lib.h"
#if defined(CRT_HAS_TF_MODE)
#if defined(CRT_HAS_F128)
// Returns: the quotient of (a + ib) / (c + id)

View file

@ -22,6 +22,7 @@
#include "int_lib.h"
#include "int_math.h"
#include "int_types.h"
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
@ -93,13 +94,14 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
#elif defined QUAD_PRECISION
#if defined(CRT_HAS_TF_MODE)
#if defined(CRT_HAS_F128) && defined(CRT_HAS_128BIT)
typedef uint64_t half_rep_t;
typedef __uint128_t rep_t;
typedef __int128_t srep_t;
typedef tf_float fp_t;
#define HALF_REP_C UINT64_C
#define REP_C (__uint128_t)
#if defined(CRT_HAS_IEEE_TF)
// Note: Since there is no explicit way to tell compiler the constant is a
// 128-bit integer, we let the constant be casted to 128-bit integer
#define significandBits 112
@ -188,7 +190,10 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
#undef Word_HiMask
#undef Word_LoMask
#undef Word_FullMask
#endif // defined(CRT_HAS_TF_MODE)
#endif // defined(CRT_HAS_IEEE_TF)
#else
typedef long double fp_t;
#endif // defined(CRT_HAS_F128) && defined(CRT_HAS_128BIT)
#else
#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
#endif
@ -196,19 +201,6 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || \
(defined(QUAD_PRECISION) && defined(CRT_HAS_TF_MODE))
#define typeWidth (sizeof(rep_t) * CHAR_BIT)
#define exponentBits (typeWidth - significandBits - 1)
#define maxExponent ((1 << exponentBits) - 1)
#define exponentBias (maxExponent >> 1)
#define implicitBit (REP_C(1) << significandBits)
#define significandMask (implicitBit - 1U)
#define signBit (REP_C(1) << (significandBits + exponentBits))
#define absMask (signBit - 1U)
#define exponentMask (absMask ^ significandMask)
#define oneRep ((rep_t)exponentBias << significandBits)
#define infRep exponentMask
#define quietBit (implicitBit >> 1)
#define qnanRep (exponentMask | quietBit)
static __inline rep_t toRep(fp_t x) {
const union {
@ -226,6 +218,21 @@ static __inline fp_t fromRep(rep_t x) {
return rep.f;
}
#if !defined(QUAD_PRECISION) || defined(CRT_HAS_IEEE_TF)
#define exponentBits (typeWidth - significandBits - 1)
#define maxExponent ((1 << exponentBits) - 1)
#define exponentBias (maxExponent >> 1)
#define implicitBit (REP_C(1) << significandBits)
#define significandMask (implicitBit - 1U)
#define signBit (REP_C(1) << (significandBits + exponentBits))
#define absMask (signBit - 1U)
#define exponentMask (absMask ^ significandMask)
#define oneRep ((rep_t)exponentBias << significandBits)
#define infRep exponentMask
#define quietBit (implicitBit >> 1)
#define qnanRep (exponentMask | quietBit)
static __inline int normalize(rep_t *significand) {
const int shift = rep_clz(*significand) - rep_clz(implicitBit);
*significand <<= shift;
@ -328,6 +335,8 @@ static __inline fp_t __compiler_rt_scalbnX(fp_t x, int y) {
return fromRep(sign | ((rep_t)exp << significandBits) | sig);
}
#endif // !defined(QUAD_PRECISION) || defined(CRT_HAS_IEEE_TF)
// Avoid using fmax from libm.
static __inline fp_t __compiler_rt_fmaxX(fp_t x, fp_t y) {
// If either argument is NaN, return the other argument. If both are NaN,
@ -405,6 +414,8 @@ static __inline tf_float __compiler_rt_fmaxtf(tf_float x, tf_float y) {
#define __compiler_rt_logbl crt_logbl
#define __compiler_rt_scalbnl crt_scalbnl
#define __compiler_rt_fmaxl crt_fmaxl
#define crt_fabstf crt_fabsl
#define crt_copysigntf crt_copysignl
#else
#error Unsupported TF mode type
#endif

View file

@ -189,12 +189,16 @@ typedef long double tf_float;
#define CRT_LDBL_IEEE_F128
#endif
#define TF_C(x) x##L
#elif __LDBL_MANT_DIG__ == 113
// Use long double instead of __float128 if it matches the IEEE 128-bit format.
#elif __LDBL_MANT_DIG__ == 113 || \
(__FLT_RADIX__ == 16 && __LDBL_MANT_DIG__ == 28)
// Use long double instead of __float128 if it matches the IEEE 128-bit format
// or the IBM hexadecimal format.
#define CRT_LDBL_128BIT
#define CRT_HAS_F128
#if __LDBL_MANT_DIG__ == 113
#define CRT_HAS_IEEE_TF
#define CRT_LDBL_IEEE_F128
#endif
typedef long double tf_float;
#define TF_C(x) x##L
#elif defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)

View file

@ -15,7 +15,7 @@
#include "int_lib.h"
#include "int_math.h"
#if defined(CRT_HAS_TF_MODE)
#if defined(CRT_HAS_F128)
// Returns: the product of a + ib and c + id

View file

@ -467,7 +467,7 @@ void __msan_init() {
__msan_clear_on_return();
if (__msan_get_track_origins())
VPrintf(1, "msan_track_origins\n");
if (!InitShadow(__msan_get_track_origins())) {
if (!InitShadowWithReExec(__msan_get_track_origins())) {
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
Printf("FATAL: Disabling ASLR is known to cause this error.\n");

View file

@ -33,12 +33,18 @@ struct MappingDesc {
uptr start;
uptr end;
enum Type {
INVALID, APP, SHADOW, ORIGIN
INVALID = 1,
ALLOCATOR = 2,
APP = 4,
SHADOW = 8,
ORIGIN = 16,
} type;
const char *name;
};
// Note: MappingDesc::ALLOCATOR entries are only used to check for memory
// layout compatibility. The actual allocation settings are in
// msan_allocator.cpp, which need to be kept in sync.
#if SANITIZER_LINUX && defined(__mips64)
// MIPS64 maps:
@ -84,7 +90,8 @@ const MappingDesc kMemoryLayout[] = {
{0X0B00000000000, 0X0C00000000000, MappingDesc::SHADOW, "shadow-10-13"},
{0X0C00000000000, 0X0D00000000000, MappingDesc::INVALID, "invalid"},
{0X0D00000000000, 0X0E00000000000, MappingDesc::ORIGIN, "origin-10-13"},
{0X0E00000000000, 0X1000000000000, MappingDesc::APP, "app-15"},
{0x0E00000000000, 0x0E40000000000, MappingDesc::ALLOCATOR, "allocator"},
{0X0E40000000000, 0X1000000000000, MappingDesc::APP, "app-15"},
};
# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0xB00000000000ULL)
# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x200000000000ULL)
@ -106,7 +113,8 @@ const MappingDesc kMemoryLayout[] = {
{0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
{0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
{0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
{0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
{0x700000000000ULL, 0x740000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x740000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
# define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x100000000000ULL)
@ -118,7 +126,8 @@ const MappingDesc kMemoryLayout[] = {
{0x180200000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
{0x1C0000000000ULL, 0x2C0200000000ULL, MappingDesc::ORIGIN, "origin"},
{0x2C0200000000ULL, 0x300000000000ULL, MappingDesc::INVALID, "invalid"},
{0x300000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};
{0x300000000000ULL, 0x320000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x320000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};
// Various kernels use different low end ranges but we can combine them into one
// big range. They also use different high end ranges but we can map them all to
@ -141,7 +150,8 @@ const MappingDesc kMemoryLayout[] = {
{0x180000000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
{0x1C0000000000ULL, 0x2C0000000000ULL, MappingDesc::ORIGIN, "origin"},
{0x2C0000000000ULL, 0x440000000000ULL, MappingDesc::INVALID, "invalid"},
{0x440000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};
{0x440000000000ULL, 0x460000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x460000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};
#define MEM_TO_SHADOW(mem) \
((((uptr)(mem)) & ~0xC00000000000ULL) + 0x080000000000ULL)
@ -208,7 +218,8 @@ const MappingDesc kMemoryLayout[] = {
{0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
{0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
{0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
{0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
{0x700000000000ULL, 0x740000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x740000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL)
@ -223,20 +234,22 @@ const uptr kMemoryLayoutSize = sizeof(kMemoryLayout) / sizeof(kMemoryLayout[0]);
#ifndef __clang__
__attribute__((optimize("unroll-loops")))
#endif
inline bool addr_is_type(uptr addr, MappingDesc::Type mapping_type) {
inline bool
addr_is_type(uptr addr, int mapping_types) {
// It is critical for performance that this loop is unrolled (because then it is
// simplified into just a few constant comparisons).
#ifdef __clang__
#pragma unroll
#endif
for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
if (kMemoryLayout[i].type == mapping_type &&
if ((kMemoryLayout[i].type & mapping_types) &&
addr >= kMemoryLayout[i].start && addr < kMemoryLayout[i].end)
return true;
return false;
}
#define MEM_IS_APP(mem) addr_is_type((uptr)(mem), MappingDesc::APP)
#define MEM_IS_APP(mem) \
(addr_is_type((uptr)(mem), MappingDesc::APP | MappingDesc::ALLOCATOR))
#define MEM_IS_SHADOW(mem) addr_is_type((uptr)(mem), MappingDesc::SHADOW)
#define MEM_IS_ORIGIN(mem) addr_is_type((uptr)(mem), MappingDesc::ORIGIN)
@ -250,7 +263,7 @@ extern bool msan_init_is_running;
extern int msan_report_count;
bool ProtectRange(uptr beg, uptr end);
bool InitShadow(bool init_origins);
bool InitShadowWithReExec(bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();

View file

@ -48,6 +48,9 @@ struct MsanMapUnmapCallback {
}
};
// Note: to ensure that the allocator is compatible with the application memory
// layout (especially with high-entropy ASLR), kSpaceBeg and kSpaceSize must be
// duplicated as MappingDesc::ALLOCATOR in msan.h.
#if defined(__mips64)
static const uptr kMaxAllowedMallocSize = 2UL << 30;

View file

@ -20,6 +20,9 @@
# include <signal.h>
# include <stdio.h>
# include <stdlib.h>
# if SANITIZER_LINUX
# include <sys/personality.h>
# endif
# include <sys/resource.h>
# include <sys/time.h>
# include <unistd.h>
@ -43,11 +46,13 @@ void ReportMapRange(const char *descr, uptr beg, uptr size) {
}
}
static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
if (size > 0) {
uptr end = beg + size - 1;
if (!MemoryRangeIsAvailable(beg, end)) {
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end);
if (verbose)
Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg,
end);
return false;
}
}
@ -86,7 +91,7 @@ static void CheckMemoryLayoutSanity() {
CHECK(addr_is_type(start, type));
CHECK(addr_is_type((start + end) / 2, type));
CHECK(addr_is_type(end - 1, type));
if (type == MappingDesc::APP) {
if (type == MappingDesc::APP || type == MappingDesc::ALLOCATOR) {
uptr addr = start;
CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
@ -106,7 +111,7 @@ static void CheckMemoryLayoutSanity() {
}
}
bool InitShadow(bool init_origins) {
static bool InitShadow(bool init_origins, bool dry_run) {
// Let user know mapping parameters first.
VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));
for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
@ -116,8 +121,9 @@ bool InitShadow(bool init_origins) {
CheckMemoryLayoutSanity();
if (!MEM_IS_APP(&__msan_init)) {
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
reinterpret_cast<void *>(&__msan_init));
if (!dry_run)
Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
reinterpret_cast<void *>(&__msan_init));
return false;
}
@ -138,20 +144,26 @@ bool InitShadow(bool init_origins) {
bool protect = type == MappingDesc::INVALID ||
(!init_origins && type == MappingDesc::ORIGIN);
CHECK(!(map && protect));
if (!map && !protect)
CHECK(type == MappingDesc::APP);
if (!map && !protect) {
CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
if (dry_run && type == MappingDesc::ALLOCATOR &&
!CheckMemoryRangeAvailability(start, size, !dry_run))
return false;
}
if (map) {
if (!CheckMemoryRangeAvailability(start, size))
if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
return false;
if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
if (!dry_run &&
!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
return false;
if (common_flags()->use_madv_dontdump)
if (!dry_run && common_flags()->use_madv_dontdump)
DontDumpShadowMemory(start, size);
}
if (protect) {
if (!CheckMemoryRangeAvailability(start, size))
if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
return false;
if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
return false;
}
}
@ -159,6 +171,35 @@ bool InitShadow(bool init_origins) {
return true;
}
bool InitShadowWithReExec(bool init_origins) {
// Start with dry run: check layout is ok, but don't print warnings because
// warning messages will cause tests to fail (even if we successfully re-exec
// after the warning).
bool success = InitShadow(__msan_get_track_origins(), true);
if (!success) {
# if SANITIZER_LINUX
// Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
int old_personality = personality(0xffffffff);
bool aslr_on =
(old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
if (aslr_on) {
VReport(1,
"WARNING: MemorySanitizer: memory layout is incompatible, "
"possibly due to high-entropy ASLR.\n"
"Re-execing with fixed virtual address space.\n"
"N.B. reducing ASLR entropy is preferable.\n");
CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
ReExec();
}
# endif
}
// The earlier dry run didn't actually map or protect anything. Run again in
// non-dry run mode.
return success && InitShadow(__msan_get_track_origins(), false);
}
static void MsanAtExit(void) {
if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
ReportStats();

View file

@ -14,6 +14,7 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_glibc_version.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
@ -1613,47 +1614,40 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
FdAccess(thr, pc, fd);
return REAL(__fxstat)(version, fd, buf);
}
#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
#else
#define TSAN_MAYBE_INTERCEPT___FXSTAT
#endif
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
#if SANITIZER_GLIBC
SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat)(0, fd, buf);
#else
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(fstat)(fd, buf);
#endif
}
#if SANITIZER_GLIBC
TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat64)(version, fd, buf);
}
#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat); TSAN_INTERCEPT(__fxstat64)
#else
#define TSAN_MAYBE_INTERCEPT___FXSTAT64
#define TSAN_MAYBE_INTERCEPT___FXSTAT
#endif
#if SANITIZER_GLIBC
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
#if !SANITIZER_GLIBC || __GLIBC_PREREQ(2, 33)
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(__fxstat64)(0, fd, buf);
return REAL(fstat)(fd, buf);
}
#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
# define TSAN_MAYBE_INTERCEPT_FSTAT TSAN_INTERCEPT(fstat)
#else
#define TSAN_MAYBE_INTERCEPT_FSTAT64
# define TSAN_MAYBE_INTERCEPT_FSTAT
#endif
#if __GLIBC_PREREQ(2, 33)
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(fstat64, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
return REAL(fstat64)(fd, buf);
}
# define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
#else
# define TSAN_MAYBE_INTERCEPT_FSTAT64
#endif
TSAN_INTERCEPTOR(int, open, const char *name, int oflag, ...) {
@ -2950,10 +2944,9 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_once);
TSAN_INTERCEPT(fstat);
TSAN_MAYBE_INTERCEPT___FXSTAT;
TSAN_MAYBE_INTERCEPT_FSTAT;
TSAN_MAYBE_INTERCEPT_FSTAT64;
TSAN_MAYBE_INTERCEPT___FXSTAT64;
TSAN_INTERCEPT(open);
TSAN_MAYBE_INTERCEPT_OPEN64;
TSAN_INTERCEPT(creat);

View file

@ -72,11 +72,10 @@
# endif
#endif
// Availability markup is disabled when building the library, or when the compiler
// Availability markup is disabled when building the library, or when a non-Clang
// compiler is used because only Clang supports the necessary attributes.
// doesn't support the proper attributes.
#if defined(_LIBCPP_BUILDING_LIBRARY) || defined(_LIBCXXABI_BUILDING_LIBRARY) || \
!__has_feature(attribute_availability_with_strict) || !__has_feature(attribute_availability_in_templates) || \
!__has_extension(pragma_clang_attribute_external_declaration)
#if defined(_LIBCPP_BUILDING_LIBRARY) || defined(_LIBCXXABI_BUILDING_LIBRARY) || !defined(_LIBCPP_COMPILER_CLANG_BASED)
# if !defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
# define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS
# endif

View file

@ -5,7 +5,7 @@
{
"logical-name": "std",
"source-path": "@LIBCXX_MODULE_RELATIVE_PATH@/std.cppm",
"is-standard-library": true,
"is-std-library": true,
"local-arguments": {
"system-include-directories": [
"@LIBCXX_MODULE_RELATIVE_PATH@"

View file

@ -172,7 +172,7 @@ binImports(COFFLinkerContext &ctx,
// A chunk for the delay import descriptor table etnry.
class DelayDirectoryChunk : public NonSectionChunk {
public:
explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {}
explicit DelayDirectoryChunk(Chunk *n) : dllName(n) { setAlignment(4); }
size_t getSize() const override {
return sizeof(delay_import_directory_table_entry);

View file

@ -11,6 +11,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/Support/LEB128.h"
using namespace llvm;
using namespace llvm::object;
@ -41,6 +42,7 @@ class LoongArch final : public TargetInfo {
};
} // end anonymous namespace
namespace {
enum Op {
SUB_W = 0x00110000,
SUB_D = 0x00118000,
@ -65,6 +67,7 @@ enum Reg {
R_T2 = 14,
R_T3 = 15,
};
} // namespace
// Mask out the input's lowest 12 bits for use with `pcalau12i`, in sequences
// like `pcalau12i + addi.[wd]` or `pcalau12i + {ld,st}.*` where the `pcalau12i`
@ -153,6 +156,17 @@ static bool isJirl(uint32_t insn) {
return (insn & 0xfc000000) == JIRL;
}
static void handleUleb128(uint8_t *loc, uint64_t val) {
const uint32_t maxcount = 1 + 64 / 7;
uint32_t count;
const char *error = nullptr;
uint64_t orig = decodeULEB128(loc, &count, nullptr, &error);
if (count > maxcount || (count == maxcount && error))
errorOrWarn(getErrorLocation(loc) + "extra space for uleb128");
uint64_t mask = count < maxcount ? (1ULL << 7 * count) - 1 : -1ULL;
encodeULEB128((orig + val) & mask, loc, count);
}
LoongArch::LoongArch() {
// The LoongArch ISA itself does not have a limit on page sizes. According to
// the ISA manual, the PS (page size) field in MTLB entries and CSR.STLBPS is
@ -394,11 +408,13 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
case R_LARCH_ADD16:
case R_LARCH_ADD32:
case R_LARCH_ADD64:
case R_LARCH_ADD_ULEB128:
case R_LARCH_SUB6:
case R_LARCH_SUB8:
case R_LARCH_SUB16:
case R_LARCH_SUB32:
case R_LARCH_SUB64:
case R_LARCH_SUB_ULEB128:
// The LoongArch add/sub relocs behave like the RISCV counterparts; reuse
// the RelExpr to avoid code duplication.
return R_RISCV_ADD;
@ -633,6 +649,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
case R_LARCH_ADD64:
write64le(loc, read64le(loc) + val);
return;
case R_LARCH_ADD_ULEB128:
handleUleb128(loc, val);
return;
case R_LARCH_SUB6:
*loc = (*loc & 0xc0) | ((*loc - val) & 0x3f);
return;
@ -648,6 +667,9 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
case R_LARCH_SUB64:
write64le(loc, read64le(loc) - val);
return;
case R_LARCH_SUB_ULEB128:
handleUleb128(loc, -val);
return;
case R_LARCH_MARK_LA:
case R_LARCH_MARK_PCREL:

View file

@ -26,6 +26,7 @@ using namespace lld::elf;
constexpr uint64_t ppc64TocOffset = 0x8000;
constexpr uint64_t dynamicThreadPointerOffset = 0x8000;
namespace {
// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
// instructions that can be used as part of the initial exec TLS sequence.
enum XFormOpcd {
@ -139,6 +140,7 @@ enum class PPCPrefixedInsn : uint64_t {
PSTXV = PREFIX_8LS | 0xd8000000,
PSTXVP = PREFIX_8LS | 0xf8000000
};
static bool checkPPCLegacyInsn(uint32_t encoding) {
PPCLegacyInsn insn = static_cast<PPCLegacyInsn>(encoding);
if (insn == PPCLegacyInsn::NOINSN)
@ -164,7 +166,6 @@ enum class LegacyToPrefixMask : uint64_t {
0x8000000003e00000, // S/T (6-10) - The [S/T]X bit moves from 28 to 5.
};
namespace {
class PPC64 final : public TargetInfo {
public:
PPC64();

View file

@ -57,6 +57,7 @@ class RISCV final : public TargetInfo {
const uint64_t dtpOffset = 0x800;
namespace {
enum Op {
ADDI = 0x13,
AUIPC = 0x17,
@ -78,6 +79,7 @@ enum Reg {
X_A0 = 10,
X_T3 = 28,
};
} // namespace
static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
static uint32_t lo12(uint32_t val) { return val & 4095; }

View file

@ -328,9 +328,10 @@ bool X86_64::relaxOnce(int pass) const {
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);
uint64_t v = sec->getRelocTargetVA(sec->file, rel.type, rel.addend,
sec->getOutputSection()->addr +
sec->outSecOff + rel.offset,
*rel.sym, rel.expr);
if (isInt<32>(v))
continue;
if (rel.sym->auxIdx == 0) {

View file

@ -261,6 +261,9 @@ static void demoteDefined(Defined &sym, DenseMap<SectionBase *, size_t> &map) {
Undefined(sym.file, sym.getName(), binding, sym.stOther, sym.type,
/*discardedSecIdx=*/map.lookup(sym.section))
.overwrite(sym);
// Eliminate from the symbol table, otherwise we would leave an undefined
// symbol if the symbol is unreferenced in the absence of GC.
sym.isUsedInRegularObj = false;
}
// If all references to a DSO happen to be weak, the DSO is not added to

View file

@ -163,5 +163,10 @@ WebAssembly Improvements
is read from object files within the archive. This matches the behaviour of
the ELF linker.
SystemZ
-------
* Add target support for SystemZ (s390x).
Fixes
#####

View file

@ -406,6 +406,11 @@ bool maskIsAllZeroOrUndef(Value *Mask);
/// lanes can be assumed active.
bool maskIsAllOneOrUndef(Value *Mask);
/// Given a mask vector of i1, Return true if any of the elements of this
/// predicate mask are known to be true or undef. That is, return true if at
/// least one lane can be assumed active.
bool maskContainsAllOneOrUndef(Value *Mask);
/// Given a mask vector of the form <Y x i1>, return an APInt (of bitwidth Y)
/// for each lane which may be active.
APInt possiblyDemandedEltsInMask(Value *Mask);

View file

@ -716,7 +716,10 @@ enum ImportNameType : unsigned {
IMPORT_NAME_NOPREFIX = 2,
/// The import name is the public symbol name, but skipping the leading ?,
/// @, or optionally _, and truncating at the first @.
IMPORT_NAME_UNDECORATE = 3
IMPORT_NAME_UNDECORATE = 3,
/// The import name is specified as a separate string in the import library
/// object file.
IMPORT_NAME_EXPORTAS = 4
};
enum class GuardFlags : uint32_t {

View file

@ -1362,6 +1362,47 @@ class SectionStrippedError
SectionStrippedError() { setErrorCode(object_error::section_stripped); }
};
inline std::optional<std::string>
getArm64ECMangledFunctionName(StringRef Name) {
bool IsCppFn = Name[0] == '?';
if (IsCppFn && Name.find("$$h") != std::string::npos)
return std::nullopt;
if (!IsCppFn && Name[0] == '#')
return std::nullopt;
StringRef Prefix = "$$h";
size_t InsertIdx = 0;
if (IsCppFn) {
InsertIdx = Name.find("@@");
size_t ThreeAtSignsIdx = Name.find("@@@");
if (InsertIdx != std::string::npos && InsertIdx != ThreeAtSignsIdx) {
InsertIdx += 2;
} else {
InsertIdx = Name.find("@");
if (InsertIdx != std::string::npos)
InsertIdx++;
}
} else {
Prefix = "#";
}
return std::optional<std::string>(
(Name.substr(0, InsertIdx) + Prefix + Name.substr(InsertIdx)).str());
}
inline std::optional<std::string>
getArm64ECDemangledFunctionName(StringRef Name) {
if (Name[0] == '#')
return std::string(Name.substr(1));
if (Name[0] != '?')
return std::nullopt;
std::pair<StringRef, StringRef> Pair = Name.split("$$h");
if (Pair.second.empty())
return std::nullopt;
return (Pair.first + Pair.second).str();
}
} // end namespace object
} // end namespace llvm

View file

@ -26,7 +26,16 @@
namespace llvm {
namespace object {
constexpr std::string_view ImportDescriptorPrefix = "__IMPORT_DESCRIPTOR_";
constexpr std::string_view NullImportDescriptorSymbolName =
"__NULL_IMPORT_DESCRIPTOR";
constexpr std::string_view NullThunkDataPrefix = "\x7f";
constexpr std::string_view NullThunkDataSuffix = "_NULL_THUNK_DATA";
class COFFImportFile : public SymbolicFile {
private:
enum SymbolIndex { ImpSymbol, ThunkSymbol, ECAuxSymbol, ECThunkSymbol };
public:
COFFImportFile(MemoryBufferRef Source)
: SymbolicFile(ID_COFFImportFile, Source) {}
@ -36,9 +45,23 @@ class COFFImportFile : public SymbolicFile {
void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; }
Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override {
if (Symb.p == 0)
switch (Symb.p) {
case ImpSymbol:
OS << "__imp_";
OS << StringRef(Data.getBufferStart() + sizeof(coff_import_header));
break;
case ECAuxSymbol:
OS << "__imp_aux_";
break;
}
const char *Name = Data.getBufferStart() + sizeof(coff_import_header);
if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) {
if (std::optional<std::string> DemangledName =
getArm64ECDemangledFunctionName(Name)) {
OS << StringRef(*DemangledName);
return Error::success();
}
}
OS << StringRef(Name);
return Error::success();
}
@ -52,7 +75,12 @@ class COFFImportFile : public SymbolicFile {
basic_symbol_iterator symbol_end() const override {
DataRefImpl Symb;
Symb.p = isData() ? 1 : 2;
if (isData())
Symb.p = ImpSymbol + 1;
else if (COFF::isArm64EC(getMachine()))
Symb.p = ECThunkSymbol + 1;
else
Symb.p = ThunkSymbol + 1;
return BasicSymbolRef(Symb, this);
}
@ -66,6 +94,7 @@ class COFFImportFile : public SymbolicFile {
uint16_t getMachine() const { return getCOFFImportHeader()->Machine; }
StringRef getFileFormatName() const;
StringRef getExportName() const;
private:
bool isData() const {

View file

@ -52,6 +52,10 @@ class formatted_raw_ostream : public raw_ostream {
/// have the rest of it.
SmallString<4> PartialUTF8Char;
/// DisableScan - Temporarily disable scanning of output. Used to ignore color
/// codes.
bool DisableScan;
void write_impl(const char *Ptr, size_t Size) override;
/// current_pos - Return the current position within the stream,
@ -89,9 +93,33 @@ class formatted_raw_ostream : public raw_ostream {
SetUnbuffered();
TheStream->SetUnbuffered();
enable_colors(TheStream->colors_enabled());
Scanned = nullptr;
}
void PreDisableScan() {
assert(!DisableScan);
ComputePosition(getBufferStart(), GetNumBytesInBuffer());
assert(PartialUTF8Char.empty());
DisableScan = true;
}
void PostDisableScan() {
assert(DisableScan);
DisableScan = false;
Scanned = getBufferStart() + GetNumBytesInBuffer();
}
struct DisableScanScope {
formatted_raw_ostream *S;
DisableScanScope(formatted_raw_ostream *FRO) : S(FRO) {
S->PreDisableScan();
}
~DisableScanScope() { S->PostDisableScan(); }
};
public:
/// formatted_raw_ostream - Open the specified file for
/// writing. If an error occurs, information about the error is
@ -104,12 +132,12 @@ class formatted_raw_ostream : public raw_ostream {
/// underneath it.
///
formatted_raw_ostream(raw_ostream &Stream)
: TheStream(nullptr), Position(0, 0) {
: TheStream(nullptr), Position(0, 0), DisableScan(false) {
setStream(Stream);
}
explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) {
Scanned = nullptr;
}
explicit formatted_raw_ostream()
: TheStream(nullptr), Position(0, 0), Scanned(nullptr),
DisableScan(false) {}
~formatted_raw_ostream() override {
flush();
@ -136,17 +164,26 @@ class formatted_raw_ostream : public raw_ostream {
}
raw_ostream &resetColor() override {
TheStream->resetColor();
if (colors_enabled()) {
DisableScanScope S(this);
raw_ostream::resetColor();
}
return *this;
}
raw_ostream &reverseColor() override {
TheStream->reverseColor();
if (colors_enabled()) {
DisableScanScope S(this);
raw_ostream::reverseColor();
}
return *this;
}
raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override {
TheStream->changeColor(Color, Bold, BG);
if (colors_enabled()) {
DisableScanScope S(this);
raw_ostream::changeColor(Color, Bold, BG);
}
return *this;
}

View file

@ -620,7 +620,7 @@ class SecondFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
: FusionPredicateWithMCInstPredicate<second_fusion_target, pred>;
// The pred will be applied on both firstMI and secondMI.
class BothFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
: FusionPredicateWithMCInstPredicate<second_fusion_target, pred>;
: FusionPredicateWithMCInstPredicate<both_fusion_target, pred>;
// Tie firstOpIdx and secondOpIdx. The operand of `FirstMI` at position
// `firstOpIdx` should be the same as the operand of `SecondMI` at position

View file

@ -5986,6 +5986,8 @@ void llvm::getUnderlyingObjects(const Value *V,
if (!LI || !LI->isLoopHeader(PN->getParent()) ||
isSameUnderlyingObjectInLoop(PN, LI))
append_range(Worklist, PN->incoming_values());
else
Objects.push_back(P);
continue;
}

View file

@ -1012,6 +1012,31 @@ bool llvm::maskIsAllOneOrUndef(Value *Mask) {
return true;
}
bool llvm::maskContainsAllOneOrUndef(Value *Mask) {
assert(isa<VectorType>(Mask->getType()) &&
isa<IntegerType>(Mask->getType()->getScalarType()) &&
cast<IntegerType>(Mask->getType()->getScalarType())->getBitWidth() ==
1 &&
"Mask must be a vector of i1");
auto *ConstMask = dyn_cast<Constant>(Mask);
if (!ConstMask)
return false;
if (ConstMask->isAllOnesValue() || isa<UndefValue>(ConstMask))
return true;
if (isa<ScalableVectorType>(ConstMask->getType()))
return false;
for (unsigned
I = 0,
E = cast<FixedVectorType>(ConstMask->getType())->getNumElements();
I != E; ++I) {
if (auto *MaskElt = ConstMask->getAggregateElement(I))
if (MaskElt->isAllOnesValue() || isa<UndefValue>(MaskElt))
return true;
}
return false;
}
/// TODO: This is a lot like known bits, but for
/// vectors. Is there something we can common this with?
APInt llvm::possiblyDemandedEltsInMask(Value *Mask) {

View file

@ -44,6 +44,7 @@
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolMachO.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Casting.h"
@ -1950,7 +1951,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
Lex();
}
if (MAI.hasSubsectionsViaSymbols() && CFIStartProcLoc && Sym->isExternal())
if (MAI.hasSubsectionsViaSymbols() && CFIStartProcLoc &&
Sym->isExternal() && !cast<MCSymbolMachO>(Sym)->isAltEntry())
return Error(StartTokLoc, "non-private labels cannot appear between "
".cfi_startproc / .cfi_endproc pairs") &&
Error(*CFIStartProcLoc, "previous .cfi_startproc was here");

View file

@ -677,6 +677,13 @@ static bool isECObject(object::SymbolicFile &Obj) {
return false;
}
bool isImportDescriptor(StringRef Name) {
return Name.starts_with(ImportDescriptorPrefix) ||
Name == StringRef{NullImportDescriptorSymbolName} ||
(Name.starts_with(NullThunkDataPrefix) &&
Name.ends_with(NullThunkDataSuffix));
}
static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj,
uint16_t Index,
raw_ostream &SymNames,
@ -704,6 +711,10 @@ static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj,
if (Map == &SymMap->Map) {
Ret.push_back(SymNames.tell());
SymNames << Name << '\0';
// If EC is enabled, then the import descriptors are NOT put into EC
// objects so we need to copy them to the EC map manually.
if (SymMap->UseECMap && isImportDescriptor(Name))
SymMap->ECMap[Name] = Index;
}
} else {
Ret.push_back(SymNames.tell());

View file

@ -52,6 +52,38 @@ StringRef COFFImportFile::getFileFormatName() const {
}
}
StringRef COFFImportFile::getExportName() const {
const coff_import_header *hdr = getCOFFImportHeader();
StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first;
auto ltrim1 = [](StringRef s, StringRef chars) {
return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s;
};
switch (hdr->getNameType()) {
case IMPORT_ORDINAL:
name = "";
break;
case IMPORT_NAME_NOPREFIX:
name = ltrim1(name, "?@_");
break;
case IMPORT_NAME_UNDECORATE:
name = ltrim1(name, "?@_");
name = name.substr(0, name.find('@'));
break;
case IMPORT_NAME_EXPORTAS: {
// Skip DLL name
name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1);
name = name.split('\0').second.split('\0').first;
break;
}
default:
break;
}
return name;
}
static uint16_t getImgRelRelocation(MachineTypes Machine) {
switch (Machine) {
default:
@ -76,7 +108,7 @@ template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
}
static void writeStringTable(std::vector<uint8_t> &B,
ArrayRef<const std::string> Strings) {
ArrayRef<const std::string_view> Strings) {
// The COFF string table consists of a 4-byte value which is the size of the
// table, including the length field itself. This value is followed by the
// string content itself, which is an array of null-terminated C-style
@ -139,9 +171,6 @@ static Expected<std::string> replace(StringRef S, StringRef From,
return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
}
static const std::string NullImportDescriptorSymbolName =
"__NULL_IMPORT_DESCRIPTOR";
namespace {
// This class constructs various small object files necessary to support linking
// symbols imported from a DLL. The contents are pretty strictly defined and
@ -160,8 +189,9 @@ class ObjectFactory {
public:
ObjectFactory(StringRef S, MachineTypes M)
: NativeMachine(M), ImportName(S), Library(llvm::sys::path::stem(S)),
ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
ImportDescriptorSymbolName((ImportDescriptorPrefix + Library).str()),
NullThunkSymbolName(
(NullThunkDataPrefix + Library + NullThunkDataSuffix).str()) {}
// Creates an Import Descriptor. This is a small object file which contains a
// reference to the terminators and contains the library name (entry) for the
@ -183,6 +213,7 @@ class ObjectFactory {
// Library Format.
NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
ImportType Type, ImportNameType NameType,
StringRef ExportName,
MachineTypes Machine);
// Create a weak external file which is described in PE/COFF Aux Format 3.
@ -474,12 +505,13 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
return {MemoryBufferRef{F, ImportName}};
}
NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
uint16_t Ordinal,
ImportType ImportType,
ImportNameType NameType,
MachineTypes Machine) {
NewArchiveMember
ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal,
ImportType ImportType, ImportNameType NameType,
StringRef ExportName, MachineTypes Machine) {
size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
if (!ExportName.empty())
ImpSize += ExportName.size() + 1;
size_t Size = sizeof(coff_import_header) + ImpSize;
char *Buf = Alloc.Allocate<char>(Size);
memset(Buf, 0, Size);
@ -499,6 +531,10 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
memcpy(P, Sym.data(), Sym.size());
P += Sym.size() + 1;
memcpy(P, ImportName.data(), ImportName.size());
if (!ExportName.empty()) {
P += ImportName.size() + 1;
memcpy(P, ExportName.data(), ExportName.size());
}
return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
}
@ -615,27 +651,51 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path,
ImportType = IMPORT_CONST;
StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
ImportNameType NameType = E.Noname
? IMPORT_ORDINAL
: getNameType(SymbolName, E.Name,
Machine, MinGW);
Expected<std::string> Name = E.ExtName.empty()
? std::string(SymbolName)
: replace(SymbolName, E.Name, E.ExtName);
std::string Name;
if (!Name)
return Name.takeError();
if (E.ExtName.empty()) {
Name = std::string(SymbolName);
} else {
Expected<std::string> ReplacedName =
replace(SymbolName, E.Name, E.ExtName);
if (!ReplacedName)
return ReplacedName.takeError();
Name.swap(*ReplacedName);
}
if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
if (!E.AliasTarget.empty() && Name != E.AliasTarget) {
Members.push_back(
OF.createWeakExternal(E.AliasTarget, *Name, false, Machine));
OF.createWeakExternal(E.AliasTarget, Name, false, Machine));
Members.push_back(
OF.createWeakExternal(E.AliasTarget, *Name, true, Machine));
OF.createWeakExternal(E.AliasTarget, Name, true, Machine));
continue;
}
Members.push_back(
OF.createShortImport(*Name, E.Ordinal, ImportType, NameType, Machine));
ImportNameType NameType;
std::string ExportName;
if (E.Noname) {
NameType = IMPORT_ORDINAL;
} else {
NameType = getNameType(SymbolName, E.Name, Machine, MinGW);
}
// On ARM64EC, use EXPORTAS to import demangled name for mangled symbols.
if (ImportType == IMPORT_CODE && isArm64EC(Machine)) {
if (std::optional<std::string> MangledName =
getArm64ECMangledFunctionName(Name)) {
if (ExportName.empty()) {
NameType = IMPORT_NAME_EXPORTAS;
ExportName.swap(Name);
}
Name = std::move(*MangledName);
} else if (ExportName.empty()) {
NameType = IMPORT_NAME_EXPORTAS;
ExportName = std::move(*getArm64ECDemangledFunctionName(Name));
}
}
Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
NameType, ExportName, Machine));
}
return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab,

View file

@ -94,6 +94,9 @@ void formatted_raw_ostream::UpdatePosition(const char *Ptr, size_t Size) {
/// ComputePosition - Examine the current output and update line and column
/// counts.
void formatted_raw_ostream::ComputePosition(const char *Ptr, size_t Size) {
if (DisableScan)
return;
// If our previous scan pointer is inside the buffer, assume we already
// scanned those bytes. This depends on raw_ostream to not change our buffer
// in unexpected ways.

View file

@ -24,11 +24,13 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
#include "llvm/InitializePasses.h"
#include "llvm/Object/COFF.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/TargetParser/Triple.h"
using namespace llvm;
using namespace llvm::object;
using OperandBundleDef = OperandBundleDefT<Value *>;
@ -43,6 +45,8 @@ static cl::opt<bool> GenerateThunks("arm64ec-generate-thunks", cl::Hidden,
namespace {
enum class ThunkType { GuestExit, Entry, Exit };
class AArch64Arm64ECCallLowering : public ModulePass {
public:
static char ID;
@ -69,14 +73,14 @@ class AArch64Arm64ECCallLowering : public ModulePass {
Type *I64Ty;
Type *VoidTy;
void getThunkType(FunctionType *FT, AttributeList AttrList, bool EntryThunk,
void getThunkType(FunctionType *FT, AttributeList AttrList, ThunkType TT,
raw_ostream &Out, FunctionType *&Arm64Ty,
FunctionType *&X64Ty);
void getThunkRetType(FunctionType *FT, AttributeList AttrList,
raw_ostream &Out, Type *&Arm64RetTy, Type *&X64RetTy,
SmallVectorImpl<Type *> &Arm64ArgTypes,
SmallVectorImpl<Type *> &X64ArgTypes, bool &HasSretPtr);
void getThunkArgTypes(FunctionType *FT, AttributeList AttrList,
void getThunkArgTypes(FunctionType *FT, AttributeList AttrList, ThunkType TT,
raw_ostream &Out,
SmallVectorImpl<Type *> &Arm64ArgTypes,
SmallVectorImpl<Type *> &X64ArgTypes, bool HasSretPtr);
@ -89,10 +93,11 @@ class AArch64Arm64ECCallLowering : public ModulePass {
void AArch64Arm64ECCallLowering::getThunkType(FunctionType *FT,
AttributeList AttrList,
bool EntryThunk, raw_ostream &Out,
ThunkType TT, raw_ostream &Out,
FunctionType *&Arm64Ty,
FunctionType *&X64Ty) {
Out << (EntryThunk ? "$ientry_thunk$cdecl$" : "$iexit_thunk$cdecl$");
Out << (TT == ThunkType::Entry ? "$ientry_thunk$cdecl$"
: "$iexit_thunk$cdecl$");
Type *Arm64RetTy;
Type *X64RetTy;
@ -102,8 +107,8 @@ void AArch64Arm64ECCallLowering::getThunkType(FunctionType *FT,
// The first argument to a thunk is the called function, stored in x9.
// For exit thunks, we pass the called function down to the emulator;
// for entry thunks, we just call the Arm64 function directly.
if (!EntryThunk)
// for entry/guest exit thunks, we just call the Arm64 function directly.
if (TT == ThunkType::Exit)
Arm64ArgTypes.push_back(PtrTy);
X64ArgTypes.push_back(PtrTy);
@ -111,14 +116,16 @@ void AArch64Arm64ECCallLowering::getThunkType(FunctionType *FT,
getThunkRetType(FT, AttrList, Out, Arm64RetTy, X64RetTy, Arm64ArgTypes,
X64ArgTypes, HasSretPtr);
getThunkArgTypes(FT, AttrList, Out, Arm64ArgTypes, X64ArgTypes, HasSretPtr);
getThunkArgTypes(FT, AttrList, TT, Out, Arm64ArgTypes, X64ArgTypes,
HasSretPtr);
Arm64Ty = FunctionType::get(Arm64RetTy, Arm64ArgTypes, false);
X64Ty = FunctionType::get(X64RetTy, X64ArgTypes, false);
}
void AArch64Arm64ECCallLowering::getThunkArgTypes(
FunctionType *FT, AttributeList AttrList, raw_ostream &Out,
FunctionType *FT, AttributeList AttrList, ThunkType TT, raw_ostream &Out,
SmallVectorImpl<Type *> &Arm64ArgTypes,
SmallVectorImpl<Type *> &X64ArgTypes, bool HasSretPtr) {
@ -156,9 +163,11 @@ void AArch64Arm64ECCallLowering::getThunkArgTypes(
X64ArgTypes.push_back(PtrTy);
// x5
Arm64ArgTypes.push_back(I64Ty);
// FIXME: x5 isn't actually passed/used by the x64 side; revisit once we
// have proper isel for varargs
X64ArgTypes.push_back(I64Ty);
if (TT != ThunkType::Entry) {
// FIXME: x5 isn't actually used by the x64 side; revisit once we
// have proper isel for varargs
X64ArgTypes.push_back(I64Ty);
}
return;
}
@ -339,8 +348,7 @@ Function *AArch64Arm64ECCallLowering::buildExitThunk(FunctionType *FT,
SmallString<256> ExitThunkName;
llvm::raw_svector_ostream ExitThunkStream(ExitThunkName);
FunctionType *Arm64Ty, *X64Ty;
getThunkType(FT, Attrs, /*EntryThunk*/ false, ExitThunkStream, Arm64Ty,
X64Ty);
getThunkType(FT, Attrs, ThunkType::Exit, ExitThunkStream, Arm64Ty, X64Ty);
if (Function *F = M->getFunction(ExitThunkName))
return F;
@ -443,7 +451,7 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
SmallString<256> EntryThunkName;
llvm::raw_svector_ostream EntryThunkStream(EntryThunkName);
FunctionType *Arm64Ty, *X64Ty;
getThunkType(F->getFunctionType(), F->getAttributes(), /*EntryThunk*/ true,
getThunkType(F->getFunctionType(), F->getAttributes(), ThunkType::Entry,
EntryThunkStream, Arm64Ty, X64Ty);
if (Function *F = M->getFunction(EntryThunkName))
return F;
@ -465,10 +473,11 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
bool TransformDirectToSRet = X64RetType->isVoidTy() && !RetTy->isVoidTy();
unsigned ThunkArgOffset = TransformDirectToSRet ? 2 : 1;
unsigned PassthroughArgSize = F->isVarArg() ? 5 : Thunk->arg_size();
// Translate arguments to call.
SmallVector<Value *> Args;
for (unsigned i = ThunkArgOffset, e = Thunk->arg_size(); i != e; ++i) {
for (unsigned i = ThunkArgOffset, e = PassthroughArgSize; i != e; ++i) {
Value *Arg = Thunk->getArg(i);
Type *ArgTy = Arm64Ty->getParamType(i - ThunkArgOffset);
if (ArgTy->isArrayTy() || ArgTy->isStructTy() ||
@ -485,6 +494,22 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
Args.push_back(Arg);
}
if (F->isVarArg()) {
// The 5th argument to variadic entry thunks is used to model the x64 sp
// which is passed to the thunk in x4, this can be passed to the callee as
// the variadic argument start address after skipping over the 32 byte
// shadow store.
// The EC thunk CC will assign any argument marked as InReg to x4.
Thunk->addParamAttr(5, Attribute::InReg);
Value *Arg = Thunk->getArg(5);
Arg = IRB.CreatePtrAdd(Arg, IRB.getInt64(0x20));
Args.push_back(Arg);
// Pass in a zero variadic argument size (in x5).
Args.push_back(IRB.getInt64(0));
}
// Call the function passed to the thunk.
Value *Callee = Thunk->getArg(0);
Callee = IRB.CreateBitCast(Callee, PtrTy);
@ -518,7 +543,7 @@ Function *AArch64Arm64ECCallLowering::buildEntryThunk(Function *F) {
Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
llvm::raw_null_ostream NullThunkName;
FunctionType *Arm64Ty, *X64Ty;
getThunkType(F->getFunctionType(), F->getAttributes(), /*EntryThunk*/ true,
getThunkType(F->getFunctionType(), F->getAttributes(), ThunkType::GuestExit,
NullThunkName, Arm64Ty, X64Ty);
auto MangledName = getArm64ECMangledFunctionName(F->getName().str());
assert(MangledName && "Can't guest exit to function that's already native");

View file

@ -213,6 +213,9 @@ def CC_AArch64_Arm64EC_VarArg : CallingConv<[
// address is passed in X9.
let Entry = 1 in
def CC_AArch64_Arm64EC_Thunk : CallingConv<[
// ARM64EC-specific: the InReg attribute can be used to access the x64 sp passed into entry thunks in x4 from the IR.
CCIfInReg<CCIfType<[i64], CCAssignToReg<[X4]>>>,
// Byval aggregates are passed by pointer
CCIfByVal<CCPassIndirect<i64>>,

View file

@ -8007,11 +8007,19 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
}
if (IsVarArg && Subtarget->isWindowsArm64EC()) {
SDValue ParamPtr = StackPtr;
if (IsTailCall) {
// Create a dummy object at the top of the stack that can be used to get
// the SP after the epilogue
int FI = MF.getFrameInfo().CreateFixedObject(1, FPDiff, true);
ParamPtr = DAG.getFrameIndex(FI, PtrVT);
}
// For vararg calls, the Arm64EC ABI requires values in x4 and x5
// describing the argument list. x4 contains the address of the
// first stack parameter. x5 contains the size in bytes of all parameters
// passed on the stack.
RegsToPass.emplace_back(AArch64::X4, StackPtr);
RegsToPass.emplace_back(AArch64::X4, ParamPtr);
RegsToPass.emplace_back(AArch64::X5,
DAG.getConstant(NumBytes, DL, MVT::i64));
}

View file

@ -23,11 +23,13 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
using namespace llvm::object;
extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;

View file

@ -248,34 +248,6 @@ static inline bool atomicBarrierDroppedOnZero(unsigned Opcode) {
return false;
}
static inline std::optional<std::string>
getArm64ECMangledFunctionName(std::string Name) {
bool IsCppFn = Name[0] == '?';
if (IsCppFn && Name.find("$$h") != std::string::npos)
return std::nullopt;
if (!IsCppFn && Name[0] == '#')
return std::nullopt;
StringRef Prefix = "$$h";
size_t InsertIdx = 0;
if (IsCppFn) {
InsertIdx = Name.find("@@");
size_t ThreeAtSignsIdx = Name.find("@@@");
if (InsertIdx != std::string::npos && InsertIdx != ThreeAtSignsIdx) {
InsertIdx += 2;
} else {
InsertIdx = Name.find("@");
if (InsertIdx != std::string::npos)
InsertIdx++;
}
} else {
Prefix = "#";
}
Name.insert(Name.begin() + InsertIdx, Prefix.begin(), Prefix.end());
return std::optional<std::string>(Name);
}
namespace AArch64CC {
// The CondCodes constants map directly to the 4-bit encoding of the condition

View file

@ -2781,10 +2781,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
AFI->setLRIsSpilled(SavedRegs.test(ARM::LR));
}
void ARMFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
TargetFrameLowering::processFunctionBeforeFrameFinalized(MF, RS);
void ARMFrameLowering::updateLRRestored(MachineFunction &MF) {
MachineFrameInfo &MFI = MF.getFrameInfo();
if (!MFI.isCalleeSavedInfoValid())
return;
@ -2808,6 +2805,12 @@ void ARMFrameLowering::processFunctionBeforeFrameFinalized(
}
}
void ARMFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
TargetFrameLowering::processFunctionBeforeFrameFinalized(MF, RS);
updateLRRestored(MF);
}
void ARMFrameLowering::getCalleeSaves(const MachineFunction &MF,
BitVector &SavedRegs) const {
TargetFrameLowering::getCalleeSaves(MF, SavedRegs);

View file

@ -59,6 +59,10 @@ class ARMFrameLowering : public TargetFrameLowering {
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS) const override;
/// Update the IsRestored flag on LR if it is spilled, based on the return
/// instructions.
static void updateLRRestored(MachineFunction &MF);
void processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS = nullptr) const override;

View file

@ -2062,17 +2062,6 @@ bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
MO.setReg(ARM::PC);
PrevMI.copyImplicitOps(*MBB.getParent(), *MBBI);
MBB.erase(MBBI);
// We now restore LR into PC so it is not live-out of the return block
// anymore: Clear the CSI Restored bit.
MachineFrameInfo &MFI = MBB.getParent()->getFrameInfo();
// CSI should be fixed after PrologEpilog Insertion
assert(MFI.isCalleeSavedInfoValid() && "CSI should be valid");
for (CalleeSavedInfo &Info : MFI.getCalleeSavedInfo()) {
if (Info.getReg() == ARM::LR) {
Info.setRestored(false);
break;
}
}
return true;
}
}
@ -2120,14 +2109,22 @@ bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
isThumb2 = AFI->isThumb2Function();
isThumb1 = AFI->isThumbFunction() && !isThumb2;
bool Modified = false;
bool Modified = false, ModifiedLDMReturn = false;
for (MachineBasicBlock &MBB : Fn) {
Modified |= LoadStoreMultipleOpti(MBB);
if (STI->hasV5TOps() && !AFI->shouldSignReturnAddress())
Modified |= MergeReturnIntoLDM(MBB);
ModifiedLDMReturn |= MergeReturnIntoLDM(MBB);
if (isThumb1)
Modified |= CombineMovBx(MBB);
}
Modified |= ModifiedLDMReturn;
// If we merged a BX instruction into an LDM, we need to re-calculate whether
// LR is restored. This check needs to consider the whole function, not just
// the instruction(s) we changed, because there may be other BX returns which
// still need LR to be restored.
if (ModifiedLDMReturn)
ARMFrameLowering::updateLRRestored(Fn);
Allocator.DestroyAll();
return Modified;

View file

@ -1398,7 +1398,7 @@ let mayLoad = 1, hasSideEffects = 0,
// Load indirect with displacement operations.
let canFoldAsLoad = 1, isReMaterializable = 1 in {
let Constraints = "@earlyclobber $reg" in def LDDRdPtrQ
def LDDRdPtrQ
: FSTDLDD<0,
(outs GPR8
: $reg),

View file

@ -2343,7 +2343,9 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(
LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
: (MaskIdx0 + MaskLen0 - 1),
DL, GRLenVT),
DAG.getConstant(MaskIdx0, DL, GRLenVT));
}
@ -4940,3 +4942,8 @@ bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
return !isa<ConstantSDNode>(Y);
}
ISD::NodeType LoongArchTargetLowering::getExtendForAtomicCmpSwapArg() const {
// TODO: LAMCAS will use amcas{_DB,}.[bhwd] which does not require extension.
return ISD::SIGN_EXTEND;
}

View file

@ -206,6 +206,8 @@ class LoongArchTargetLowering : public TargetLowering {
return ISD::SIGN_EXTEND;
}
ISD::NodeType getExtendForAtomicCmpSwapArg() const override;
Register getRegisterByName(const char *RegName, LLT VT,
const MachineFunction &MF) const override;
bool mayBeEmittedAsTailCall(const CallInst *CI) const override;

View file

@ -45,6 +45,11 @@ class LoongArchTargetMachine : public LLVMTargetMachine {
MachineFunctionInfo *
createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F,
const TargetSubtargetInfo *STI) const override;
// Addrspacecasts are always noops.
bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override {
return true;
}
};
} // end namespace llvm

View file

@ -1255,7 +1255,9 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
emitRRI(Mips::SD, GPReg, Mips::SP, RegOrOffset, SMLoc(), &STI);
}
if (getABI().IsN32()) {
#if 0
// We haven't support -mabicalls -mno-shared yet.
if (-mno-shared) {
MCSymbol *GPSym = MCA.getContext().getOrCreateSymbol("__gnu_local_gp");
const MipsMCExpr *HiExpr = MipsMCExpr::create(
MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(GPSym, MCA.getContext()),
@ -1273,6 +1275,7 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
return;
}
#endif
const MipsMCExpr *HiExpr = MipsMCExpr::createGpOff(
MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
@ -1288,8 +1291,11 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
emitRRX(Mips::ADDiu, GPReg, GPReg, MCOperand::createExpr(LoExpr), SMLoc(),
&STI);
// daddu $gp, $gp, $funcreg
emitRRR(Mips::DADDu, GPReg, GPReg, RegNo, SMLoc(), &STI);
// (d)addu $gp, $gp, $funcreg
if (getABI().IsN32())
emitRRR(Mips::ADDu, GPReg, GPReg, RegNo, SMLoc(), &STI);
else
emitRRR(Mips::DADDu, GPReg, GPReg, RegNo, SMLoc(), &STI);
}
void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation,

View file

@ -388,18 +388,32 @@ bool MipsExpandPseudo::expandAtomicBinOpSubword(
Opcode = Mips::XOR;
break;
case Mips::ATOMIC_LOAD_UMIN_I8_POSTRA:
IsUnsigned = true;
IsMin = true;
break;
case Mips::ATOMIC_LOAD_UMIN_I16_POSTRA:
IsUnsigned = true;
[[fallthrough]];
IsMin = true;
break;
case Mips::ATOMIC_LOAD_MIN_I8_POSTRA:
SEOp = Mips::SEB;
IsMin = true;
break;
case Mips::ATOMIC_LOAD_MIN_I16_POSTRA:
IsMin = true;
break;
case Mips::ATOMIC_LOAD_UMAX_I8_POSTRA:
IsUnsigned = true;
IsMax = true;
break;
case Mips::ATOMIC_LOAD_UMAX_I16_POSTRA:
IsUnsigned = true;
[[fallthrough]];
IsMax = true;
break;
case Mips::ATOMIC_LOAD_MAX_I8_POSTRA:
SEOp = Mips::SEB;
IsMax = true;
break;
case Mips::ATOMIC_LOAD_MAX_I16_POSTRA:
IsMax = true;
break;
@ -461,14 +475,42 @@ bool MipsExpandPseudo::expandAtomicBinOpSubword(
// For little endian we need to clear uninterested bits.
if (STI->isLittle()) {
// and OldVal, OldVal, Mask
// and Incr, Incr, Mask
BuildMI(loopMBB, DL, TII->get(Mips::AND), OldVal)
.addReg(OldVal)
.addReg(Mask);
BuildMI(loopMBB, DL, TII->get(Mips::AND), Incr).addReg(Incr).addReg(Mask);
if (!IsUnsigned) {
BuildMI(loopMBB, DL, TII->get(Mips::SRAV), OldVal)
.addReg(OldVal)
.addReg(ShiftAmnt);
BuildMI(loopMBB, DL, TII->get(Mips::SRAV), Incr)
.addReg(Incr)
.addReg(ShiftAmnt);
if (STI->hasMips32r2()) {
BuildMI(loopMBB, DL, TII->get(SEOp), OldVal).addReg(OldVal);
BuildMI(loopMBB, DL, TII->get(SEOp), Incr).addReg(Incr);
} else {
const unsigned ShiftImm = SEOp == Mips::SEH ? 16 : 24;
BuildMI(loopMBB, DL, TII->get(Mips::SLL), OldVal)
.addReg(OldVal, RegState::Kill)
.addImm(ShiftImm);
BuildMI(loopMBB, DL, TII->get(Mips::SRA), OldVal)
.addReg(OldVal, RegState::Kill)
.addImm(ShiftImm);
BuildMI(loopMBB, DL, TII->get(Mips::SLL), Incr)
.addReg(Incr, RegState::Kill)
.addImm(ShiftImm);
BuildMI(loopMBB, DL, TII->get(Mips::SRA), Incr)
.addReg(Incr, RegState::Kill)
.addImm(ShiftImm);
}
} else {
// and OldVal, OldVal, Mask
// and Incr, Incr, Mask
BuildMI(loopMBB, DL, TII->get(Mips::AND), OldVal)
.addReg(OldVal)
.addReg(Mask);
BuildMI(loopMBB, DL, TII->get(Mips::AND), Incr)
.addReg(Incr)
.addReg(Mask);
}
}
// unsigned: sltu Scratch4, oldVal, Incr
// signed: slt Scratch4, oldVal, Incr
BuildMI(loopMBB, DL, TII->get(SLTScratch4), Scratch4)

View file

@ -1191,12 +1191,6 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if ((Reg == PPC::X2 || Reg == PPC::R2) && MustSaveTOC)
continue;
// For SVR4, don't emit a move for the CR spill slot if we haven't
// spilled CRs.
if (isSVR4ABI && (PPC::CR2 <= Reg && Reg <= PPC::CR4)
&& !MustSaveCR)
continue;
// For 64-bit SVR4 when we have spilled CRs, the spill location
// is SP+8, not a frame-relative slot.
if (isSVR4ABI && isPPC64 && (PPC::CR2 <= Reg && Reg <= PPC::CR4)) {

View file

@ -14942,6 +14942,7 @@ SDValue PPCTargetLowering::combineFPToIntToFP(SDNode *N,
SDValue Ld = DAG.getMemIntrinsicNode(PPCISD::LXSIZX, dl,
DAG.getVTList(MVT::f64, MVT::Other),
Ops, MVT::i8, LDN->getMemOperand());
DAG.makeEquivalentMemoryOrdering(LDN, Ld);
// For signed conversion, we need to sign-extend the value in the VSR
if (Signed) {

View file

@ -3192,7 +3192,8 @@ static std::optional<uint64_t> getExactInteger(const APFloat &APF,
// Note that this method will also match potentially unappealing index
// sequences, like <i32 0, i32 50939494>, however it is left to the caller to
// determine whether this is worth generating code for.
static std::optional<VIDSequence> isSimpleVIDSequence(SDValue Op) {
static std::optional<VIDSequence> isSimpleVIDSequence(SDValue Op,
unsigned EltSizeInBits) {
unsigned NumElts = Op.getNumOperands();
assert(Op.getOpcode() == ISD::BUILD_VECTOR && "Unexpected BUILD_VECTOR");
bool IsInteger = Op.getValueType().isInteger();
@ -3200,7 +3201,7 @@ static std::optional<VIDSequence> isSimpleVIDSequence(SDValue Op) {
std::optional<unsigned> SeqStepDenom;
std::optional<int64_t> SeqStepNum, SeqAddend;
std::optional<std::pair<uint64_t, unsigned>> PrevElt;
unsigned EltSizeInBits = Op.getValueType().getScalarSizeInBits();
assert(EltSizeInBits >= Op.getValueType().getScalarSizeInBits());
for (unsigned Idx = 0; Idx < NumElts; Idx++) {
// Assume undef elements match the sequence; we just have to be careful
// when interpolating across them.
@ -3213,14 +3214,14 @@ static std::optional<VIDSequence> isSimpleVIDSequence(SDValue Op) {
if (!isa<ConstantSDNode>(Op.getOperand(Idx)))
return std::nullopt;
Val = Op.getConstantOperandVal(Idx) &
maskTrailingOnes<uint64_t>(EltSizeInBits);
maskTrailingOnes<uint64_t>(Op.getScalarValueSizeInBits());
} else {
// The BUILD_VECTOR must be all constants.
if (!isa<ConstantFPSDNode>(Op.getOperand(Idx)))
return std::nullopt;
if (auto ExactInteger = getExactInteger(
cast<ConstantFPSDNode>(Op.getOperand(Idx))->getValueAPF(),
EltSizeInBits))
Op.getScalarValueSizeInBits()))
Val = *ExactInteger;
else
return std::nullopt;
@ -3276,11 +3277,11 @@ static std::optional<VIDSequence> isSimpleVIDSequence(SDValue Op) {
uint64_t Val;
if (IsInteger) {
Val = Op.getConstantOperandVal(Idx) &
maskTrailingOnes<uint64_t>(EltSizeInBits);
maskTrailingOnes<uint64_t>(Op.getScalarValueSizeInBits());
} else {
Val = *getExactInteger(
cast<ConstantFPSDNode>(Op.getOperand(Idx))->getValueAPF(),
EltSizeInBits);
Op.getScalarValueSizeInBits());
}
uint64_t ExpectedVal =
(int64_t)(Idx * (uint64_t)*SeqStepNum) / *SeqStepDenom;
@ -3550,7 +3551,7 @@ static SDValue lowerBuildVectorOfConstants(SDValue Op, SelectionDAG &DAG,
// Try and match index sequences, which we can lower to the vid instruction
// with optional modifications. An all-undef vector is matched by
// getSplatValue, above.
if (auto SimpleVID = isSimpleVIDSequence(Op)) {
if (auto SimpleVID = isSimpleVIDSequence(Op, Op.getScalarValueSizeInBits())) {
int64_t StepNumerator = SimpleVID->StepNumerator;
unsigned StepDenominator = SimpleVID->StepDenominator;
int64_t Addend = SimpleVID->Addend;
@ -15562,7 +15563,10 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
if (Index.getOpcode() == ISD::BUILD_VECTOR &&
MGN->getExtensionType() == ISD::NON_EXTLOAD && isTypeLegal(VT)) {
if (std::optional<VIDSequence> SimpleVID = isSimpleVIDSequence(Index);
// The sequence will be XLenVT, not the type of Index. Tell
// isSimpleVIDSequence this so we avoid overflow.
if (std::optional<VIDSequence> SimpleVID =
isSimpleVIDSequence(Index, Subtarget.getXLen());
SimpleVID && SimpleVID->StepDenominator == 1) {
const int64_t StepNumerator = SimpleVID->StepNumerator;
const int64_t Addend = SimpleVID->Addend;

View file

@ -37,6 +37,9 @@ static cl::opt<unsigned> SLPMaxVF(
InstructionCost
RISCVTTIImpl::getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
TTI::TargetCostKind CostKind) {
// Check if the type is valid for all CostKind
if (!VT.isVector())
return InstructionCost::getInvalid();
size_t NumInstr = OpCodes.size();
if (CostKind == TTI::TCK_CodeSize)
return NumInstr;

View file

@ -4252,6 +4252,7 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
if (N->getValueType(0) == MVT::i128) {
unsigned BaseOp = 0;
unsigned FlagOp = 0;
bool IsBorrow = false;
switch (Op.getOpcode()) {
default: llvm_unreachable("Unknown instruction!");
case ISD::UADDO:
@ -4261,6 +4262,7 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
case ISD::USUBO:
BaseOp = ISD::SUB;
FlagOp = SystemZISD::VSCBI;
IsBorrow = true;
break;
}
SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS);
@ -4268,6 +4270,9 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op,
Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
DAG.getValueType(MVT::i1));
Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
if (IsBorrow)
Flag = DAG.getNode(ISD::XOR, DL, Flag.getValueType(),
Flag, DAG.getConstant(1, DL, Flag.getValueType()));
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
}
@ -4340,6 +4345,7 @@ SDValue SystemZTargetLowering::lowerUADDSUBO_CARRY(SDValue Op,
if (VT == MVT::i128) {
unsigned BaseOp = 0;
unsigned FlagOp = 0;
bool IsBorrow = false;
switch (Op.getOpcode()) {
default: llvm_unreachable("Unknown instruction!");
case ISD::UADDO_CARRY:
@ -4349,14 +4355,21 @@ SDValue SystemZTargetLowering::lowerUADDSUBO_CARRY(SDValue Op,
case ISD::USUBO_CARRY:
BaseOp = SystemZISD::VSBI;
FlagOp = SystemZISD::VSBCBI;
IsBorrow = true;
break;
}
if (IsBorrow)
Carry = DAG.getNode(ISD::XOR, DL, Carry.getValueType(),
Carry, DAG.getConstant(1, DL, Carry.getValueType()));
Carry = DAG.getZExtOrTrunc(Carry, DL, MVT::i128);
SDValue Result = DAG.getNode(BaseOp, DL, MVT::i128, LHS, RHS, Carry);
SDValue Flag = DAG.getNode(FlagOp, DL, MVT::i128, LHS, RHS, Carry);
Flag = DAG.getNode(ISD::AssertZext, DL, MVT::i128, Flag,
DAG.getValueType(MVT::i1));
Flag = DAG.getZExtOrTrunc(Flag, DL, N->getValueType(1));
if (IsBorrow)
Flag = DAG.getNode(ISD::XOR, DL, Flag.getValueType(),
Flag, DAG.getConstant(1, DL, Flag.getValueType()));
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Flag);
}
@ -6611,6 +6624,27 @@ SDValue SystemZTargetLowering::combineZERO_EXTEND(
return NewSelect;
}
}
// Convert (zext (xor (trunc X), C)) into (xor (trunc X), C') if the size
// of the result is smaller than the size of X and all the truncated bits
// of X are already zero.
if (N0.getOpcode() == ISD::XOR &&
N0.hasOneUse() && N0.getOperand(0).hasOneUse() &&
N0.getOperand(0).getOpcode() == ISD::TRUNCATE &&
N0.getOperand(1).getOpcode() == ISD::Constant) {
SDValue X = N0.getOperand(0).getOperand(0);
if (VT.isScalarInteger() && VT.getSizeInBits() < X.getValueSizeInBits()) {
KnownBits Known = DAG.computeKnownBits(X);
APInt TruncatedBits = APInt::getBitsSet(X.getValueSizeInBits(),
N0.getValueSizeInBits(),
VT.getSizeInBits());
if (TruncatedBits.isSubsetOf(Known.Zero)) {
X = DAG.getNode(ISD::TRUNCATE, SDLoc(X), VT, X);
APInt Mask = N0.getConstantOperandAPInt(1).zext(VT.getSizeInBits());
return DAG.getNode(ISD::XOR, SDLoc(N0), VT,
X, DAG.getConstant(Mask, SDLoc(N0), VT));
}
}
}
return SDValue();
}

View file

@ -47878,6 +47878,7 @@ static SDValue combineAndShuffleNot(SDNode *N, SelectionDAG &DAG,
SDValue X, Y;
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
if (SDValue Not = GetNot(N0)) {
X = Not;
@ -47891,9 +47892,11 @@ static SDValue combineAndShuffleNot(SDNode *N, SelectionDAG &DAG,
X = DAG.getBitcast(VT, X);
Y = DAG.getBitcast(VT, Y);
SDLoc DL(N);
// We do not split for SSE at all, but we need to split vectors for AVX1 and
// AVX2.
if (!Subtarget.useAVX512Regs() && VT.is512BitVector()) {
if (!Subtarget.useAVX512Regs() && VT.is512BitVector() &&
TLI.isTypeLegal(VT.getHalfNumVectorElementsVT(*DAG.getContext()))) {
SDValue LoX, HiX;
std::tie(LoX, HiX) = splitVector(X, DAG, DL);
SDValue LoY, HiY;
@ -47903,7 +47906,11 @@ static SDValue combineAndShuffleNot(SDNode *N, SelectionDAG &DAG,
SDValue HiV = DAG.getNode(X86ISD::ANDNP, DL, SplitVT, {HiX, HiY});
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, {LoV, HiV});
}
return DAG.getNode(X86ISD::ANDNP, DL, VT, {X, Y});
if (TLI.isTypeLegal(VT))
return DAG.getNode(X86ISD::ANDNP, DL, VT, {X, Y});
return SDValue();
}
// Try to widen AND, OR and XOR nodes to VT in order to remove casts around

View file

@ -83,6 +83,7 @@ defm : subvector_subreg_lowering<VR128, v2f64, VR256, v4f64, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8i16, VR256, v16i16, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v16i8, VR256, v32i8, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8f16, VR256, v16f16, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8bf16, VR256, v16bf16, sub_xmm>;
// A 128-bit subvector extract from the first 512-bit vector position is a
// subregister copy that needs no instruction. Likewise, a 128-bit subvector
@ -95,6 +96,7 @@ defm : subvector_subreg_lowering<VR128, v2f64, VR512, v8f64, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8i16, VR512, v32i16, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v16i8, VR512, v64i8, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8f16, VR512, v32f16, sub_xmm>;
defm : subvector_subreg_lowering<VR128, v8bf16, VR512, v32bf16, sub_xmm>;
// A 128-bit subvector extract from the first 512-bit vector position is a
// subregister copy that needs no instruction. Likewise, a 128-bit subvector
@ -107,6 +109,7 @@ defm : subvector_subreg_lowering<VR256, v4f64, VR512, v8f64, sub_ymm>;
defm : subvector_subreg_lowering<VR256, v16i16, VR512, v32i16, sub_ymm>;
defm : subvector_subreg_lowering<VR256, v32i8, VR512, v64i8, sub_ymm>;
defm : subvector_subreg_lowering<VR256, v16f16, VR512, v32f16, sub_ymm>;
defm : subvector_subreg_lowering<VR256, v16bf16, VR512, v32bf16, sub_ymm>;
// If we're inserting into an all zeros vector, just use a plain move which

View file

@ -6080,6 +6080,10 @@ bool X86TTIImpl::areInlineCompatible(const Function *Caller,
for (const Instruction &I : instructions(Callee)) {
if (const auto *CB = dyn_cast<CallBase>(&I)) {
// Having more target features is fine for inline ASM.
if (CB->isInlineAsm())
continue;
SmallVector<Type *, 8> Types;
for (Value *Arg : CB->args())
Types.push_back(Arg->getType());

View file

@ -652,10 +652,6 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
// check to see if the pointer is guaranteed to not be modified from entry of
// the function to each of the load instructions.
// Because there could be several/many load instructions, remember which
// blocks we know to be transparent to the load.
df_iterator_default_set<BasicBlock *, 16> TranspBlocks;
for (LoadInst *Load : Loads) {
// Check to see if the load is invalidated from the start of the block to
// the load itself.
@ -669,7 +665,7 @@ static bool findArgParts(Argument *Arg, const DataLayout &DL, AAResults &AAR,
// To do this, we perform a depth first search on the inverse CFG from the
// loading block.
for (BasicBlock *P : predecessors(BB)) {
for (BasicBlock *TranspBB : inverse_depth_first_ext(P, TranspBlocks))
for (BasicBlock *TranspBB : inverse_depth_first(P))
if (AAR.canBasicBlockModify(*TranspBB, Loc))
return false;
}

View file

@ -412,11 +412,14 @@ Instruction *InstCombinerImpl::simplifyMaskedScatter(IntrinsicInst &II) {
if (auto *SplatPtr = getSplatValue(II.getArgOperand(1))) {
// scatter(splat(value), splat(ptr), non-zero-mask) -> store value, ptr
if (auto *SplatValue = getSplatValue(II.getArgOperand(0))) {
Align Alignment = cast<ConstantInt>(II.getArgOperand(2))->getAlignValue();
StoreInst *S =
new StoreInst(SplatValue, SplatPtr, /*IsVolatile=*/false, Alignment);
S->copyMetadata(II);
return S;
if (maskContainsAllOneOrUndef(ConstMask)) {
Align Alignment =
cast<ConstantInt>(II.getArgOperand(2))->getAlignValue();
StoreInst *S = new StoreInst(SplatValue, SplatPtr, /*IsVolatile=*/false,
Alignment);
S->copyMetadata(II);
return S;
}
}
// scatter(vector, splat(ptr), splat(true)) -> store extract(vector,
// lastlane), ptr

View file

@ -2156,14 +2156,14 @@ static bool collectInsertionElements(Value *V, unsigned Shift,
Type *ElementIntTy = IntegerType::get(C->getContext(), ElementSize);
for (unsigned i = 0; i != NumElts; ++i) {
unsigned ShiftI = Shift + i * ElementSize;
unsigned ShiftI = i * ElementSize;
Constant *Piece = ConstantFoldBinaryInstruction(
Instruction::LShr, C, ConstantInt::get(C->getType(), ShiftI));
if (!Piece)
return false;
Piece = ConstantExpr::getTrunc(Piece, ElementIntTy);
if (!collectInsertionElements(Piece, ShiftI, Elements, VecEltTy,
if (!collectInsertionElements(Piece, ShiftI + Shift, Elements, VecEltTy,
isBigEndian))
return false;
}

View file

@ -6491,6 +6491,13 @@ InstCombiner::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred,
if (!SafeReplacementConstant)
SafeReplacementConstant = CI;
}
} else if (isa<VectorType>(C->getType())) {
// Handle scalable splat
Value *SplatC = C->getSplatValue();
auto *CI = dyn_cast_or_null<ConstantInt>(SplatC);
// Bail out if the constant can't be safely incremented/decremented.
if (!CI || !ConstantIsOk(CI))
return std::nullopt;
} else {
// ConstantExpr?
return std::nullopt;

View file

@ -1284,7 +1284,11 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT)) {
if (Value *V = simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
// Require either the replacement or the simplification result to be a
// constant to avoid infinite loops.
// FIXME: Make this check more precise.
if (isa<Constant>(CmpRHS) || isa<Constant>(V))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
// Even if TrueVal does not simplify, we can directly replace a use of
// CmpLHS with CmpRHS, as long as the instruction is not used anywhere
@ -1302,7 +1306,8 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
if (Value *V = simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
if (isa<Constant>(CmpLHS) || isa<Constant>(V))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
auto *FalseInst = dyn_cast<Instruction>(FalseVal);
if (!FalseInst)

View file

@ -1455,6 +1455,7 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, SelectInst *SI,
Value *NewOp, InstCombiner &IC) {
Instruction *Clone = I.clone();
Clone->replaceUsesOfWith(SI, NewOp);
Clone->dropUBImplyingAttrsAndMetadata();
IC.InsertNewInstBefore(Clone, SI->getIterator());
return Clone;
}

View file

@ -752,11 +752,12 @@ bool ThreadSanitizer::instrumentAtomic(Instruction *I, const DataLayout &DL) {
const unsigned ByteSize = 1U << Idx;
const unsigned BitSize = ByteSize * 8;
Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
Value *Args[] = {Addr,
IRB.CreateIntCast(RMWI->getValOperand(), Ty, false),
Value *Val = RMWI->getValOperand();
Value *Args[] = {Addr, IRB.CreateBitOrPointerCast(Val, Ty),
createOrdering(&IRB, RMWI->getOrdering())};
CallInst *C = CallInst::Create(F, Args);
ReplaceInstWithInst(I, C);
Value *C = IRB.CreateCall(F, Args);
I->replaceAllUsesWith(IRB.CreateBitOrPointerCast(C, Val->getType()));
I->eraseFromParent();
} else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
Value *Addr = CASI->getPointerOperand();
Type *OrigOldValTy = CASI->getNewValOperand()->getType();

View file

@ -857,6 +857,9 @@ struct DSEState {
// no longer be captured.
bool ShouldIterateEndOfFunctionDSE;
/// Dead instructions to be removed at the end of DSE.
SmallVector<Instruction *> ToRemove;
// Class contains self-reference, make sure it's not copied/moved.
DSEState(const DSEState &) = delete;
DSEState &operator=(const DSEState &) = delete;
@ -1692,7 +1695,8 @@ struct DSEState {
return {MaybeDeadAccess};
}
// Delete dead memory defs
/// Delete dead memory defs and recursively add their operands to ToRemove if
/// they became dead.
void deleteDeadInstruction(Instruction *SI) {
MemorySSAUpdater Updater(&MSSA);
SmallVector<Instruction *, 32> NowDeadInsts;
@ -1708,8 +1712,11 @@ struct DSEState {
salvageKnowledge(DeadInst);
// Remove the Instruction from MSSA.
if (MemoryAccess *MA = MSSA.getMemoryAccess(DeadInst)) {
if (MemoryDef *MD = dyn_cast<MemoryDef>(MA)) {
MemoryAccess *MA = MSSA.getMemoryAccess(DeadInst);
bool IsMemDef = MA && isa<MemoryDef>(MA);
if (MA) {
if (IsMemDef) {
auto *MD = cast<MemoryDef>(MA);
SkipStores.insert(MD);
if (auto *SI = dyn_cast<StoreInst>(MD->getMemoryInst())) {
if (SI->getValueOperand()->getType()->isPointerTy()) {
@ -1730,13 +1737,21 @@ struct DSEState {
// Remove its operands
for (Use &O : DeadInst->operands())
if (Instruction *OpI = dyn_cast<Instruction>(O)) {
O = nullptr;
O.set(PoisonValue::get(O->getType()));
if (isInstructionTriviallyDead(OpI, &TLI))
NowDeadInsts.push_back(OpI);
}
EI.removeInstruction(DeadInst);
DeadInst->eraseFromParent();
// Remove memory defs directly if they don't produce results, but only
// queue other dead instructions for later removal. They may have been
// used as memory locations that have been cached by BatchAA. Removing
// them here may lead to newly created instructions to be allocated at the
// same address, yielding stale cache entries.
if (IsMemDef && DeadInst->getType()->isVoidTy())
DeadInst->eraseFromParent();
else
ToRemove.push_back(DeadInst);
}
}
@ -2233,6 +2248,12 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
MadeChange |= State.eliminateRedundantStoresOfExistingValues();
MadeChange |= State.eliminateDeadWritesAtEndOfFunction();
while (!State.ToRemove.empty()) {
Instruction *DeadInst = State.ToRemove.pop_back_val();
DeadInst->eraseFromParent();
}
return MadeChange;
}
} // end anonymous namespace

View file

@ -2257,6 +2257,41 @@ checkVectorTypesForPromotion(Partition &P, const DataLayout &DL,
return nullptr;
}
static VectorType *createAndCheckVectorTypesForPromotion(
SetVector<Type *> &OtherTys, ArrayRef<VectorType *> CandidateTysCopy,
function_ref<void(Type *)> CheckCandidateType, Partition &P,
const DataLayout &DL, SmallVectorImpl<VectorType *> &CandidateTys,
bool &HaveCommonEltTy, Type *&CommonEltTy, bool &HaveVecPtrTy,
bool &HaveCommonVecPtrTy, VectorType *&CommonVecPtrTy) {
[[maybe_unused]] VectorType *OriginalElt =
CandidateTysCopy.size() ? CandidateTysCopy[0] : nullptr;
// Consider additional vector types where the element type size is a
// multiple of load/store element size.
for (Type *Ty : OtherTys) {
if (!VectorType::isValidElementType(Ty))
continue;
unsigned TypeSize = DL.getTypeSizeInBits(Ty).getFixedValue();
// Make a copy of CandidateTys and iterate through it, because we
// might append to CandidateTys in the loop.
for (VectorType *const VTy : CandidateTysCopy) {
// The elements in the copy should remain invariant throughout the loop
assert(CandidateTysCopy[0] == OriginalElt && "Different Element");
unsigned VectorSize = DL.getTypeSizeInBits(VTy).getFixedValue();
unsigned ElementSize =
DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
if (TypeSize != VectorSize && TypeSize != ElementSize &&
VectorSize % TypeSize == 0) {
VectorType *NewVTy = VectorType::get(Ty, VectorSize / TypeSize, false);
CheckCandidateType(NewVTy);
}
}
}
return checkVectorTypesForPromotion(P, DL, CandidateTys, HaveCommonEltTy,
CommonEltTy, HaveVecPtrTy,
HaveCommonVecPtrTy, CommonVecPtrTy);
}
/// Test whether the given alloca partitioning and range of slices can be
/// promoted to a vector.
///
@ -2271,6 +2306,7 @@ static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
// we have different element types.
SmallVector<VectorType *, 4> CandidateTys;
SetVector<Type *> LoadStoreTys;
SetVector<Type *> DeferredTys;
Type *CommonEltTy = nullptr;
VectorType *CommonVecPtrTy = nullptr;
bool HaveVecPtrTy = false;
@ -2314,42 +2350,32 @@ static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
Ty = SI->getValueOperand()->getType();
else
continue;
auto CandTy = Ty->getScalarType();
if (CandTy->isPointerTy() && (S.beginOffset() != P.beginOffset() ||
S.endOffset() != P.endOffset())) {
DeferredTys.insert(Ty);
continue;
}
LoadStoreTys.insert(Ty);
// Consider any loads or stores that are the exact size of the slice.
if (S.beginOffset() == P.beginOffset() && S.endOffset() == P.endOffset())
CheckCandidateType(Ty);
}
if (auto *VTy = checkVectorTypesForPromotion(
P, DL, CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
SmallVector<VectorType *, 4> CandidateTysCopy = CandidateTys;
if (auto *VTy = createAndCheckVectorTypesForPromotion(
LoadStoreTys, CandidateTysCopy, CheckCandidateType, P, DL,
CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
HaveCommonVecPtrTy, CommonVecPtrTy))
return VTy;
// Consider additional vector types where the element type size is a
// multiple of load/store element size.
for (Type *Ty : LoadStoreTys) {
if (!VectorType::isValidElementType(Ty))
continue;
unsigned TypeSize = DL.getTypeSizeInBits(Ty).getFixedValue();
// Make a copy of CandidateTys and iterate through it, because we might
// append to CandidateTys in the loop.
SmallVector<VectorType *, 4> CandidateTysCopy = CandidateTys;
CandidateTys.clear();
for (VectorType *&VTy : CandidateTysCopy) {
unsigned VectorSize = DL.getTypeSizeInBits(VTy).getFixedValue();
unsigned ElementSize =
DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
if (TypeSize != VectorSize && TypeSize != ElementSize &&
VectorSize % TypeSize == 0) {
VectorType *NewVTy = VectorType::get(Ty, VectorSize / TypeSize, false);
CheckCandidateType(NewVTy);
}
}
}
return checkVectorTypesForPromotion(P, DL, CandidateTys, HaveCommonEltTy,
CommonEltTy, HaveVecPtrTy,
HaveCommonVecPtrTy, CommonVecPtrTy);
CandidateTys.clear();
return createAndCheckVectorTypesForPromotion(
DeferredTys, CandidateTysCopy, CheckCandidateType, P, DL, CandidateTys,
HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
CommonVecPtrTy);
}
/// Test whether a slice of an alloca is valid for integer widening.

View file

@ -547,11 +547,6 @@ int main(int argc, char **argv) {
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
auto FOut = std::make_unique<formatted_raw_ostream>(*OS);
// FIXME: Workaround for bug in formatted_raw_ostream. Color escape codes
// are (incorrectly) written directly to the unbuffered raw_ostream wrapped
// by the formatted_raw_ostream.
if (Action == AC_CDisassemble)
FOut->SetUnbuffered();
Str.reset(
TheTarget->createAsmStreamer(Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP,

View file

@ -2032,13 +2032,6 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
formatted_raw_ostream FOS(outs());
// FIXME: Workaround for bug in formatted_raw_ostream. Color escape codes
// are (incorrectly) written directly to the unbuffered raw_ostream
// wrapped by the formatted_raw_ostream.
if (DisassemblyColor == ColorOutput::Enable ||
DisassemblyColor == ColorOutput::Auto)
FOS.SetUnbuffered();
std::unordered_map<uint64_t, std::string> AllLabels;
std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels;
if (SymbolizeOperands) {

View file

@ -45,8 +45,14 @@ void dumpCOFFImportFile(const COFFImportFile *File, ScopedPrinter &Writer) {
case COFF::IMPORT_NAME_UNDECORATE:
Writer.printString("Name type", "undecorate");
break;
case COFF::IMPORT_NAME_EXPORTAS:
Writer.printString("Name type", "export as");
break;
}
if (H->getNameType() != COFF::IMPORT_ORDINAL)
Writer.printString("Export name", File->getExportName());
for (const object::BasicSymbolRef &Sym : File->symbols()) {
raw_ostream &OS = Writer.startLine();
OS << "Symbol: ";

View file

@ -152,8 +152,7 @@ void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
<< "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n";
OS.indent(4) << " return false;\n";
OS.indent(2) << "}\n";
} else if (Predicate->isSubClassOf(
"FirstFusionPredicateWithMCInstPredicate")) {
} else if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
OS.indent(2) << "{\n";
OS.indent(4) << "const MachineInstr *MI = FirstMI;\n";
OS.indent(4) << "if (";
@ -173,7 +172,7 @@ void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate,
void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
PredicateExpander &PE,
raw_ostream &OS) {
if (Predicate->isSubClassOf("SecondFusionPredicateWithMCInstPredicate")) {
if (Predicate->isSubClassOf("FusionPredicateWithMCInstPredicate")) {
OS.indent(2) << "{\n";
OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n";
OS.indent(4) << "if (";
@ -185,7 +184,7 @@ void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate,
OS.indent(2) << "}\n";
} else {
PrintFatalError(Predicate->getLoc(),
"Unsupported predicate for first instruction: " +
"Unsupported predicate for second instruction: " +
Predicate->getType()->getAsString());
}
}
@ -196,9 +195,8 @@ void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate,
if (Predicate->isSubClassOf("FusionPredicateWithCode"))
OS << Predicate->getValueAsString("Predicate");
else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) {
Record *MCPred = Predicate->getValueAsDef("Predicate");
emitFirstPredicate(MCPred, PE, OS);
emitSecondPredicate(MCPred, PE, OS);
emitFirstPredicate(Predicate, PE, OS);
emitSecondPredicate(Predicate, PE, OS);
} else if (Predicate->isSubClassOf("TieReg")) {
int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx");
int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx");

View file

@ -818,6 +818,7 @@ class KMPAffinity {
typedef KMPAffinity::Mask kmp_affin_mask_t;
extern KMPAffinity *__kmp_affinity_dispatch;
#ifndef KMP_OS_AIX
class kmp_affinity_raii_t {
kmp_affin_mask_t *mask;
bool restored;
@ -842,6 +843,7 @@ class kmp_affinity_raii_t {
}
~kmp_affinity_raii_t() { restore(); }
};
#endif // !KMP_OS_AIX
// Declare local char buffers with this size for printing debug and info
// messages, using __kmp_affinity_print_mask().
@ -2506,7 +2508,7 @@ typedef struct kmp_depend_info {
union {
kmp_uint8 flag; // flag as an unsigned char
struct { // flag as a set of 8 bits
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
/* Same fields as in the #else branch, but in reverse order */
unsigned all : 1;
unsigned unused : 3;
@ -2671,7 +2673,7 @@ typedef struct kmp_task_stack {
#endif // BUILD_TIED_TASK_STACK
typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
/* Same fields as in the #else branch, but in reverse order */
#if OMPX_TASKGRAPH
unsigned reserved31 : 6;
@ -3911,7 +3913,7 @@ extern void __kmp_balanced_affinity(kmp_info_t *th, int team_size);
#if KMP_WEIGHTED_ITERATIONS_SUPPORTED
extern int __kmp_get_first_osid_with_ecore(void);
#endif
#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
extern int kmp_set_thread_affinity_mask_initial(void);
#endif
static inline void __kmp_assign_root_init_mask() {

View file

@ -2906,12 +2906,17 @@ static inline const char *__kmp_cpuinfo_get_envvar() {
}
// Parse /proc/cpuinfo (or an alternate file in the same format) to obtain the
// affinity map.
// affinity map. On AIX, the map is obtained through system SRAD (Scheduler
// Resource Allocation Domain).
static bool __kmp_affinity_create_cpuinfo_map(int *line,
kmp_i18n_id_t *const msg_id) {
*msg_id = kmp_i18n_null;
#if KMP_OS_AIX
unsigned num_records = __kmp_xproc;
#else
const char *filename = __kmp_cpuinfo_get_filename();
const char *envvar = __kmp_cpuinfo_get_envvar();
*msg_id = kmp_i18n_null;
if (__kmp_affinity.flags.verbose) {
KMP_INFORM(AffParseFilename, "KMP_AFFINITY", filename);
@ -2970,6 +2975,7 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
*msg_id = kmp_i18n_str_CantRewindCpuinfo;
return false;
}
#endif // KMP_OS_AIX
// Allocate the array of records to store the proc info in. The dummy
// element at the end makes the logic in filling them out easier to code.
@ -2999,6 +3005,99 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
INIT_PROC_INFO(threadInfo[i]);
}
#if KMP_OS_AIX
int smt_threads;
lpar_info_format1_t cpuinfo;
unsigned num_avail = __kmp_xproc;
if (__kmp_affinity.flags.verbose)
KMP_INFORM(AffParseFilename, "KMP_AFFINITY", "system info for topology");
// Get the number of SMT threads per core.
int retval =
lpar_get_info(LPAR_INFO_FORMAT1, &cpuinfo, sizeof(lpar_info_format1_t));
if (!retval)
smt_threads = cpuinfo.smt_threads;
else {
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Allocate a resource set containing available system resourses.
rsethandle_t sys_rset = rs_alloc(RS_SYSTEM);
if (sys_rset == NULL) {
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Allocate a resource set for the SRAD info.
rsethandle_t srad = rs_alloc(RS_EMPTY);
if (srad == NULL) {
rs_free(sys_rset);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Get the SRAD system detail level.
int sradsdl = rs_getinfo(NULL, R_SRADSDL, 0);
if (sradsdl < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Get the number of RADs at that SRAD SDL.
int num_rads = rs_numrads(sys_rset, sradsdl, 0);
if (num_rads < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Get the maximum number of procs that may be contained in a resource set.
int max_procs = rs_getinfo(NULL, R_MAXPROCS, 0);
if (max_procs < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
int cur_rad = 0;
int num_set = 0;
for (int srad_idx = 0; cur_rad < num_rads && srad_idx < VMI_MAXRADS;
++srad_idx) {
// Check if the SRAD is available in the RSET.
if (rs_getrad(sys_rset, srad, sradsdl, srad_idx, 0) < 0)
continue;
for (int cpu = 0; cpu < max_procs; cpu++) {
// Set the info for the cpu if it is in the SRAD.
if (rs_op(RS_TESTRESOURCE, srad, NULL, R_PROCS, cpu)) {
threadInfo[cpu][osIdIndex] = cpu;
threadInfo[cpu][pkgIdIndex] = cur_rad;
threadInfo[cpu][coreIdIndex] = cpu / smt_threads;
++num_set;
if (num_set >= num_avail) {
// Done if all available CPUs have been set.
break;
}
}
}
++cur_rad;
}
rs_free(sys_rset);
rs_free(srad);
// The topology is already sorted.
#else // !KMP_OS_AIX
unsigned num_avail = 0;
*line = 0;
#if KMP_ARCH_S390X
@ -3246,6 +3345,8 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
qsort(threadInfo, num_avail, sizeof(*threadInfo),
__kmp_affinity_cmp_ProcCpuInfo_phys_id);
#endif // KMP_OS_AIX
// The table is now sorted by pkgId / coreId / threadId, but we really don't
// know the radix of any of the fields. pkgId's may be sparsely assigned among
// the chips on a system. Although coreId's are usually assigned
@ -4441,7 +4542,7 @@ static bool __kmp_aux_affinity_initialize_topology(kmp_affinity_t &affinity) {
}
#endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
#if KMP_OS_LINUX
#if KMP_OS_LINUX || KMP_OS_AIX
if (!success) {
int line = 0;
success = __kmp_affinity_create_cpuinfo_map(&line, &msg_id);
@ -4837,7 +4938,12 @@ void __kmp_affinity_uninitialize(void) {
}
if (__kmp_affin_origMask != NULL) {
if (KMP_AFFINITY_CAPABLE()) {
#if KMP_OS_AIX
// Uninitialize by unbinding the thread.
bindprocessor(BINDTHREAD, thread_self(), PROCESSOR_CLASS_ANY);
#else
__kmp_set_system_affinity(__kmp_affin_origMask, FALSE);
#endif
}
KMP_CPU_FREE(__kmp_affin_origMask);
__kmp_affin_origMask = NULL;
@ -5011,7 +5117,10 @@ void __kmp_affinity_bind_init_mask(int gtid) {
__kmp_set_system_affinity(th->th.th_affin_mask, FALSE);
} else
#endif
#ifndef KMP_OS_AIX
// Do not set the full mask as the init mask on AIX.
__kmp_set_system_affinity(th->th.th_affin_mask, TRUE);
#endif
}
void __kmp_affinity_bind_place(int gtid) {
@ -5124,7 +5233,7 @@ int __kmp_aux_set_affinity(void **mask) {
int __kmp_aux_get_affinity(void **mask) {
int gtid;
int retval;
#if KMP_OS_WINDOWS || KMP_DEBUG
#if KMP_OS_WINDOWS || KMP_OS_AIX || KMP_DEBUG
kmp_info_t *th;
#endif
if (!KMP_AFFINITY_CAPABLE()) {
@ -5132,7 +5241,7 @@ int __kmp_aux_get_affinity(void **mask) {
}
gtid = __kmp_entry_gtid();
#if KMP_OS_WINDOWS || KMP_DEBUG
#if KMP_OS_WINDOWS || KMP_OS_AIX || KMP_DEBUG
th = __kmp_threads[gtid];
#else
(void)gtid; // unused variable
@ -5155,7 +5264,7 @@ int __kmp_aux_get_affinity(void **mask) {
}
}
#if !KMP_OS_WINDOWS
#if !KMP_OS_WINDOWS && !KMP_OS_AIX
retval = __kmp_get_system_affinity((kmp_affin_mask_t *)(*mask), FALSE);
KA_TRACE(
@ -5175,7 +5284,7 @@ int __kmp_aux_get_affinity(void **mask) {
KMP_CPU_COPY((kmp_affin_mask_t *)(*mask), th->th.th_affin_mask);
return 0;
#endif /* KMP_OS_WINDOWS */
#endif /* !KMP_OS_WINDOWS && !KMP_OS_AIX */
}
int __kmp_aux_get_affinity_max_proc() {
@ -5557,7 +5666,7 @@ void __kmp_balanced_affinity(kmp_info_t *th, int nthreads) {
}
}
#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
// We don't need this entry for Windows because
// there is GetProcessAffinityMask() api
//
@ -5592,7 +5701,11 @@ extern "C"
"set full mask for thread %d\n",
gtid));
KMP_DEBUG_ASSERT(__kmp_affin_fullMask != NULL);
#if KMP_OS_AIX
return bindprocessor(BINDTHREAD, thread_self(), PROCESSOR_CLASS_ANY);
#else
return __kmp_set_system_affinity(__kmp_affin_fullMask, FALSE);
#endif
}
#endif

View file

@ -191,7 +191,7 @@ class KMPHwlocAffinity : public KMPAffinity {
};
#endif /* KMP_USE_HWLOC */
#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
#if KMP_OS_LINUX
/* On some of the older OS's that we build on, these constants aren't present
in <asm/unistd.h> #included from <sys.syscall.h>. They must be the same on
@ -314,6 +314,10 @@ class KMPHwlocAffinity : public KMPAffinity {
#elif KMP_OS_FREEBSD
#include <pthread.h>
#include <pthread_np.h>
#elif KMP_OS_AIX
#include <sys/dr.h>
#include <sys/rset.h>
#define VMI_MAXRADS 64 // Maximum number of RADs allowed by AIX.
#endif
class KMPNativeAffinity : public KMPAffinity {
class Mask : public KMPAffinity::Mask {
@ -401,6 +405,70 @@ class KMPNativeAffinity : public KMPAffinity {
++retval;
return retval;
}
#if KMP_OS_AIX
// On AIX, we don't have a way to get CPU(s) a thread is bound to.
// This routine is only used to get the full mask.
int get_system_affinity(bool abort_on_error) override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal get affinity operation when not capable");
(void)abort_on_error;
// Set the mask with all CPUs that are available.
for (int i = 0; i < __kmp_xproc; ++i)
KMP_CPU_SET(i, this);
return 0;
}
int set_system_affinity(bool abort_on_error) const override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal set affinity operation when not capable");
int location;
int gtid = __kmp_entry_gtid();
int tid = thread_self();
// Unbind the thread if it was bound to any processors before so that
// we can bind the thread to CPUs specified by the mask not others.
int retval = bindprocessor(BINDTHREAD, tid, PROCESSOR_CLASS_ANY);
// On AIX, we can only bind to one instead of a set of CPUs with the
// bindprocessor() system call.
KMP_CPU_SET_ITERATE(location, this) {
if (KMP_CPU_ISSET(location, this)) {
retval = bindprocessor(BINDTHREAD, tid, location);
if (retval == -1 && errno == 1) {
rsid_t rsid;
rsethandle_t rsh;
// Put something in rsh to prevent compiler warning
// about uninitalized use
rsh = rs_alloc(RS_EMPTY);
rsid.at_pid = getpid();
if (RS_DEFAULT_RSET != ra_getrset(R_PROCESS, rsid, 0, rsh)) {
retval = ra_detachrset(R_PROCESS, rsid, 0);
retval = bindprocessor(BINDTHREAD, tid, location);
}
}
if (retval == 0) {
KA_TRACE(10, ("__kmp_set_system_affinity: Done binding "
"T#%d to cpu=%d.\n",
gtid, location));
continue;
}
int error = errno;
if (abort_on_error) {
__kmp_fatal(KMP_MSG(FunctionError, "bindprocessor()"),
KMP_ERR(error), __kmp_msg_null);
KA_TRACE(10, ("__kmp_set_system_affinity: Error binding "
"T#%d to cpu=%d, errno=%d.\n",
gtid, location, error));
return error;
}
}
}
return 0;
}
#else // !KMP_OS_AIX
int get_system_affinity(bool abort_on_error) override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal get affinity operation when not capable");
@ -443,6 +511,7 @@ class KMPNativeAffinity : public KMPAffinity {
}
return error;
}
#endif // KMP_OS_AIX
};
void determine_capable(const char *env_var) override {
__kmp_affinity_determine_capable(env_var);
@ -471,7 +540,7 @@ class KMPNativeAffinity : public KMPAffinity {
}
api_type get_api_type() const override { return NATIVE_OS; }
};
#endif /* KMP_OS_LINUX || KMP_OS_FREEBSD */
#endif /* KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX */
#if KMP_OS_WINDOWS
class KMPNativeAffinity : public KMPAffinity {

View file

@ -120,7 +120,8 @@ 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__
#if defined(__BYTE_ORDER__) && (__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

View file

@ -75,7 +75,8 @@
#error Unknown compiler
#endif
#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD) && !KMP_OS_WASI
#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD || KMP_OS_AIX) && \
!KMP_OS_WASI
#define KMP_AFFINITY_SUPPORTED 1
#if KMP_OS_WINDOWS && KMP_ARCH_X86_64
#define KMP_GROUP_AFFINITY 1

View file

@ -116,7 +116,7 @@ static void __kmp_print_cond(char *buffer, kmp_cond_align_t *cond) {
}
#endif
#if ((KMP_OS_LINUX || KMP_OS_FREEBSD) && KMP_AFFINITY_SUPPORTED)
#if ((KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX) && KMP_AFFINITY_SUPPORTED)
/* Affinity support */
@ -132,6 +132,29 @@ void __kmp_affinity_bind_thread(int which) {
KMP_CPU_FREE_FROM_STACK(mask);
}
#if KMP_OS_AIX
void __kmp_affinity_determine_capable(const char *env_var) {
// All versions of AIX support bindprocessor().
size_t mask_size = __kmp_xproc / CHAR_BIT;
// Round up to byte boundary.
if (__kmp_xproc % CHAR_BIT)
++mask_size;
// Round up to the mask_size_type boundary.
if (mask_size % sizeof(__kmp_affin_mask_size))
mask_size += sizeof(__kmp_affin_mask_size) -
mask_size % sizeof(__kmp_affin_mask_size);
KMP_AFFINITY_ENABLE(mask_size);
KA_TRACE(10,
("__kmp_affinity_determine_capable: "
"AIX OS affinity interface bindprocessor functional (mask size = "
"%" KMP_SIZE_T_SPEC ").\n",
__kmp_affin_mask_size));
}
#else // !KMP_OS_AIX
/* Determine if we can access affinity functionality on this version of
* Linux* OS by checking __NR_sched_{get,set}affinity system calls, and set
* __kmp_affin_mask_size to the appropriate value (0 means not capable). */
@ -259,8 +282,9 @@ void __kmp_affinity_determine_capable(const char *env_var) {
KMP_WARNING(AffCantGetMaskSize, env_var);
}
}
#endif // KMP_OS_LINUX && KMP_AFFINITY_SUPPORTED
#endif // KMP_OS_AIX
#endif // (KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX) &&
// KMP_AFFINITY_SUPPORTED
#if KMP_USE_FUTEX
@ -476,7 +500,7 @@ static void *__kmp_launch_worker(void *thr) {
#endif /* KMP_BLOCK_SIGNALS */
void *exit_val;
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_AIX
void *volatile padding = 0;
#endif
int gtid;
@ -525,7 +549,7 @@ static void *__kmp_launch_worker(void *thr) {
#endif /* KMP_BLOCK_SIGNALS */
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_AIX
if (__kmp_stkoffset > 0 && gtid > 0) {
padding = KMP_ALLOCA(gtid * __kmp_stkoffset);
(void)padding;
@ -1245,7 +1269,7 @@ static void __kmp_atfork_child(void) {
++__kmp_fork_count;
#if KMP_AFFINITY_SUPPORTED
#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
// reset the affinity in the child to the initial thread
// affinity in the parent
kmp_set_thread_affinity_mask_initial();
@ -2214,6 +2238,7 @@ int __kmp_is_address_mapped(void *addr) {
found = (int)addr < (__builtin_wasm_memory_size(0) * PAGESIZE);
#elif KMP_OS_DRAGONFLY || KMP_OS_SOLARIS || KMP_OS_AIX
(void)rc;
// FIXME(DragonFly, Solaris, AIX): Implement this
found = 1;

Some files were not shown because too many files have changed in this diff Show more