84 changes: 44 additions & 40 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ namespace {
/// contains enough information to determine where the runs break. Microsoft
/// and Itanium follow different rules and use different codepaths.
/// * It is desired that, when possible, bitfields use the appropriate iN type
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// i24. This isn't always possible because i24 has storage size of 32 bit
/// and if it is possible to use that extra byte of padding we must use
/// [i8 x 3] instead of i24. The function clipTailPadding does this.
/// and if it is possible to use that extra byte of padding we must use [i8 x
/// 3] instead of i24. This is computed when accumulating bitfields in
/// accumulateBitfields.
/// C++ examples that require clipping:
/// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3
/// struct A { int a : 24; ~A(); }; // a must be clipped because:
Expand All @@ -62,11 +63,7 @@ namespace {
/// that the tail padding is not used in the complete class.) However,
/// because LLVM reads from the complete type it can generate incorrect code
/// if we do not clip the tail padding off of the bitfield in the complete
/// layout. This introduces a somewhat awkward extra unnecessary clip stage.
/// The location of the clip is stored internally as a sentinel of type
/// SCISSOR. If LLVM were updated to read base types (which it probably
/// should because locations of things such as VBases are bogus in the llvm
/// type anyway) then we could eliminate the SCISSOR.
/// layout.
/// * Itanium allows nearly empty primary virtual bases. These bases don't get
/// get their own storage because they're laid out as part of another base
/// or at the beginning of the structure. Determining if a VBase actually
Expand Down Expand Up @@ -200,9 +197,7 @@ struct CGRecordLowering {
const CXXRecordDecl *Query) const;
void calculateZeroInit();
CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
/// Lowers bitfield storage types to I8 arrays for bitfields with tail
/// padding that is or can potentially be used.
void clipTailPadding();
void checkBitfieldClipping() const;
/// Determines if we need a packed llvm struct.
void determinePacked(bool NVBaseType);
/// Inserts padding everywhere it's needed.
Expand Down Expand Up @@ -305,7 +300,7 @@ void CGRecordLowering::lower(bool NVBaseType) {
}
llvm::stable_sort(Members);
Members.push_back(StorageInfo(Size, getIntNType(8)));
clipTailPadding();
checkBitfieldClipping();
determinePacked(NVBaseType);
insertPadding();
Members.pop_back();
Expand Down Expand Up @@ -531,6 +526,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// available padding characters.
RecordDecl::field_iterator BestEnd = Begin;
CharUnits BestEndOffset;
bool BestClipped; // Whether the representation must be in a byte array.

for (;;) {
// AtAlignedBoundary is true iff Field is the (potential) start of a new
Expand Down Expand Up @@ -593,10 +589,9 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// this is the best seen so far.
BestEnd = Field;
BestEndOffset = BeginOffset + AccessSize;
if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else if (!BitSizeSinceBegin)
// Assume clipped until proven not below.
BestClipped = true;
if (!BitSizeSinceBegin)
// A zero-sized initial span -- this will install nothing and reset
// for another.
InstallBest = true;
Expand Down Expand Up @@ -624,6 +619,12 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// The access unit is not at a naturally aligned offset within the
// structure.
InstallBest = true;

if (InstallBest && BestEnd == Field)
// We're installing the first span, whose clipping was presumed
// above. Compute it correctly.
if (getSize(Type) == AccessSize)
BestClipped = false;
}

if (!InstallBest) {
Expand Down Expand Up @@ -656,11 +657,15 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// access unit.
BestEndOffset = BeginOffset + TypeSize;
BestEnd = Field;
BestClipped = false;
}

if (Barrier)
// The next field is a barrier that we cannot merge across.
InstallBest = true;
else if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else
// Otherwise, we're not installing. Update the bit size
// of the current span to go all the way to LimitOffset, which is
Expand All @@ -679,7 +684,17 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// Add the storage member for the access unit to the record. The
// bitfields get the offset of their storage but come afterward and
// remain there after a stable sort.
llvm::Type *Type = getIntNType(Context.toBits(AccessSize));
llvm::Type *Type;
if (BestClipped) {
assert(getSize(getIntNType(Context.toBits(AccessSize))) >
AccessSize &&
"Clipped access need not be clipped");
Type = getByteArrayType(AccessSize);
} else {
Type = getIntNType(Context.toBits(AccessSize));
assert(getSize(Type) == AccessSize &&
"Unclipped access must be clipped");
}
Members.push_back(StorageInfo(BeginOffset, Type));
for (; Begin != BestEnd; ++Begin)
if (!Begin->isZeroLengthBitField(Context))
Expand Down Expand Up @@ -934,32 +949,21 @@ void CGRecordLowering::calculateZeroInit() {
}
}

void CGRecordLowering::clipTailPadding() {
std::vector<MemberInfo>::iterator Prior = Members.begin();
CharUnits Tail = getSize(Prior->Data);
for (std::vector<MemberInfo>::iterator Member = Prior + 1,
MemberEnd = Members.end();
Member != MemberEnd; ++Member) {
// Verify accumulateBitfields computed the correct storage representations.
void CGRecordLowering::checkBitfieldClipping() const {
#ifndef NDEBUG
auto Tail = CharUnits::Zero();
for (const auto &M : Members) {
// Only members with data and the scissor can cut into tail padding.
if (!Member->Data && Member->Kind != MemberInfo::Scissor)
if (!M.Data && M.Kind != MemberInfo::Scissor)
continue;
if (Member->Offset < Tail) {
assert(Prior->Kind == MemberInfo::Field &&
"Only storage fields have tail padding!");
if (!Prior->FD || Prior->FD->isBitField())
Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
else {
assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() &&
"should not have reused this field's tail padding");
Prior->Data = getByteArrayType(
Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).Width);
}
}
if (Member->Data)
Prior = Member;
Tail = Prior->Offset + getSize(Prior->Data);

assert(M.Offset >= Tail && "Bitfield access unit is not clipped");
Tail = M.Offset;
if (M.Data)
Tail += getSize(M.Data);
}
#endif
}

void CGRecordLowering::determinePacked(bool NVBaseType) {
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3952,9 +3952,20 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
// behavior may break ABI compatibility of the current unit.
if (const Module *M = F->getOwningModule();
M && M->getTopLevelModule()->isNamedModule() &&
getContext().getCurrentNamedModule() != M->getTopLevelModule() &&
!F->hasAttr<AlwaysInlineAttr>())
return false;
getContext().getCurrentNamedModule() != M->getTopLevelModule()) {
// There are practices to mark template member function as always-inline
// and mark the template as extern explicit instantiation but not give
// the definition for member function. So we have to emit the function
// from explicitly instantiation with always-inline.
//
// See https://github.com/llvm/llvm-project/issues/86893 for details.
//
// TODO: Maybe it is better to give it a warning if we call a non-inline
// function from other module units which is marked as always-inline.
if (!F->isTemplateInstantiation() || !F->hasAttr<AlwaysInlineAttr>()) {
return false;
}
}

if (F->hasAttr<NoInlineAttr>())
return false;
Expand Down
4 changes: 0 additions & 4 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2380,10 +2380,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
if (getLangOpts().CPlusPlus23) {
auto &LastRecord = Actions.ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;

// Materialize non-`cv void` prvalue temporaries in discarded
// expressions. These materialized temporaries may be lifetime-extented.
LastRecord.InMaterializeTemporaryObjectContext = true;
}

if (getLangOpts().OpenMP)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Core
Demangle
FrontendHLSL
FrontendOpenMP
MC
Expand Down
44 changes: 33 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/Error.h"
Expand Down Expand Up @@ -1983,6 +1984,36 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}

// Mark alias/ifunc target as used. Due to name mangling, we look up the
// demangled name ignoring parameters (not supported by microsoftDemangle
// https://github.com/llvm/llvm-project/issues/88825). This should handle the
// majority of use cases while leaving namespace scope names unmarked.
static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL,
StringRef Str) {
std::unique_ptr<char, llvm::FreeDeleter> Demangled;
if (S.getASTContext().getCXXABIKind() != TargetCXXABI::Microsoft)
Demangled.reset(llvm::itaniumDemangle(Str, /*ParseParams=*/false));
std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
SmallString<256> Name;

const DeclarationNameInfo Target(
&S.Context.Idents.get(Demangled ? Demangled.get() : Str), AL.getLoc());
LookupResult LR(S, Target, Sema::LookupOrdinaryName);
if (S.LookupName(LR, S.TUScope)) {
for (NamedDecl *ND : LR) {
if (MC->shouldMangleDeclName(ND)) {
llvm::raw_svector_ostream Out(Name);
Name.clear();
MC->mangleName(GlobalDecl(ND), Out);
} else {
Name = ND->getIdentifier()->getName();
}
if (Name == Str)
ND->markUsed(S.Context);
}
}
}

static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
Expand All @@ -1995,6 +2026,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}

Expand Down Expand Up @@ -2029,17 +2061,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

// Mark target used to prevent unneeded-internal-declaration warnings.
if (!S.LangOpts.CPlusPlus) {
// FIXME: demangle Str for C++, as the attribute refers to the mangled
// linkage name, not the pre-mangled identifier.
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
LookupResult LR(S, target, Sema::LookupOrdinaryName);
if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
for (NamedDecl *ND : LR)
ND->markUsed(S.Context);
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6314,7 +6314,6 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// Pass down lifetime extending flag, and collect temporaries in
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
keepInLifetimeExtendingContext();
keepInMaterializeTemporaryObjectContext();
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(CallLoc, [&] {
Expand Down Expand Up @@ -7740,7 +7739,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}

if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
if (Method->isImplicitObjectMemberFunction())
if (!isa<RequiresExprBodyDecl>(CurContext) &&
Method->isImplicitObjectMemberFunction())
return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
<< Fn->getSourceRange() << 0);

Expand Down Expand Up @@ -18679,9 +18679,9 @@ void Sema::PopExpressionEvaluationContext() {
// Append the collected materialized temporaries into previous context before
// exit if the previous also is a lifetime extending context.
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
if (getLangOpts().CPlusPlus23 && isInLifetimeExtendingContext() &&
PrevRecord.InLifetimeExtendingContext && !ExprEvalContexts.empty()) {
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext &&
PrevRecord.InLifetimeExtendingContext &&
!Rec.ForRangeLifetimeExtendTemps.empty()) {
PrevRecord.ForRangeLifetimeExtendTemps.append(
Rec.ForRangeLifetimeExtendTemps);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8429,7 +8429,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// unnecessary temporary objects. If we skip this step, IR generation is
// able to synthesize the storage for itself in the aggregate case, and
// adding the extra node to the AST is just clutter.
if (isInMaterializeTemporaryObjectContext() && getLangOpts().CPlusPlus17 &&
if (isInLifetimeExtendingContext() && getLangOpts().CPlusPlus17 &&
E->isPRValue() && !E->getType()->isVoidType()) {
ExprResult Res = TemporaryMaterializationConversion(E);
if (Res.isInvalid())
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14395,9 +14395,16 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
ArrayRef<Expr *> ArgsArray(Args, NumArgs);

if (Input->isTypeDependent()) {
ExprValueKind VK = ExprValueKind::VK_PRValue;
// [C++26][expr.unary.op][expr.pre.incr]
// The * operator yields an lvalue of type
// The pre/post increment operators yied an lvalue.
if (Opc == UO_PreDec || Opc == UO_PreInc || Opc == UO_Deref)
VK = VK_LValue;

if (Fns.empty())
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
VK_PRValue, OK_Ordinary, OpLoc, false,
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, VK,
OK_Ordinary, OpLoc, false,
CurFPFeatureOverrides());

CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
Expand All @@ -14406,7 +14413,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (Fn.isInvalid())
return ExprError();
return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), ArgsArray,
Context.DependentTy, VK_PRValue, OpLoc,
Context.DependentTy, VK, OpLoc,
CurFPFeatureOverrides());
}

Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5483,7 +5483,6 @@ void Sema::InstantiateVariableInitializer(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);

keepInLifetimeExtendingContext();
keepInMaterializeTemporaryObjectContext();
// Instantiate the initializer.
ExprResult Init;

Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -4177,7 +4177,6 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
getSema(), EnterExpressionEvaluationContext::InitList,
Construct->isListInitialization());

getSema().keepInLifetimeExtendingContext();
getSema().keepInLifetimeExtendingContext();
SmallVector<Expr*, 8> NewArgs;
bool ArgChanged = false;
Expand Down Expand Up @@ -8752,10 +8751,6 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
if (getSema().getLangOpts().CPlusPlus23) {
auto &LastRecord = getSema().ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;

// Materialize non-`cv void` prvalue temporaries in discarded
// expressions. These materialized temporaries may be lifetime-extented.
LastRecord.InMaterializeTemporaryObjectContext = true;
}
StmtResult Init =
S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult();
Expand Down
36 changes: 24 additions & 12 deletions clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,26 @@ void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
}
}

void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
const LangOptions &LangOpts,
CodeGenOptions &CGOpts) {
// TODO: Figure out better way to set options to their default value.
if (ProgramAction == frontend::GenerateModule) {
CGOpts.MainFileName.clear();
CGOpts.DwarfDebugFlags.clear();
}
if (ProgramAction == frontend::GeneratePCH ||
(ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
CGOpts.DebugCompilationDir.clear();
CGOpts.CoverageCompilationDir.clear();
CGOpts.CoverageDataFile.clear();
CGOpts.CoverageNotesFile.clear();
CGOpts.ProfileInstrumentUsePath.clear();
CGOpts.SampleProfileFile.clear();
CGOpts.ProfileRemappingFile.clear();
}
}

static CowCompilerInvocation
makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
CI.resetNonModularOptions();
Expand All @@ -167,18 +187,8 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
// LLVM options are not going to affect the AST
CI.getFrontendOpts().LLVMArgs.clear();

// TODO: Figure out better way to set options to their default value.
CI.getCodeGenOpts().MainFileName.clear();
CI.getCodeGenOpts().DwarfDebugFlags.clear();
if (!CI.getLangOpts().ModulesCodegen) {
CI.getCodeGenOpts().DebugCompilationDir.clear();
CI.getCodeGenOpts().CoverageCompilationDir.clear();
CI.getCodeGenOpts().CoverageDataFile.clear();
CI.getCodeGenOpts().CoverageNotesFile.clear();
CI.getCodeGenOpts().ProfileInstrumentUsePath.clear();
CI.getCodeGenOpts().SampleProfileFile.clear();
CI.getCodeGenOpts().ProfileRemappingFile.clear();
}
resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(),
CI.getCodeGenOpts());

// Map output paths that affect behaviour to "-" so their existence is in the
// context hash. The final path will be computed in addOutputPaths.
Expand Down Expand Up @@ -342,6 +352,8 @@ static bool needsModules(FrontendInputFile FIF) {

void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
CI.clearImplicitModuleBuildOptions();
resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction,
CI.getLangOpts(), CI.getCodeGenOpts());

if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
Preprocessor &PP = ScanInstance.getPreprocessor();
Expand Down
1 change: 1 addition & 0 deletions clang/test/AST/ast-dump-attr-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ __thread __attribute__ ((tls_model ("local-exec"))) int tls_model_var;
// CHECK-NEXT: "tokLen": 11
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isUsed": true,
// CHECK-NEXT: "name": "global_decl",
// CHECK-NEXT: "mangledName": "global_decl",
// CHECK-NEXT: "type": {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/over/over.built/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ struct A{};

template <typename T, typename U>
auto Test(T* pt, U* pu) {
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '*'
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)*pt;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '++'
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(++pt);

Expand Down
28 changes: 28 additions & 0 deletions clang/test/ClangScanDeps/removed-args.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,31 @@
// CHECK-NOT: "-fmodules-prune-interval=
// CHECK-NOT: "-fmodules-prune-after=
// CHECK: ],

// Check for removed args for PCH invocations.

// RUN: split-file %s %t
// RUN: sed "s|DIR|%/t|g" %t/cdb-pch.json.template > %t/cdb-pch.json
// RUN: clang-scan-deps -compilation-database %t/cdb-pch.json -format experimental-full > %t/result-pch.json
// RUN: cat %t/result-pch.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t -check-prefix=PCH
//
// PCH-NOT: "-fdebug-compilation-dir="
// PCH-NOT: "-fcoverage-compilation-dir="
// PCH-NOT: "-coverage-notes-file
// PCH-NOT: "-coverage-data-file
// PCH-NOT: "-fprofile-instrument-use-path
// PCH-NOT: "-include"
// PCH-NOT: "-fmodules-cache-path=
// PCH-NOT: "-fmodules-validate-once-per-build-session"
// PCH-NOT: "-fbuild-session-timestamp=
// PCH-NOT: "-fmodules-prune-interval=
// PCH-NOT: "-fmodules-prune-after=

//--- cdb-pch.json.template
[
{
"directory": "DIR",
"command": "clang -x c-header DIR/header.h -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -fdebug-compilation-dir=DIR/debug -fcoverage-compilation-dir=DIR/coverage -ftest-coverage -fprofile-instr-use=DIR/tu.profdata -o DIR/header.h.pch -serialize-diagnostics DIR/header.h.pch.diag ",
"file": "DIR/header.h.pch"
}
]
18 changes: 18 additions & 0 deletions clang/test/CodeGen/bitfield-access-unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,24 @@ struct G {
// LAYOUT-DWN32-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:7 IsSigned:1 StorageSize:8 StorageOffset:4
// CHECK-NEXT: ]>

struct __attribute__((aligned(8))) H {
char a;
unsigned b : 24; // on expensive alignment we want this to stay 24
unsigned c __attribute__((aligned(8))); // Think 'long long' or lp64 ptr
} h;
// CHECK-LABEL: LLVMType:%struct.H =
// LAYOUT-FLEX-SAME: type <{ i8, i32, [3 x i8], i32, [4 x i8] }>
// LAYOUT-STRICT-SAME: type { i8, [3 x i8], [4 x i8], i32, [4 x i8] }
// LAYOUT-DWN32-FLEX-SAME: type <{ i8, i32, [3 x i8], i32, [4 x i8] }>
// LAYOUT-DWN32-STRICT-SAME: type { i8, [3 x i8], [4 x i8], i32, [4 x i8] }
// CHECK: BitFields:[
// LAYOUT-FLEX-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:32 StorageOffset:1
// LAYOUT-STRICT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:24 StorageOffset:1

// LAYOUT-DWN32-FLEX-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:32 StorageOffset:1
// LAYOUT-DWN32-STRICT-NEXT: <CGBitFieldInfo Offset:{{[0-9]+}} Size:24 IsSigned:0 StorageSize:24 StorageOffset:1
// CHECK-NEXT: ]>

#if _LP64
struct A64 {
int a : 16;
Expand Down
31 changes: 30 additions & 1 deletion clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 --std=c++20 -fexceptions -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=EH %s
// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=NOEH,CHECK %s

struct Printy {
Printy(const char *name) : name(name) {}
Expand Down Expand Up @@ -349,6 +350,34 @@ void NewArrayInit() {
// CHECK-NEXT: br label %return
}

void DestroyInConditionalCleanup() {
// EH-LABEL: DestroyInConditionalCleanupv()
// NOEH-LABEL: DestroyInConditionalCleanupv()
struct A {
A() {}
~A() {}
};

struct Value {
Value(A) {}
~Value() {}
};

struct V2 {
Value K;
Value V;
};
// Verify we use conditional cleanups.
(void)(foo() ? V2{A(), A()} : V2{A(), A()});
// NOEH: cond.true:
// NOEH: call void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
// NOEH: store ptr %{{.*}}, ptr %cond-cleanup.save

// EH: cond.true:
// EH: invoke void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev
// EH: store ptr %{{.*}}, ptr %cond-cleanup.save
}

void ArrayInitWithContinue() {
// CHECK-LABEL: @_Z21ArrayInitWithContinuev
// Verify that we start to emit the array destructor.
Expand Down
31 changes: 26 additions & 5 deletions clang/test/CodeGenCXX/module-funcs-from-imports.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ int func_in_gmf_not_called() {
return 44;
}

template <class T>
class A {
public:
__attribute__((always_inline))
inline constexpr int getValue() {
return 43;
}

inline constexpr int getValue2() {
return 43;
}
};

extern template class A<char>;

//--- M.cppm
module;
#include "foo.h"
Expand All @@ -47,17 +62,21 @@ int always_inline_func() {
return 45;
}

export using ::A;

//--- Use.cpp
import M;
int use() {
return exported_func() + always_inline_func();
A<char> a;
return exported_func() + always_inline_func() +
a.getValue() + a.getValue2();
}

// Checks that none of the function (except the always_inline_func) in the importees
// are generated in the importer's code.
// CHECK-O0: define{{.*}}_Z3usev(
// CHECK-O0: declare{{.*}}_ZW1M13exported_funcv(
// CHECK-O0: define{{.*}}available_externally{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O0: declare{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O0: define{{.*}}@_ZN1AIcE8getValueEv(
// CHECK-O0: declare{{.*}}@_ZN1AIcE9getValue2Ev(
// CHECK-O0-NOT: func_in_gmf
// CHECK-O0-NOT: func_in_gmf_not_called
// CHECK-O0-NOT: non_exported_func
Expand All @@ -68,7 +87,9 @@ int use() {
// O0 to keep consistent ABI.
// CHECK-O1: define{{.*}}_Z3usev(
// CHECK-O1: declare{{.*}}_ZW1M13exported_funcv(
// CHECK-O1: define{{.*}}available_externally{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O1: declare{{.*}}_ZW1M18always_inline_funcv(
// CHECK-O1: define{{.*}}@_ZN1AIcE8getValueEv(
// CHECK-O1: declare{{.*}}@_ZN1AIcE9getValue2Ev(
// CHECK-O1-NOT: func_in_gmf
// CHECK-O1-NOT: func_in_gmf_not_called
// CHECK-O1-NOT: non_exported_func
Expand Down
3 changes: 1 addition & 2 deletions clang/test/OpenMP/ompx_attributes_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ void func() {
// NVIDIA: "omp_target_thread_limit"="45"
// NVIDIA: "omp_target_thread_limit"="17"
// NVIDIA: !{ptr @__omp_offloading[[HASH1:.*]]_l16, !"maxntidx", i32 20}
// NVIDIA: !{ptr @__omp_offloading[[HASH2:.*]]_l18, !"minctasm", i32 90}
// NVIDIA: !{ptr @__omp_offloading[[HASH2]]_l18, !"maxntidx", i32 45}
// NVIDIA: !{ptr @__omp_offloading[[HASH2:.*]]_l18, !"maxntidx", i32 45}
// NVIDIA: !{ptr @__omp_offloading[[HASH3:.*]]_l20, !"maxntidx", i32 17}
2 changes: 1 addition & 1 deletion clang/test/Sema/alias-unused-win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern "C" {
static int f(void) { return 42; } // cxx-warning{{unused function 'f'}}
int g(void) __attribute__((alias("f")));

static int foo [] = { 42, 0xDEAD }; // cxx-warning{{variable 'foo' is not needed and will not be emitted}}
static int foo [] = { 42, 0xDEAD };
extern typeof(foo) bar __attribute__((unused, alias("foo")));

static int __attribute__((overloadable)) f0(int x) { return x; } // expected-warning{{unused function 'f0'}}
Expand Down
16 changes: 9 additions & 7 deletions clang/test/Sema/alias-unused.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@ extern typeof(foo) bar __attribute__((unused, alias("foo")));
/// We report a warning in C++ mode because the internal linkage `resolver` gets
/// mangled as it does not have a language linkage. GCC does not mangle
/// `resolver` or report a warning.
static int (*resolver(void))(void) { return f; } // expected-warning{{unused function 'resolver'}}
static int (*resolver(void))(void) { return f; } // cxx-warning{{unused function 'resolver'}}
int ifunc(void) __attribute__((ifunc("resolver")));

static int __attribute__((overloadable)) f0(int x) { return x; } // expected-warning{{unused function 'f0'}}
static int __attribute__((overloadable)) f0(int x) { return x; }
static float __attribute__((overloadable)) f0(float x) { return x; } // expected-warning{{unused function 'f0'}}
int g0(void) __attribute__((alias("_ZL2f0i")));

#ifdef __cplusplus
static int f1() { return 42; } // expected-warning{{unused function 'f1'}}
static int f1() { return 42; }
int g1(void) __attribute__((alias("_ZL2f1v")));
}

static int f2(int) { return 42; } // expected-warning{{unused function 'f2'}}
static int f2() { return 42; } // expected-warning{{unused function 'f2'}}
/// We demangle alias/ifunc target and mark all found functions as used.

static int f2(int) { return 42; } // cxx-warning{{unused function 'f2'}}
static int f2() { return 42; }
int g2() __attribute__((alias("_ZL2f2v")));

static int (*resolver1())() { return f; } // expected-warning{{unused function 'resolver1'}}
static int (*resolver1(int))() { return f; } // expected-warning{{unused function 'resolver1'}}
static int (*resolver1())() { return f; } // cxx-warning{{unused function 'resolver1'}}
static int (*resolver1(int))() { return f; }
int ifunc1() __attribute__((ifunc("_ZL9resolver1i")));

/// TODO: We should report "unused function" for f3(int).
Expand Down
23 changes: 23 additions & 0 deletions clang/test/SemaCXX/PR84020.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// RUN: %clang_cc1 -std=c++23 -verify %s
// expected-no-diagnostics

struct B {
template <typename S>
void foo();

void bar();
};

template <typename T, typename S>
struct A : T {
auto foo() {
static_assert(requires { T::template foo<S>(); });
static_assert(requires { T::bar(); });
}
};

int main() {
A<B, double> a;
a.foo();
}
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/overloaded-operator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -682,3 +682,13 @@ namespace nw{
}
}
#endif

#if __cplusplus >= 201703L
namespace GH88329 {

template <auto T> struct A {};
template <auto T> A<*T> operator *() { return {}; }
// expected-error@-1 {{overloaded 'operator*' must have at least one parameter of class or enumeration type}}
}

#endif
30 changes: 0 additions & 30 deletions clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,36 +977,6 @@ TEST(ExprMutationAnalyzerTest, FollowFuncArgModified) {
"void f() { int x; g(x); }");
Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));

AST = buildASTFromCode(
StdRemoveReference + StdForward +
"template <class T> void f1(T &&a);"
"template <class T> void f2(T &&a);"
"template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); }"
"template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); }"
"void f() { int x; f1(x); }");
Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_FALSE(isMutated(Results, AST.get()));

AST = buildASTFromCode(
StdRemoveReference + StdForward +
"template <class T> void f1(T &&a);"
"template <class T> void f2(T &&a);"
"template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); }"
"template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); a++; }"
"void f() { int x; f1(x); }");
Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f1(x)"));

AST = buildASTFromCode(
StdRemoveReference + StdForward +
"template <class T> void f1(T &&a);"
"template <class T> void f2(T &&a);"
"template <class T> void f1(T &&a) { f2<T>(std::forward<T>(a)); a++; }"
"template <class T> void f2(T &&a) { f1<T>(std::forward<T>(a)); }"
"void f() { int x; f1(x); }");
Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("f1(x)"));
}

TEST(ExprMutationAnalyzerTest, FollowFuncArgNotModified) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// RUN: %clangxx %s -pie -fPIE -o %t && %run %t
// RUN: %clang %s -pie -fPIE -o %t && %run %t
// REQUIRES: x86_64-target-arch

// FIXME: Fails Asan, as expected, with 5lvl page tables.
// UNSUPPORTED: x86_64-target-arch

#include <assert.h>
#include <stdio.h>
#include <sys/mman.h>
Expand Down
32 changes: 32 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -3190,4 +3190,36 @@ def fir_CUDADataTransferOp : fir_Op<"cuda_data_transfer", []> {
}];
}

def fir_CUDAAllocateOp : fir_Op<"cuda_allocate", [AttrSizedOperandSegments,
MemoryEffects<[MemAlloc<DefaultResource>]>]> {
let summary = "Perform the device allocation of data of an allocatable";

let description = [{
The fir.cuda_allocate operation performs the allocation on the device
of the data of an allocatable. The descriptor passed to the operation
is initialized before with the standard flang runtime calls.
}];

let arguments = (ins Arg<AnyRefOrBoxType, "", [MemWrite]>:$box,
Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$errmsg,
Optional<AnyIntegerType>:$stream,
Arg<Optional<AnyRefOrBoxType>, "", [MemWrite]>:$pinned,
Arg<Optional<AnyRefOrBoxType>, "", [MemRead]>:$source,
fir_CUDADataAttributeAttr:$cuda_attr,
UnitAttr:$hasStat);

let results = (outs AnyIntegerType:$stat);

let assemblyFormat = [{
$box `:` qualified(type($box))
( `source` `(` $source^ `:` qualified(type($source) )`)` )?
( `errmsg` `(` $errmsg^ `:` type($errmsg) `)` )?
( `stream` `(` $stream^ `:` type($stream) `)` )?
( `pinned` `(` $pinned^ `:` type($pinned) `)` )?
attr-dict `->` type($stat)
}];

let hasVerifier = 1;
}

#endif
1 change: 1 addition & 0 deletions flang/include/flang/Optimizer/Dialect/FIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ def AnyRefOrBoxLike : TypeConstraint<Or<[AnyReferenceLike.predicate,
def AnyRefOrBox : TypeConstraint<Or<[fir_ReferenceType.predicate,
fir_HeapType.predicate, fir_PointerType.predicate,
IsBaseBoxTypePred]>, "any reference or box">;
def AnyRefOrBoxType : Type<AnyRefOrBox.predicate, "any legal ref or box type">;

def AnyShapeLike : TypeConstraint<Or<[fir_ShapeType.predicate,
fir_ShapeShiftType.predicate]>, "any legal shape type">;
Expand Down
19 changes: 19 additions & 0 deletions flang/lib/Optimizer/Dialect/FIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3993,6 +3993,25 @@ mlir::LogicalResult fir::CUDAKernelOp::verify() {
return mlir::success();
}

mlir::LogicalResult fir::CUDAAllocateOp::verify() {
if (getPinned() && getStream())
return emitOpError("pinned and stream cannot appears at the same time");
if (!fir::unwrapRefType(getBox().getType()).isa<fir::BaseBoxType>())
return emitOpError(
"expect box to be a reference to/or a class or box type value");
if (getSource() &&
!fir::unwrapRefType(getSource().getType()).isa<fir::BaseBoxType>())
return emitOpError(
"expect source to be a reference to/or a class or box type value");
if (getErrmsg() &&
!fir::unwrapRefType(getErrmsg().getType()).isa<fir::BoxType>())
return emitOpError(
"expect errmsg to be a reference to/or a box type value");
if (getErrmsg() && !getHasStat())
return emitOpError("expect stat attribute when errmsg is provided");
return mlir::success();
}

//===----------------------------------------------------------------------===//
// FIROpsDialect
//===----------------------------------------------------------------------===//
Expand Down
50 changes: 50 additions & 0 deletions flang/test/Fir/cuf-invalid.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// RUN: fir-opt -split-input-file -verify-diagnostics %s

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%1 = fir.alloca i32
%pinned = fir.alloca i1
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%s = fir.load %1 : !fir.ref<i32>
// expected-error@+1{{'fir.cuda_allocate' op pinned and stream cannot appears at the same time}}
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> stream(%s : i32) pinned(%pinned : !fir.ref<i1>) {cuda_attr = #fir.cuda<device>} -> i32
return
}

// -----

func.func @_QPsub1() {
%1 = fir.alloca i32
// expected-error@+1{{'fir.cuda_allocate' op expect box to be a reference to/or a class or box type value}}
%2 = fir.cuda_allocate %1 : !fir.ref<i32> {cuda_attr = #fir.cuda<device>} -> i32
return
}

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%c100 = arith.constant 100 : index
%7 = fir.alloca !fir.char<1,100> {bindc_name = "msg", uniq_name = "_QFsub1Emsg"}
%8:2 = hlfir.declare %7 typeparams %c100 {uniq_name = "_QFsub1Emsg"} : (!fir.ref<!fir.char<1,100>>, index) -> (!fir.ref<!fir.char<1,100>>, !fir.ref<!fir.char<1,100>>)
%9 = fir.embox %8#1 : (!fir.ref<!fir.char<1,100>>) -> !fir.box<!fir.char<1,100>>
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%16 = fir.convert %9 : (!fir.box<!fir.char<1,100>>) -> !fir.box<none>
// expected-error@+1{{'fir.cuda_allocate' op expect stat attribute when errmsg is provided}}
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> errmsg(%16 : !fir.box<none>) {cuda_attr = #fir.cuda<device>} -> i32
return
}

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%1 = fir.alloca i32
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
// expected-error@+1{{'fir.cuda_allocate' op expect errmsg to be a reference to/or a box type value}}
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> errmsg(%1 : !fir.ref<i32>) {cuda_attr = #fir.cuda<device>, hasStat} -> i32
return
}
70 changes: 70 additions & 0 deletions flang/test/Fir/cuf.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// RUN: fir-opt --split-input-file %s | fir-opt --split-input-file | FileCheck %s

// Simple round trip test of operations.

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> {cuda_attr = #fir.cuda<device>} -> i32
return
}

// CHECK: fir.cuda_allocate %{{.*}} : !fir.ref<!fir.box<none>> {cuda_attr = #fir.cuda<device>} -> i32

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%1 = fir.alloca i32
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%s = fir.load %1 : !fir.ref<i32>
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> stream(%s : i32) {cuda_attr = #fir.cuda<device>} -> i32
return
}

// CHECK: fir.cuda_allocate %{{.*}} : !fir.ref<!fir.box<none>> stream(%{{.*}} : i32) {cuda_attr = #fir.cuda<device>} -> i32

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%1 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "b", uniq_name = "_QFsub1Eb"}
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%5:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%12 = fir.convert %5#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> source(%12 : !fir.ref<!fir.box<none>>) {cuda_attr = #fir.cuda<device>} -> i32
return
}

// CHECK: fir.cuda_allocate %{{.*}} : !fir.ref<!fir.box<none>> source(%{{.*}} : !fir.ref<!fir.box<none>>) {cuda_attr = #fir.cuda<device>} -> i32

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%pinned = fir.alloca i1
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> pinned(%pinned : !fir.ref<i1>) {cuda_attr = #fir.cuda<device>} -> i32
return
}

// CHECK: fir.cuda_allocate %{{.*}} : !fir.ref<!fir.box<none>> pinned(%{{.*}} : !fir.ref<i1>) {cuda_attr = #fir.cuda<device>} -> i32

// -----

func.func @_QPsub1() {
%0 = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub1Ea"}
%4:2 = hlfir.declare %0 {cuda_attr = #fir.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
%c100 = arith.constant 100 : index
%7 = fir.alloca !fir.char<1,100> {bindc_name = "msg", uniq_name = "_QFsub1Emsg"}
%8:2 = hlfir.declare %7 typeparams %c100 {uniq_name = "_QFsub1Emsg"} : (!fir.ref<!fir.char<1,100>>, index) -> (!fir.ref<!fir.char<1,100>>, !fir.ref<!fir.char<1,100>>)
%9 = fir.embox %8#1 : (!fir.ref<!fir.char<1,100>>) -> !fir.box<!fir.char<1,100>>
%11 = fir.convert %4#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<none>>
%16 = fir.convert %9 : (!fir.box<!fir.char<1,100>>) -> !fir.box<none>
%13 = fir.cuda_allocate %11 : !fir.ref<!fir.box<none>> errmsg(%16 : !fir.box<none>) {cuda_attr = #fir.cuda<device>, hasStat} -> i32
return
}
18 changes: 18 additions & 0 deletions libc/hdr/types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,21 @@ add_proxy_header_library(
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.struct_timespec
)

add_proxy_header_library(
fenv_t
HDRS
fenv_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.fenv_t
libc.incude.fenv
)

add_proxy_header_library(
fexcept_t
HDRS
fexcept_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.fexcept_t
libc.incude.fenv
)
22 changes: 22 additions & 0 deletions libc/hdr/types/fenv_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Definition of macros from fenv_t.h --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_HDR_FENV_T_H
#define LLVM_LIBC_HDR_FENV_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/fenv_t.h"

#else // Overlay mode

#include <fenv.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_FENV_T_H
22 changes: 22 additions & 0 deletions libc/hdr/types/fexcept_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Definition of macros from fexcept_t.h -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_HDR_FEXCEPT_T_H
#define LLVM_LIBC_HDR_FEXCEPT_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/fexcept_t.h"

#else // Overlay mode

#include <fenv.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_FENV_T_H
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ add_header_library(
HDRS
FEnvImpl.h
DEPENDS
libc.include.fenv
libc.hdr.types.fenv_t
libc.hdr.fenv_macros
libc.hdr.math_macros
libc.src.__support.macros.attributes
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/aarch64/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#endif

#include <arm_acle.h>
#include <fenv.h>
#include <stdint.h>

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/aarch64/fenv_darwin_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#endif

#include <arm_acle.h>
#include <fenv.h>
#include <stdint.h>

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/arm/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ARM_FENVIMPL_H

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
#include <fenv.h>
#include <stdint.h>

namespace LIBC_NAMESPACE {
Expand Down
1 change: 1 addition & 0 deletions libc/src/__support/FPUtil/riscv/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM
#include "src/__support/macros/config.h" // For LIBC_INLINE
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/x86_64/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
#error "Invalid include"
#endif

#include <fenv.h>
#include <stdint.h>

#include "hdr/types/fenv_t.h"
#include "src/__support/macros/sanitizer.h"

namespace LIBC_NAMESPACE {
Expand Down
7 changes: 6 additions & 1 deletion libc/src/fenv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ add_entrypoint_object(
HDRS
fegetround.h
DEPENDS
libc.include.fenv
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand Down Expand Up @@ -71,6 +70,7 @@ add_entrypoint_object(
fegetenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -84,6 +84,7 @@ add_entrypoint_object(
fesetenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -97,6 +98,7 @@ add_entrypoint_object(
fegetexceptflag.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fexcept_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -123,6 +125,7 @@ add_entrypoint_object(
fesetexceptflag.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fexcept_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -136,6 +139,7 @@ add_entrypoint_object(
feholdexcept.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -149,6 +153,7 @@ add_entrypoint_object(
feupdateenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fegetenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEGETENV_H
#define LLVM_LIBC_SRC_FENV_FEGETENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
3 changes: 1 addition & 2 deletions libc/src/fenv/fegetexceptflag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/fegetexceptflag.h"
#include "hdr/types/fexcept_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"

#include <fenv.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, fegetexceptflag, (fexcept_t * flagp, int excepts)) {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feholdexcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/feholdexcept.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"
#include <fenv.h>

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feholdexcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEHOLDEXCEPT_H
#define LLVM_LIBC_SRC_FENV_FEHOLDEXCEPT_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fesetenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FESETENV_H
#define LLVM_LIBC_SRC_FENV_FESETENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fesetexceptflag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/fesetexceptflag.h"
#include "hdr/types/fexcept_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"
#include <fenv.h>

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feupdateenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEUPDATEENV_H
#define LLVM_LIBC_SRC_FENV_FEUPDATEENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
1 change: 1 addition & 0 deletions libc/test/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ add_unittest_framework_library(
LibcTest
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fenv_impl
libc.hdr.types.fenv_t
)

add_unittest_framework_library(
Expand Down
7 changes: 4 additions & 3 deletions libc/test/UnitTest/FPExceptMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

#include "FPExceptMatcher.h"

#include <fenv.h>
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include <memory>
#include <setjmp.h>
#include <signal.h>
Expand Down Expand Up @@ -36,12 +37,12 @@ FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) {

caughtExcept = false;
fenv_t oldEnv;
fegetenv(&oldEnv);
fputil::get_env(&oldEnv);
if (sigsetjmp(jumpBuffer, 1) == 0)
funcUP->call();
// We restore the previous floating point environment after
// the call to the function which can potentially raise SIGFPE.
fesetenv(&oldEnv);
fputil::set_env(&oldEnv);
signal(SIGFPE, oldSIGFPEHandler);
exceptionRaised = caughtExcept;
}
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/exception_flags_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fexcept_t.h"
#include "src/fenv/fegetexceptflag.h"
#include "src/fenv/fesetexceptflag.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFenvTest, GetExceptFlagAndSetExceptFlag) {
// We will disable all exceptions to prevent invocation of the exception
// handler.
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/feholdexcept_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/feholdexcept.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/macros/properties/architectures.h"
#include "test/UnitTest/FPExceptMatcher.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFEnvTest, RaiseAndCrash) {
#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || \
defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/fenv/feupdateenv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/feupdateenv.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>
#include <signal.h>

TEST(LlvmLibcFEnvTest, UpdateEnvTest) {
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/getenv_and_setenv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/fegetenv.h"
#include "src/fenv/fegetround.h"
#include "src/fenv/fesetenv.h"
Expand All @@ -14,8 +15,6 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFenvTest, GetEnvAndSetEnv) {
// We will disable all exceptions to prevent invocation of the exception
// handler.
Expand Down
10 changes: 7 additions & 3 deletions libcxx/utils/ci/run-buildbot
Original file line number Diff line number Diff line change
Expand Up @@ -368,18 +368,22 @@ bootstrapping-build)
-DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DLLVM_ENABLE_PROJECTS="clang" \
-DLLVM_ENABLE_PROJECTS="clang;lldb" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DLLVM_RUNTIME_TARGETS="$(${CXX} --print-target-triple)" \
-DLLVM_HOST_TRIPLE="$(${CXX} --print-target-triple)" \
-DLLVM_TARGETS_TO_BUILD="host" \
-DRUNTIMES_BUILD_ALLOW_DARWIN=ON \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_LIT_ARGS="-sv --xunit-xml-output test-results.xml --timeout=1500 --time-tests"

echo "+++ Running the libc++ and libc++abi tests"
echo "+++ Running the LLDB libc++ data formatter tests"
${NINJA} -vC "${BUILD_DIR}" check-lldb-api-functionalities-data-formatter-data-formatter-stl-libcxx

echo "--- Running the libc++ and libc++abi tests"
${NINJA} -vC "${BUILD_DIR}" check-runtimes

echo "--- Installing libc++ and libc++abi to a fake location"
echo "+++ Installing libc++ and libc++abi to a fake location"
${NINJA} -vC "${BUILD_DIR}" install-runtimes

ccache -s
Expand Down
5 changes: 5 additions & 0 deletions libcxxabi/src/aix_state_tab_eh.inc
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
} else {
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
// TODO: in the legacy ABI, destructors had a second argument. We don't expect to encounter
// destructors of this type in the itanium-based ABI, so this should be safe, but this could use some cleanup.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
reinterpret_cast<destruct_f>(fsmEntry->destructor));
#pragma GCC diagnostic pop
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
}
} catch (...) {
Expand Down
7 changes: 7 additions & 0 deletions lld/COFF/Chunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,13 @@ void SectionChunk::getRuntimePseudoRelocs(
dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
if (!target || !target->isRuntimePseudoReloc)
continue;
// If the target doesn't have a chunk allocated, it may be a
// DefinedImportData symbol which ended up unnecessary after GC.
// Normally we wouldn't eliminate section chunks that are referenced, but
// references within DWARF sections don't count for keeping section chunks
// alive. Thus such dangling references in DWARF sections are expected.
if (!target->getChunk())
continue;
int sizeInBits =
getRuntimePseudoRelocSize(rel.Type, file->ctx.config.machine);
if (sizeInBits == 0) {
Expand Down
8 changes: 4 additions & 4 deletions lld/MachO/ObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ class ObjcCategoryMerger {
const PointerListInfo &ptrList);

Defined *emitCategory(const ClassExtensionInfo &extInfo);
Defined *emitCatListEntrySec(const std::string &forCateogryName,
Defined *emitCatListEntrySec(const std::string &forCategoryName,
const std::string &forBaseClassName,
ObjFile *objFile);
Defined *emitCategoryBody(const std::string &name, const Defined *nameSym,
Expand Down Expand Up @@ -878,7 +878,7 @@ void ObjcCategoryMerger::emitAndLinkPointerList(

// This method creates an __objc_catlist ConcatInputSection with a single slot
Defined *
ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCateogryName,
ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCategoryName,
const std::string &forBaseClassName,
ObjFile *objFile) {
uint32_t sectionSize = target->wordSize;
Expand All @@ -894,7 +894,7 @@ ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCateogryName,
newCatList->parent = infoCategoryWriter.catListInfo.outputSection;

std::string catSymName = "<__objc_catlist slot for merged category ";
catSymName += forBaseClassName + "(" + forCateogryName + ")>";
catSymName += forBaseClassName + "(" + forCategoryName + ")>";

Defined *catListSym = make<Defined>(
newStringData(catSymName.c_str()), /*file=*/objFile, newCatList,
Expand Down Expand Up @@ -1069,7 +1069,7 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
off += target->wordSize) {
Defined *categorySym = tryGetDefinedAtIsecOffset(catListCisec, off);
assert(categorySym &&
"Failed to get a valid cateogry at __objc_catlit offset");
"Failed to get a valid category at __objc_catlit offset");

// We only support ObjC categories (no swift + @objc)
// TODO: Support swift + @objc categories also
Expand Down
41 changes: 41 additions & 0 deletions lld/test/COFF/autoimport-gc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# REQUIRES: x86
# RUN: split-file %s %t.dir

# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/lib.s -filetype=obj -o %t.dir/lib.obj
# RUN: lld-link -out:%t.dir/lib.dll -dll -entry:DllMainCRTStartup %t.dir/lib.obj -lldmingw -implib:%t.dir/lib.lib

# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/main.s -filetype=obj -o %t.dir/main.obj
# RUN: lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/lib.lib -opt:ref -debug:dwarf

#--- main.s
.global main
.section .text$main,"xr",one_only,main
main:
ret

.global other
.section .text$other,"xr",one_only,other
other:
movq .refptr.variable(%rip), %rax
movl (%rax), %eax
ret

.section .rdata$.refptr.variable,"dr",discard,.refptr.variable
.global .refptr.variable
.refptr.variable:
.quad variable

.section .debug_info
.long 1
.quad variable
.long 2

#--- lib.s
.global variable
.global DllMainCRTStartup
.text
DllMainCRTStartup:
ret
.data
variable:
.long 42
2 changes: 1 addition & 1 deletion lldb/cmake/modules/LLDBFramework.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ add_custom_command(TARGET liblldb POST_BUILD
if(NOT APPLE_EMBEDDED)
if (TARGET clang-resource-headers)
add_dependencies(liblldb clang-resource-headers)
set(clang_resource_headers_dir $<TARGET_PROPERTY:clang-resource-headers,RUNTIME_OUTPUT_DIRECTORY>)
set(clang_resource_headers_dir $<TARGET_PROPERTY:clang-resource-headers,INTERFACE_INCLUDE_DIRECTORIES>)
else()
set(clang_resource_headers_dir ${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}/include)
if(NOT EXISTS ${clang_resource_headers_dir})
Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ enum CompletionType {

/// Specifies if children need to be re-computed
/// after a call to \ref SyntheticChildrenFrontEnd::Update.
enum class ChildCacheState {
enum ChildCacheState {
eRefetch = 0, ///< Children need to be recomputed dynamically.

eReuse = 1, ///< Children did not change and don't need to be recomputed;
Expand Down
2 changes: 2 additions & 0 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,8 @@ def setUpCommands(cls):
"settings set symbols.enable-external-lookup false",
# Inherit the TCC permissions from the inferior's parent.
"settings set target.inherit-tcc true",
# Based on https://discourse.llvm.org/t/running-lldb-in-a-container/76801/4
"settings set target.disable-aslr false",
# Kill rather than detach from the inferior if something goes wrong.
"settings set target.detach-on-error false",
# Disable fix-its by default so that incorrect expressions in tests don't
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,6 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor(
context.AddNamedDecl(copied_function);

context.m_found_function_with_type_info = true;
context.m_found_function = true;
} else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) {
context.AddNamedDecl(copied_var);
context.m_found_variable = true;
Expand Down Expand Up @@ -1299,7 +1298,6 @@ void ClangExpressionDeclMap::LookupFunction(

AddOneFunction(context, sym_ctx.function, nullptr);
context.m_found_function_with_type_info = true;
context.m_found_function = true;
} else if (sym_ctx.symbol) {
Symbol *symbol = sym_ctx.symbol;
if (target && symbol->GetType() == eSymbolTypeReExported) {
Expand Down Expand Up @@ -1331,10 +1329,8 @@ void ClangExpressionDeclMap::LookupFunction(
if (!context.m_found_function_with_type_info) {
if (extern_symbol) {
AddOneFunction(context, nullptr, extern_symbol);
context.m_found_function = true;
} else if (non_extern_symbol) {
AddOneFunction(context, nullptr, non_extern_symbol);
context.m_found_function = true;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct NameSearchContext {

bool m_found_variable = false;
bool m_found_function_with_type_info = false;
bool m_found_function = false;
bool m_found_local_vars_nsp = false;
bool m_found_type = false;

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxQueue.cpp
LibCxxRangesRefView.cpp
LibCxxSliceArray.cpp
LibCxxProxyArray.cpp
LibCxxSpan.cpp
LibCxxTuple.cpp
LibCxxUnorderedMap.cpp
Expand Down
11 changes: 11 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,12 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator,
"libc++ std::slice_array synthetic children",
"^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator,
"libc++ synthetic children for the valarray proxy arrays",
"^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
stl_deref_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
Expand Down Expand Up @@ -890,6 +896,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::slice_array summary provider",
"^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags,
true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ summary provider for the valarray proxy arrays",
"^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
stl_summary_flags, true);
AddCXXSummary(
cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ std::list summary provider",
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ SyntheticChildrenFrontEnd *
LibcxxStdSliceArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdProxyArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
Expand Down
194 changes: 194 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//===-- LibCxxProxyArray.cpp-----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "LibCxx.h"

#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include <optional>

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace lldb_private {
namespace formatters {

/// Data formatter for libc++'s std::"proxy_array".
///
/// A proxy_array's are created by using:
/// std::gslice_array operator[](const std::gslice& gslicearr);
/// std::mask_array operator[](const std::valarray<bool>& boolarr);
/// std::indirect_array operator[](const std::valarray<std::size_t>& indarr);
///
/// These arrays have the following members:
/// - __vp_ points to std::valarray::__begin_
/// - __1d_ an array of offsets of the elements from @a __vp_
class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);

~LibcxxStdProxyArraySyntheticFrontEnd() override;

llvm::Expected<uint32_t> CalculateNumChildren() override;

lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;

lldb::ChildCacheState Update() override;

bool MightHaveChildren() override;

size_t GetIndexOfChildWithName(ConstString name) override;

private:
/// A non-owning pointer to the array's __vp_.
ValueObject *m_base = nullptr;
/// The type of the array's template argument T.
CompilerType m_element_type;
/// The sizeof the array's template argument T.
uint32_t m_element_size = 0;

/// A non-owning pointer to the array's __1d_.__begin_.
ValueObject *m_start = nullptr;
/// A non-owning pointer to the array's __1d_.__end_.
ValueObject *m_finish = nullptr;
/// The type of the __1d_ array's template argument T (size_t).
CompilerType m_element_type_size_t;
/// The sizeof the __1d_ array's template argument T (size_t)
uint32_t m_element_size_size_t = 0;
};

} // namespace formatters
} // namespace lldb_private

lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
if (valobj_sp)
Update();
}

lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
~LibcxxStdProxyArraySyntheticFrontEnd() {
// these need to stay around because they are child objects who will follow
// their parent's life cycle
// delete m_base;
}

llvm::Expected<uint32_t> lldb_private::formatters::
LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() {

if (!m_start || !m_finish)
return 0;
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);

if (start_val == 0 || finish_val == 0)
return 0;

if (start_val >= finish_val)
return 0;

size_t num_children = (finish_val - start_val);
if (num_children % m_element_size_size_t)
return 0;
return num_children / m_element_size_size_t;
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex(
uint32_t idx) {
if (!m_base)
return lldb::ValueObjectSP();

uint64_t offset = idx * m_element_size_size_t;
offset = offset + m_start->GetValueAsUnsigned(0);

lldb::ValueObjectSP indirect = CreateValueObjectFromAddress(
"", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t);
if (!indirect)
return lldb::ValueObjectSP();

const size_t value = indirect->GetValueAsUnsigned(0);
if (!value)
return lldb::ValueObjectSP();

offset = value * m_element_size;
offset = offset + m_base->GetValueAsUnsigned(0);

StreamString name;
name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value);
return CreateValueObjectFromAddress(name.GetString(), offset,
m_backend.GetExecutionContextRef(),
m_element_type);
}

lldb::ChildCacheState
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() {
m_base = nullptr;
m_start = nullptr;
m_finish = nullptr;

CompilerType type = m_backend.GetCompilerType();
if (type.GetNumTemplateArguments() == 0)
return ChildCacheState::eRefetch;

m_element_type = type.GetTypeTemplateArgument(0);
if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr))
m_element_size = *size;

if (m_element_size == 0)
return ChildCacheState::eRefetch;

ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_");
if (!vector)
return ChildCacheState::eRefetch;

type = vector->GetCompilerType();
if (type.GetNumTemplateArguments() == 0)
return ChildCacheState::eRefetch;

m_element_type_size_t = type.GetTypeTemplateArgument(0);
if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr))
m_element_size_size_t = *size;

if (m_element_size_size_t == 0)
return ChildCacheState::eRefetch;

ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_");
ValueObjectSP start = vector->GetChildMemberWithName("__begin_");
ValueObjectSP finish = vector->GetChildMemberWithName("__end_");
if (!base || !start || !finish)
return ChildCacheState::eRefetch;

m_base = base.get();
m_start = start.get();
m_finish = finish.get();

return ChildCacheState::eRefetch;
}

bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
MightHaveChildren() {
return true;
}

size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name) {
if (!m_base)
return std::numeric_limits<size_t>::max();
return ExtractIndexFromString(name.GetCString());
}

lldb_private::SyntheticChildrenFrontEnd *
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
if (!valobj_sp)
return nullptr;
return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp);
}
79 changes: 6 additions & 73 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,85 +459,19 @@ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) {
return AS_none;
}

static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
static void ParseLangArgs(LangOptions &Opts, ArchSpec arch) {
// FIXME: Cleanup per-file based stuff.

// Set some properties which depend solely on the input kind; it would be
// nice to move these to the language standard, and have the driver resolve
// the input kind + language standard.
if (IK.getLanguage() == clang::Language::Asm) {
Opts.AsmPreprocessor = 1;
} else if (IK.isObjectiveC()) {
Opts.ObjC = 1;
}

LangStandard::Kind LangStd = LangStandard::lang_unspecified;

if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
switch (IK.getLanguage()) {
case clang::Language::Unknown:
case clang::Language::CIR:
case clang::Language::LLVM_IR:
case clang::Language::RenderScript:
llvm_unreachable("Invalid input kind!");
case clang::Language::OpenCL:
LangStd = LangStandard::lang_opencl10;
break;
case clang::Language::OpenCLCXX:
LangStd = LangStandard::lang_openclcpp10;
break;
case clang::Language::Asm:
case clang::Language::C:
case clang::Language::ObjC:
LangStd = LangStandard::lang_gnu99;
break;
case clang::Language::CXX:
case clang::Language::ObjCXX:
LangStd = LangStandard::lang_gnucxx98;
break;
case clang::Language::CUDA:
case clang::Language::HIP:
LangStd = LangStandard::lang_gnucxx17;
break;
case clang::Language::HLSL:
LangStd = LangStandard::lang_hlsl;
break;
}
}

const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
Opts.LineComment = Std.hasLineComments();
Opts.C99 = Std.isC99();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus17 = Std.isCPlusPlus17();
Opts.CPlusPlus20 = Std.isCPlusPlus20();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Std.isC99();
Opts.HexFloats = Std.hasHexFloats();

Opts.WChar = true;

// OpenCL has some additional defaults.
if (LangStd == LangStandard::lang_opencl10) {
Opts.OpenCL = 1;
Opts.AltiVec = 1;
Opts.CXXOperatorNames = 1;
Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All);
}

// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
std::vector<std::string> Includes;
LangOptions::setLangDefaults(Opts, clang::Language::ObjCXX, arch.GetTriple(),
Includes, clang::LangStandard::lang_gnucxx98);

Opts.setValueVisibilityMode(DefaultVisibility);

// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is
// specified, or -std is set to a conforming mode.
Opts.Trigraphs = !Opts.GNUMode;
Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault();
Opts.CharIsSigned = arch.CharIsSignedByDefault();
Opts.OptimizeSize = 0;

// FIXME: Eliminate this dependency.
Expand Down Expand Up @@ -727,8 +661,7 @@ void TypeSystemClang::CreateASTContext() {
m_ast_owned = true;

m_language_options_up = std::make_unique<LangOptions>();
ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX,
GetTargetTriple());
ParseLangArgs(*m_language_options_up, ArchSpec(GetTargetTriple()));

m_identifier_table_up =
std::make_unique<IdentifierTable>(*m_language_options_up, nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def test_diagnose_dereference_function_return(self):
TestBase.setUp(self)
self.build()
exe = self.getBuildArtifact("a.out")
# FIXME: This default changed in lldbtest.py and this test
# seems to rely on having it turned off.
self.runCmd("settings set target.disable-aslr true")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
self.runCmd("run", RUN_SUCCEEDED)
self.expect("thread list", "Thread should be stopped", substrs=["stopped"])
Expand Down
6 changes: 5 additions & 1 deletion lldb/test/API/functionalities/asan/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
C_SOURCES := main.c
CFLAGS_EXTRAS := -fsanitize=address -g -gcolumn-info
asan: CFLAGS_EXTRAS := -fsanitize=address -g -gcolumn-info
asan: all

libsanitizers: CFLAGS_EXTRAS := -fsanitize=address -fsanitize-stable-abi -g -gcolumn-info
libsanitizers: all

include Makefile.rules
73 changes: 72 additions & 1 deletion lldb/test/API/functionalities/asan/TestMemoryHistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
from lldbsuite.test import lldbplatform
from lldbsuite.test import lldbutil

from functionalities.libsanitizers.util import no_libsanitizers

class AsanTestCase(TestBase):
@skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default
@expectedFailureNetBSD
@skipUnlessAddressSanitizer
def test(self):
self.build()
self.build(make_targets=["asan"])
self.asan_tests()

@skipIf(oslist=no_match(["macosx"]))
def test_libsanitizers_asan(self):
self.build(make_targets=["libsanitizers"])
self.libsanitizer_tests()

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Expand All @@ -26,6 +32,71 @@ def setUp(self):
self.line_free = line_number("main.c", "// free line")
self.line_breakpoint = line_number("main.c", "// break line")

# Test line numbers: rdar://126237493
def libsanitizer_tests(self):
target = self.createTestTarget()

if no_libsanitizers(self):
self.skipTest("libsanitizers not found")

self.runCmd(
"env SanitizersAddress=1 MallocSanitizerZone=1 MallocSecureAllocator=0"
)

self.runCmd("run")

# In libsanitizers, memory history is not supported until a report has been generated
self.expect(
"thread list",
"Process should be stopped due to ASan report",
substrs=["stopped", "stop reason = Use of deallocated memory"],
)

# test the 'memory history' command
self.expect(
"memory history 'pointer'",
substrs=[
"Memory deallocated by Thread",
"a.out`f2",
"main.c",
"Memory allocated by Thread",
"a.out`f1",
"main.c",
],
)

# do the same using SB API
process = self.dbg.GetSelectedTarget().process
val = (
process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer")
)
addr = val.GetValueAsUnsigned()
threads = process.GetHistoryThreads(addr)
self.assertEqual(threads.GetSize(), 2)

history_thread = threads.GetThreadAtIndex(0)
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

history_thread = threads.GetThreadAtIndex(1)
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

# let's free the container (SBThreadCollection) and see if the
# SBThreads still live
threads = None
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

def asan_tests(self):
target = self.createTestTarget()

Expand Down
20 changes: 17 additions & 3 deletions lldb/test/API/functionalities/asan/TestReportData.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

from functionalities.libsanitizers.util import no_libsanitizers

class AsanTestReportDataCase(TestBase):
@skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default
@expectedFailureNetBSD
@skipUnlessAddressSanitizer
@skipIf(archs=["i386"], bugnumber="llvm.org/PR36710")
def test(self):
self.build()
self.build(make_targets=["asan"])
self.asan_tests()

@skipIf(oslist=no_match(["macosx"]))
def test_libsanitizers_asan(self):
self.build(make_targets=["libsanitizers"])
self.asan_tests(libsanitizers=True)

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Expand All @@ -29,10 +35,18 @@ def setUp(self):
self.line_crash = line_number("main.c", "// BOOM line")
self.col_crash = 16

def asan_tests(self):
def asan_tests(self, libsanitizers=False):
target = self.createTestTarget()

self.registerSanitizerLibrariesWithTarget(target)
if libsanitizers and no_libsanitizers(self):
self.skipTest("libsanitizers not found")

if libsanitizers:
self.runCmd(
"env SanitizersAddress=1 MallocSanitizerZone=1 MallocSecureAllocator=0"
)
else:
self.registerSanitizerLibrariesWithTarget(target)

self.runCmd("run")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,93 @@ def test_with_run_command(self):
"frame variable sa",
substrs=[
"sa = stride=2 size=4",
"[0] = 1",
"[1] = 3",
"[2] = 5",
"[3] = 7",
"[0] = 11",
"[1] = 13",
"[2] = 15",
"[3] = 17",
"}",
],
)

# check access-by-index
self.expect("frame variable sa[0]", substrs=["1"])
self.expect("frame variable sa[1]", substrs=["3"])
self.expect("frame variable sa[2]", substrs=["5"])
self.expect("frame variable sa[3]", substrs=["7"])
self.expect("frame variable sa[0]", substrs=["11"])
self.expect("frame variable sa[1]", substrs=["13"])
self.expect("frame variable sa[2]", substrs=["15"])
self.expect("frame variable sa[3]", substrs=["17"])
self.expect(
"frame variable sa[4]",
error=True,
substrs=['array index 4 is not valid for "(slice_array<int>) sa"'],
)

#
# std::gslice_array
#

self.expect(
"frame variable ga",
substrs=[
"ga = size=3",
"[0] -> [3] = 13",
"[1] -> [4] = 14",
"[2] -> [5] = 15",
"}",
],
)

# check access-by-index
self.expect("frame variable ga[0]", substrs=["13"])
self.expect("frame variable ga[1]", substrs=["14"])
self.expect("frame variable ga[2]", substrs=["15"])
self.expect(
"frame variable ga[3]",
error=True,
substrs=['array index 3 is not valid for "(gslice_array<int>) ga"'],
)
#
# std::mask_array
#

self.expect(
"frame variable ma",
substrs=[
"ma = size=2",
"[0] -> [1] = 11",
"[1] -> [2] = 12",
"}",
],
)

# check access-by-index
self.expect("frame variable ma[0]", substrs=["11"])
self.expect("frame variable ma[1]", substrs=["12"])
self.expect(
"frame variable ma[2]",
error=True,
substrs=['array index 2 is not valid for "(mask_array<int>) ma"'],
)

#
# std::indirect_array
#

self.expect(
"frame variable ia",
substrs=[
"ia = size=3",
"[0] -> [3] = 13",
"[1] -> [6] = 16",
"[2] -> [9] = 19",
"}",
],
)

# check access-by-index
self.expect("frame variable ia[0]", substrs=["13"])
self.expect("frame variable ia[1]", substrs=["16"])
self.expect("frame variable ia[2]", substrs=["19"])
self.expect(
"frame variable ia[3]",
error=True,
substrs=['array index 3 is not valid for "(indirect_array<int>) ia"'],
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ int main() {

std::valarray<double> va_double({1.0, 0.5, 0.25, 0.125});

std::valarray<int> va({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
std::valarray<int> va({10, 11, 12, 13, 14, 15, 16, 17, 18, 19});
std::slice_array<int> sa = va[std::slice(1, 4, 2)];
std::gslice_array<int> ga = va[std::gslice(
3, std::valarray<std::size_t>(3, 1), std::valarray<std::size_t>(1, 1))];
std::mask_array<int> ma = va[std::valarray<bool>{false, true, true}];
std::indirect_array<int> ia = va[std::valarray<size_t>{3, 6, 9}];

std::cout << "break here\n";
}
3 changes: 3 additions & 0 deletions lldb/test/API/functionalities/libsanitizers/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def no_libsanitizers(testbase):
testbase.runCmd("image list libsystem_sanitizers.dylib", check=False)
return not "libsystem_sanitizers.dylib" in testbase.res.GetOutput()
12 changes: 8 additions & 4 deletions lldb/test/Shell/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@
)

# Enable sanitizer runtime flags.
config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1"
config.environment["TSAN_OPTIONS"] = "halt_on_error=1"
if platform.system() == "Darwin":
config.environment["MallocNanoZone"] = "0"
if "Address" in config.llvm_use_sanitizer:
config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1"
if platform.system() == "Darwin":
config.environment["MallocNanoZone"] = "0"

if "Thread" in config.llvm_use_sanitizer:
config.environment["TSAN_OPTIONS"] = "halt_on_error=1"


# Support running the test suite under the lldb-repro wrapper. This makes it
# possible to capture a test suite run and then rerun all the test from the
Expand Down
1 change: 1 addition & 0 deletions lldb/test/Shell/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ config.lldb_enable_lua = @LLDB_ENABLE_LUA@
config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
config.have_lldb_server = @LLDB_TOOL_LLDB_SERVER_BUILD@
config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
# The shell tests use their own module caches.
config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell")
config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-shell")
Expand Down
4 changes: 3 additions & 1 deletion lldb/unittests/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
if(LLDB_TOOL_LLDB_SERVER_BUILD)
add_subdirectory(lldb-server)
if (NOT LLVM_USE_SANITIZER MATCHES ".*Address.*")
add_subdirectory(lldb-server)
endif()
endif()
3 changes: 3 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ Changes to the C API

* Deprecated ``LLVMConstNUWNeg`` and ``LLVMBuildNUWNeg``.

* Added ``LLVMAtomicRMWBinOpUIncWrap`` and ``LLVMAtomicRMWBinOpUDecWrap`` to
``LLVMAtomicRMWBinOp`` enum for AtomicRMW instructions.

Changes to the CodeGen infrastructure
-------------------------------------

Expand Down
60 changes: 32 additions & 28 deletions llvm/include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,35 +361,39 @@ typedef enum {
} LLVMAtomicOrdering;

typedef enum {
LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
old one */
LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpUIncWrap, /**< Increments the value, wrapping back to zero
when incremented above input value */
LLVMAtomicRMWBinOpUDecWrap, /**< Decrements the value, wrapping back to
the input value when decremented below zero */
} LLVMAtomicRMWBinOp;

typedef enum {
Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/Analysis/TypeMetadataUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void findDevirtualizableCallsForTypeCheckedLoad(
/// Used for example from GlobalDCE to find an entry in a C++ vtable that
/// matches a vcall offset.
///
/// To support Swift vtables, getPointerAtOffset can see through "relative
/// To support relative vtables, getPointerAtOffset can see through "relative
/// pointers", i.e. (sub-)expressions of the form of:
///
/// @symbol = ... {
Expand All @@ -87,8 +87,8 @@ std::pair<Function *, Constant *>
getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M);

/// Finds the same "relative pointer" pattern as described above, where the
/// target is `F`, and replaces the entire pattern with a constant zero.
void replaceRelativePointerUsersWithZero(Function *F);
/// target is `C`, and replaces the entire pattern with a constant zero.
void replaceRelativePointerUsersWithZero(Constant *C);

} // namespace llvm

Expand Down
18 changes: 18 additions & 0 deletions llvm/include/llvm/CodeGen/LivePhysRegs.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@

namespace llvm {

template <typename T> class ArrayRef;

class MachineInstr;
class MachineFunction;
class MachineOperand;
Expand Down Expand Up @@ -207,6 +209,22 @@ static inline bool recomputeLiveIns(MachineBasicBlock &MBB) {
return oldLiveIns != newLiveIns;
}

/// Convenience function for recomputing live-in's for a set of MBBs until the
/// computation converges.
inline void fullyRecomputeLiveIns(ArrayRef<MachineBasicBlock *> MBBs) {
MachineBasicBlock *const *Data = MBBs.data();
const size_t Len = MBBs.size();
while (true) {
bool AnyChange = false;
for (size_t I = 0; I < Len; ++I)
if (recomputeLiveIns(*Data[I]))
AnyChange = true;
if (!AnyChange)
return;
}
}


} // end namespace llvm

#endif // LLVM_CODEGEN_LIVEPHYSREGS_H
3 changes: 3 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,9 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
/// Returns Hdr field
Header getHeader() const { return Hdr; }

/// Returns Offsets field
DWARFDebugNamesOffsets getOffsets() const { return Offsets; }

/// Reads offset of compilation unit CU. CU is 0-based.
uint64_t getCUOffset(uint32_t CU) const;
uint32_t getCUCount() const { return Hdr.CompUnitCount; }
Expand Down
14 changes: 12 additions & 2 deletions llvm/include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2004,8 +2004,18 @@ class IRBuilderBase {
// Instruction creation methods: Cast/Conversion Operators
//===--------------------------------------------------------------------===//

Value *CreateTrunc(Value *V, Type *DestTy, const Twine &Name = "") {
return CreateCast(Instruction::Trunc, V, DestTy, Name);
Value *CreateTrunc(Value *V, Type *DestTy, const Twine &Name = "",
bool IsNUW = false, bool IsNSW = false) {
if (V->getType() == DestTy)
return V;
if (Value *Folded = Folder.FoldCast(Instruction::Trunc, V, DestTy))
return Folded;
Instruction *I = CastInst::Create(Instruction::Trunc, V, DestTy);
if (IsNUW)
I->setHasNoUnsignedWrap();
if (IsNSW)
I->setHasNoSignedWrap();
return Insert(I, Name);
}

Value *CreateZExt(Value *V, Type *DestTy, const Twine &Name = "",
Expand Down
19 changes: 17 additions & 2 deletions llvm/include/llvm/Support/Endian.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ template <typename value_type, std::size_t alignment, typename CharT>
return ret;
}

template <typename value_type, endianness endian, std::size_t alignment,
typename CharT>
template <typename value_type, endianness endian,
std::size_t alignment = unaligned, typename CharT>
[[nodiscard]] inline value_type readNext(const CharT *&memory) {
return readNext<value_type, alignment, CharT>(memory, endian);
}
Expand All @@ -102,6 +102,21 @@ inline void write(void *memory, value_type value) {
write<value_type, alignment>(memory, value, endian);
}

/// Write a value of a particular endianness, and increment the buffer past that
/// value.
template <typename value_type, std::size_t alignment = unaligned,
typename CharT>
inline void writeNext(CharT *&memory, value_type value, endianness endian) {
write(memory, value, endian);
memory += sizeof(value_type);
}

template <typename value_type, endianness endian,
std::size_t alignment = unaligned, typename CharT>
inline void writeNext(CharT *&memory, value_type value) {
writeNext<value_type, alignment, CharT>(memory, value, endian);
}

template <typename value_type>
using make_unsigned_t = std::make_unsigned_t<value_type>;

Expand Down
9 changes: 3 additions & 6 deletions llvm/include/llvm/Support/OnDiskHashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,12 @@ template <typename Info> class OnDiskChainedHashTable {

// 'Items' starts with a 16-bit unsigned integer representing the
// number of items in this bucket.
unsigned Len =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(Items);
unsigned Len = endian::readNext<uint16_t, llvm::endianness::little>(Items);

for (unsigned i = 0; i < Len; ++i) {
// Read the hash.
hash_value_type ItemHash =
endian::readNext<hash_value_type, llvm::endianness::little,
unaligned>(Items);
endian::readNext<hash_value_type, llvm::endianness::little>(Items);

// Determine the length of the key and the data.
const std::pair<offset_type, offset_type> &L =
Expand Down Expand Up @@ -473,8 +471,7 @@ class OnDiskIterableChainedHashTable : public OnDiskChainedHashTable<Info> {
// 'Items' starts with a 16-bit unsigned integer representing the
// number of items in this bucket.
NumItemsInBucketLeft =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(
Ptr);
endian::readNext<uint16_t, llvm::endianness::little>(Ptr);
}
Ptr += sizeof(hash_value_type); // Skip the hash.
// Determine the length of the key and the data.
Expand Down
37 changes: 33 additions & 4 deletions llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryProfileInfo.h"
Expand Down Expand Up @@ -668,7 +669,8 @@ static void computeFunctionSummary(
/// within the initializer.
static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
const Module &M, ModuleSummaryIndex &Index,
VTableFuncList &VTableFuncs) {
VTableFuncList &VTableFuncs,
const GlobalVariable &OrigGV) {
// First check if this is a function pointer.
if (I->getType()->isPointerTy()) {
auto C = I->stripPointerCasts();
Expand Down Expand Up @@ -696,15 +698,42 @@ static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
auto Offset = SL->getElementOffset(EI.index());
unsigned Op = SL->getElementContainingOffset(Offset);
findFuncPointers(cast<Constant>(I->getOperand(Op)),
StartingOffset + Offset, M, Index, VTableFuncs);
StartingOffset + Offset, M, Index, VTableFuncs, OrigGV);
}
} else if (auto *C = dyn_cast<ConstantArray>(I)) {
ArrayType *ATy = C->getType();
Type *EltTy = ATy->getElementType();
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
findFuncPointers(cast<Constant>(I->getOperand(i)),
StartingOffset + i * EltSize, M, Index, VTableFuncs);
StartingOffset + i * EltSize, M, Index, VTableFuncs,
OrigGV);
}
} else if (const auto *CE = dyn_cast<ConstantExpr>(I)) {
// For relative vtables, the next sub-component should be a trunc.
if (CE->getOpcode() != Instruction::Trunc ||
!(CE = dyn_cast<ConstantExpr>(CE->getOperand(0))))
return;

// If this constant can be reduced to the offset between a function and a
// global, then we know this is a valid virtual function if the RHS is the
// original vtable we're scanning through.
if (CE->getOpcode() == Instruction::Sub) {
GlobalValue *LHS, *RHS;
APSInt LHSOffset, RHSOffset;
if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHS, LHSOffset, DL) &&
IsConstantOffsetFromGlobal(CE->getOperand(1), RHS, RHSOffset, DL) &&
RHS == &OrigGV &&

// For relative vtables, this component should point to the callable
// function without any offsets.
LHSOffset == 0 &&

// Also, the RHS should always point to somewhere within the vtable.
RHSOffset <=
static_cast<uint64_t>(DL.getTypeAllocSize(OrigGV.getInitializer()->getType()))) {
findFuncPointers(LHS, StartingOffset, M, Index, VTableFuncs, OrigGV);
}
}
}
}
Expand All @@ -717,7 +746,7 @@ static void computeVTableFuncs(ModuleSummaryIndex &Index,
return;

findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
VTableFuncs);
VTableFuncs, V);

#ifndef NDEBUG
// Validate that the VTableFuncs list is ordered by offset.
Expand Down
47 changes: 34 additions & 13 deletions llvm/lib/Analysis/TypeMetadataUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ static void findLoadCallsAtConstantOffset(
findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset + GEPOffset,
CI, DT);
}
} else if (auto *Call = dyn_cast<CallInst>(User)) {
if (Call->getIntrinsicID() == llvm::Intrinsic::load_relative) {
if (auto *LoadOffset = dyn_cast<ConstantInt>(Call->getOperand(1))) {
findCallsAtConstantOffset(DevirtCalls, nullptr, User,
Offset + LoadOffset->getSExtValue(), CI,
DT);
}
}
}
}
}
Expand Down Expand Up @@ -131,6 +139,12 @@ void llvm::findDevirtualizableCallsForTypeCheckedLoad(

Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
Constant *TopLevelGlobal) {
// TODO: Ideally it would be the caller who knows if it's appropriate to strip
// the DSOLocalEquicalent. More generally, it would feel more appropriate to
// have two functions that handle absolute and relative pointers separately.
if (auto *Equiv = dyn_cast<DSOLocalEquivalent>(I))
I = Equiv->getGlobalValue();

if (I->getType()->isPointerTy()) {
if (Offset == 0)
return I;
Expand Down Expand Up @@ -161,7 +175,7 @@ Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
Offset % ElemSize, M, TopLevelGlobal);
}

// (Swift-specific) relative-pointer support starts here.
// Relative-pointer support starts here.
if (auto *CI = dyn_cast<ConstantInt>(I)) {
if (Offset == 0 && CI->isZero()) {
return I;
Expand Down Expand Up @@ -221,19 +235,26 @@ llvm::getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset,
return std::pair<Function *, Constant *>(Fn, C);
}

void llvm::replaceRelativePointerUsersWithZero(Function *F) {
for (auto *U : F->users()) {
auto *PtrExpr = dyn_cast<ConstantExpr>(U);
if (!PtrExpr || PtrExpr->getOpcode() != Instruction::PtrToInt)
continue;
static void replaceRelativePointerUserWithZero(User *U) {
auto *PtrExpr = dyn_cast<ConstantExpr>(U);
if (!PtrExpr || PtrExpr->getOpcode() != Instruction::PtrToInt)
return;

for (auto *PtrToIntUser : PtrExpr->users()) {
auto *SubExpr = dyn_cast<ConstantExpr>(PtrToIntUser);
if (!SubExpr || SubExpr->getOpcode() != Instruction::Sub)
continue;
for (auto *PtrToIntUser : PtrExpr->users()) {
auto *SubExpr = dyn_cast<ConstantExpr>(PtrToIntUser);
if (!SubExpr || SubExpr->getOpcode() != Instruction::Sub)
return;

SubExpr->replaceNonMetadataUsesWith(
ConstantInt::get(SubExpr->getType(), 0));
}
SubExpr->replaceNonMetadataUsesWith(
ConstantInt::get(SubExpr->getType(), 0));
}
}

void llvm::replaceRelativePointerUsersWithZero(Constant *C) {
for (auto *U : C->users()) {
if (auto *Equiv = dyn_cast<DSOLocalEquivalent>(U))
replaceRelativePointerUsersWithZero(Equiv);
else
replaceRelativePointerUserWithZero(U);
}
}
8 changes: 2 additions & 6 deletions llvm/lib/CodeGen/BranchFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2047,12 +2047,8 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
MBB->splice(Loc, TBB, TBB->begin(), TIB);
FBB->erase(FBB->begin(), FIB);

if (UpdateLiveIns) {
bool anyChange = false;
do {
anyChange = recomputeLiveIns(*TBB) || recomputeLiveIns(*FBB);
} while (anyChange);
}
if (UpdateLiveIns)
fullyRecomputeLiveIns({TBB, FBB});

++NumHoist;
return true;
Expand Down
Loading