Skip to content

Commit c5f22f9

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:b5af667b01458e9083256f2614df175916c73e5a into amd-gfx:3ceb816dd24a
Local branch amd-gfx 3ceb816 Merged main:0869204cff22831d0bb19a82c99bf85e4deb4ae3 into amd-gfx:d30ece0223f2 Remote branch main b5af667 [BOLT] Map branch source address to the containing basic block in BAT YAML
2 parents 3ceb816 + b5af667 commit c5f22f9

37 files changed

+327
-296
lines changed

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/STLExtras.h"
2424
#include "llvm/ADT/ScopeExit.h"
2525
#include "llvm/Support/CommandLine.h"
26+
#include "llvm/Support/Compiler.h"
2627
#include "llvm/Support/Debug.h"
2728
#include "llvm/Support/Errc.h"
2829
#include "llvm/Support/FileSystem.h"
@@ -2378,21 +2379,27 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
23782379
return CSI;
23792380
};
23802381

2382+
// Lookup containing basic block offset and index
2383+
auto getBlock = [&BlockMap](uint32_t Offset) {
2384+
auto BlockIt = BlockMap.upper_bound(Offset);
2385+
if (LLVM_UNLIKELY(BlockIt == BlockMap.begin())) {
2386+
errs() << "BOLT-ERROR: invalid BAT section\n";
2387+
exit(1);
2388+
}
2389+
--BlockIt;
2390+
return std::pair(BlockIt->first, BlockIt->second.getBBIndex());
2391+
};
2392+
23812393
for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) {
2382-
if (!BlockMap.isInputBlock(FromOffset))
2383-
continue;
2384-
const unsigned Index = BlockMap.getBBIndex(FromOffset);
2394+
const auto &[_, Index] = getBlock(FromOffset);
23852395
yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[Index];
23862396
for (const auto &[SuccOffset, SuccDataIdx] : SuccKV)
23872397
if (BlockMap.isInputBlock(SuccOffset))
23882398
YamlBB.Successors.emplace_back(
23892399
getSuccessorInfo(SuccOffset, SuccDataIdx));
23902400
}
23912401
for (const auto &[FromOffset, CallTo] : Branches.InterIndex) {
2392-
auto BlockIt = BlockMap.upper_bound(FromOffset);
2393-
--BlockIt;
2394-
const unsigned BlockOffset = BlockIt->first;
2395-
const unsigned BlockIndex = BlockIt->second.getBBIndex();
2402+
const auto &[BlockOffset, BlockIndex] = getBlock(FromOffset);
23962403
yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex];
23972404
const uint32_t Offset = FromOffset - BlockOffset;
23982405
for (const auto &[CallToLoc, CallToIdx] : CallTo)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
B 80010c 800194 1 0

bolt/test/X86/bolt-address-translation-yaml.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ RUN: llvm-bolt %t.exe -o %t.out --pa -p %p/Inputs/blarge_new.preagg.txt \
55
RUN: --reorder-blocks=ext-tsp --split-functions --split-strategy=cdsplit \
66
RUN: --reorder-functions=cdsort --enable-bat --dyno-stats --skip-funcs=main \
77
RUN: 2>&1 | FileCheck --check-prefix WRITE-BAT-CHECK %s
8+
# Check that branch with entry in BAT is accounted for.
9+
RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat_branchentry.preagg.txt \
10+
RUN: -w %t.yaml -o %t.fdata
11+
RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o %t.null
12+
RUN: FileCheck --input-file %t.yaml --check-prefix BRANCHENTRY-YAML-CHECK %s
13+
RUN: FileCheck --input-file %t.yaml-fdata --check-prefix BRANCHENTRY-YAML-CHECK %s
14+
BRANCHENTRY-YAML-CHECK: - name: SolveCubic
15+
BRANCHENTRY-YAML-CHECK: bid: 0
16+
BRANCHENTRY-YAML-CHECK: hash: 0x700F19D24600000
17+
BRANCHENTRY-YAML-CHECK-NEXT: succ: [ { bid: 7, cnt: 1 }
18+
# Large profile test
819
RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat.preagg.txt -w %t.yaml -o %t.fdata \
920
RUN: 2>&1 | FileCheck --check-prefix READ-BAT-CHECK %s
1021
RUN: FileCheck --input-file %t.yaml --check-prefix YAML-BAT-CHECK %s

bolt/test/runtime/bolt-reserved.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
* not enough for allocating new sections.
1717
*/
1818

19-
// RUN: %clang %s -o %t.exe -Wl,--no-eh-frame-hdr -Wl,-q -DTINY
20-
// RUN: not llvm-bolt %t.exe -o %t.bolt.exe 2>&1 | \
19+
// RUN: %clang %s -o %t.tiny.exe -Wl,--no-eh-frame-hdr -Wl,-q -DTINY
20+
// RUN: not llvm-bolt %t.tiny.exe -o %t.tiny.bolt.exe 2>&1 | \
2121
// RUN: FileCheck %s --check-prefix=CHECK-TINY
2222

2323
// CHECK-TINY: BOLT-ERROR: reserved space (1 byte) is smaller than required

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10035,12 +10035,6 @@ def warn_new_dangling_initializer_list : Warning<
1003510035
"the allocated initializer list}0 "
1003610036
"will be destroyed at the end of the full-expression">,
1003710037
InGroup<DanglingInitializerList>;
10038-
def warn_unsupported_lifetime_extension : Warning<
10039-
"lifetime extension of "
10040-
"%select{temporary|backing array of initializer list}0 created "
10041-
"by aggregate initialization using a default member initializer "
10042-
"is not yet supported; lifetime of %select{temporary|backing array}0 "
10043-
"will end at the end of the full-expression">, InGroup<Dangling>;
1004410038

1004510039
// For non-floating point, expressions of the form x == x or x != x
1004610040
// should result in a warning, since these always evaluate to a constant.

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,14 +347,6 @@ Descriptor::Descriptor(const DeclTy &D)
347347
assert(Source && "Missing source");
348348
}
349349

350-
/// Dummy array.
351-
Descriptor::Descriptor(const DeclTy &D, UnknownSize)
352-
: Source(D), ElemSize(1), Size(UnknownSizeMark), MDSize(0),
353-
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
354-
IsTemporary(false), IsArray(true), IsDummy(true) {
355-
assert(Source && "Missing source");
356-
}
357-
358350
QualType Descriptor::getType() const {
359351
if (auto *E = asExpr())
360352
return E->getType();

clang/lib/AST/Interp/Descriptor.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ struct Descriptor final {
128128
/// Flag indicating if the block is an array.
129129
const bool IsArray = false;
130130
/// Flag indicating if this is a dummy descriptor.
131-
const bool IsDummy = false;
131+
bool IsDummy = false;
132132

133133
/// Storage management methods.
134134
const BlockCtorFn CtorFn = nullptr;
@@ -162,8 +162,8 @@ struct Descriptor final {
162162
/// Allocates a dummy descriptor.
163163
Descriptor(const DeclTy &D);
164164

165-
/// Allocates a dummy array descriptor.
166-
Descriptor(const DeclTy &D, UnknownSize);
165+
/// Make this descriptor a dummy descriptor.
166+
void makeDummy() { IsDummy = true; }
167167

168168
QualType getType() const;
169169
QualType getElemQualType() const;

clang/lib/AST/Interp/Interp.h

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
823823
// element in the same array are NOT equal. They have the same Base value,
824824
// but a different Offset. This is a pretty rare case, so we fix this here
825825
// by comparing pointers to the first elements.
826-
if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
826+
if (!LHS.isZero() && LHS.isArrayRoot())
827827
VL = LHS.atIndex(0).getByteOffset();
828-
if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
828+
if (!RHS.isZero() && RHS.isArrayRoot())
829829
VR = RHS.atIndex(0).getByteOffset();
830830

831831
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
@@ -1241,14 +1241,16 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
12411241
!CheckNull(S, OpPC, Ptr, CSK_Field))
12421242
return false;
12431243

1244-
if (CheckDummy(S, OpPC, Ptr)) {
1245-
if (!CheckExtern(S, OpPC, Ptr))
1246-
return false;
1247-
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1248-
return false;
1249-
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1250-
return false;
1251-
}
1244+
if (!CheckExtern(S, OpPC, Ptr))
1245+
return false;
1246+
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1247+
return false;
1248+
if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1249+
return false;
1250+
1251+
if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1252+
return false;
1253+
12521254
S.Stk.push<Pointer>(Ptr.atField(Off));
12531255
return true;
12541256
}
@@ -2034,11 +2036,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
20342036
if (!Ptr.isZero()) {
20352037
if (!CheckArray(S, OpPC, Ptr))
20362038
return false;
2037-
2038-
if (Ptr.isDummy()) {
2039-
S.Stk.push<Pointer>(Ptr);
2040-
return true;
2041-
}
20422039
}
20432040

20442041
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
@@ -2055,11 +2052,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
20552052
if (!Ptr.isZero()) {
20562053
if (!CheckArray(S, OpPC, Ptr))
20572054
return false;
2058-
2059-
if (Ptr.isDummy()) {
2060-
S.Stk.push<Pointer>(Ptr);
2061-
return true;
2062-
}
20632055
}
20642056

20652057
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
@@ -2113,12 +2105,12 @@ inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t
21132105
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
21142106
const Pointer &Ptr = S.Stk.pop<Pointer>();
21152107

2116-
if (Ptr.isZero() || Ptr.isDummy()) {
2108+
if (Ptr.isZero()) {
21172109
S.Stk.push<Pointer>(Ptr);
21182110
return true;
21192111
}
21202112

2121-
if (!Ptr.isUnknownSizeArray()) {
2113+
if (!Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
21222114
S.Stk.push<Pointer>(Ptr.atIndex(0));
21232115
return true;
21242116
}

clang/lib/AST/Interp/Program.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,20 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
144144
if (auto It = DummyVariables.find(VD); It != DummyVariables.end())
145145
return It->second;
146146

147-
// Create dummy descriptor.
148-
// We create desriptors of 'array of unknown size' if the type is an array
149-
// type _and_ the size isn't known (it's not a ConstantArrayType). If the size
150-
// is known however, we create a regular dummy pointer.
151147
Descriptor *Desc;
152-
if (const auto *AT = VD->getType()->getAsArrayTypeUnsafe();
153-
AT && !isa<ConstantArrayType>(AT))
154-
Desc = allocateDescriptor(VD, Descriptor::UnknownSize{});
148+
if (std::optional<PrimType> T = Ctx.classify(VD->getType()))
149+
Desc = createDescriptor(VD, *T, std::nullopt, true, false);
155150
else
151+
Desc = createDescriptor(VD, VD->getType().getTypePtr(), std::nullopt, true,
152+
false);
153+
if (!Desc)
156154
Desc = allocateDescriptor(VD);
157155

156+
assert(Desc);
157+
Desc->makeDummy();
158+
159+
assert(Desc->isDummy());
160+
158161
// Allocate a block for storage.
159162
unsigned I = Globals.size();
160163

@@ -310,8 +313,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
310313
for (const FieldDecl *FD : RD->fields()) {
311314
// Note that we DO create fields and descriptors
312315
// for unnamed bitfields here, even though we later ignore
313-
// them everywhere. That's because so the FieldDecl's
314-
// getFieldIndex() matches.
316+
// them everywhere. That's so the FieldDecl's getFieldIndex() matches.
315317

316318
// Reserve space for the field's descriptor and the offset.
317319
BaseSize += align(sizeof(InlineDescriptor));
@@ -344,6 +346,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
344346
Descriptor::MetadataSize MDSize,
345347
bool IsConst, bool IsTemporary,
346348
bool IsMutable, const Expr *Init) {
349+
347350
// Classes and structures.
348351
if (const auto *RT = Ty->getAs<RecordType>()) {
349352
if (const auto *Record = getOrCreateRecord(RT->getDecl()))

clang/lib/CodeGen/CGRecordLayoutBuilder.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct CGRecordLowering {
7575
// sentinel member type that ensures correct rounding.
7676
struct MemberInfo {
7777
CharUnits Offset;
78-
enum InfoKind { VFPtr, VBPtr, Field, Base, VBase, Scissor } Kind;
78+
enum InfoKind { VFPtr, VBPtr, Field, Base, VBase } Kind;
7979
llvm::Type *Data;
8080
union {
8181
const FieldDecl *FD;
@@ -197,7 +197,7 @@ struct CGRecordLowering {
197197
const CXXRecordDecl *Query) const;
198198
void calculateZeroInit();
199199
CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
200-
void checkBitfieldClipping() const;
200+
void checkBitfieldClipping(bool isNonVirtualBaseType) const;
201201
/// Determines if we need a packed llvm struct.
202202
void determinePacked(bool NVBaseType);
203203
/// Inserts padding everywhere it's needed.
@@ -299,8 +299,8 @@ void CGRecordLowering::lower(bool NVBaseType) {
299299
accumulateVBases();
300300
}
301301
llvm::stable_sort(Members);
302+
checkBitfieldClipping(NVBaseType);
302303
Members.push_back(StorageInfo(Size, getIntNType(8)));
303-
checkBitfieldClipping();
304304
determinePacked(NVBaseType);
305305
insertPadding();
306306
Members.pop_back();
@@ -894,8 +894,6 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
894894
}
895895

896896
void CGRecordLowering::accumulateVBases() {
897-
Members.push_back(MemberInfo(calculateTailClippingOffset(false),
898-
MemberInfo::Scissor, nullptr, RD));
899897
for (const auto &Base : RD->vbases()) {
900898
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
901899
if (BaseDecl->isEmpty())
@@ -950,18 +948,19 @@ void CGRecordLowering::calculateZeroInit() {
950948
}
951949

952950
// Verify accumulateBitfields computed the correct storage representations.
953-
void CGRecordLowering::checkBitfieldClipping() const {
951+
void CGRecordLowering::checkBitfieldClipping(bool IsNonVirtualBaseType) const {
954952
#ifndef NDEBUG
953+
auto ScissorOffset = calculateTailClippingOffset(IsNonVirtualBaseType);
955954
auto Tail = CharUnits::Zero();
956955
for (const auto &M : Members) {
957-
// Only members with data and the scissor can cut into tail padding.
958-
if (!M.Data && M.Kind != MemberInfo::Scissor)
956+
// Only members with data could possibly overlap.
957+
if (!M.Data)
959958
continue;
960959

961960
assert(M.Offset >= Tail && "Bitfield access unit is not clipped");
962-
Tail = M.Offset;
963-
if (M.Data)
964-
Tail += getSize(M.Data);
961+
Tail = M.Offset + getSize(M.Data);
962+
assert((Tail <= ScissorOffset || M.Offset >= ScissorOffset) &&
963+
"Bitfield straddles scissor offset");
965964
}
966965
#endif
967966
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5777,10 +5777,9 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
57775777
Res = Immediate.TransformInitializer(Param->getInit(),
57785778
/*NotCopy=*/false);
57795779
});
5780-
if (Res.isInvalid())
5781-
return ExprError();
5782-
Res = ConvertParamDefaultArgument(Param, Res.get(),
5783-
Res.get()->getBeginLoc());
5780+
if (Res.isUsable())
5781+
Res = ConvertParamDefaultArgument(Param, Res.get(),
5782+
Res.get()->getBeginLoc());
57845783
if (Res.isInvalid())
57855784
return ExprError();
57865785
Init = Res.get();
@@ -5816,7 +5815,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
58165815
Expr *Init = nullptr;
58175816

58185817
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
5819-
5818+
bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
58205819
EnterExpressionEvaluationContext EvalContext(
58215820
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
58225821

@@ -5851,19 +5850,35 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
58515850
ImmediateCallVisitor V(getASTContext());
58525851
if (!NestedDefaultChecking)
58535852
V.TraverseDecl(Field);
5854-
if (V.HasImmediateCalls) {
5853+
5854+
// CWG1815
5855+
// Support lifetime extension of temporary created by aggregate
5856+
// initialization using a default member initializer. We should always rebuild
5857+
// the initializer if it contains any temporaries (if the initializer
5858+
// expression is an ExprWithCleanups). Then make sure the normal lifetime
5859+
// extension code recurses into the default initializer and does lifetime
5860+
// extension when warranted.
5861+
bool ContainsAnyTemporaries =
5862+
isa_and_present<ExprWithCleanups>(Field->getInClassInitializer());
5863+
if (V.HasImmediateCalls || InLifetimeExtendingContext ||
5864+
ContainsAnyTemporaries) {
58555865
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
58565866
CurContext};
58575867
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
58585868
NestedDefaultChecking;
5859-
5869+
// Pass down lifetime extending flag, and collect temporaries in
5870+
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
5871+
keepInLifetimeExtendingContext();
58605872
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
58615873
ExprResult Res;
5874+
5875+
// Rebuild CXXDefaultInitExpr might cause diagnostics.
5876+
SFINAETrap Trap(*this);
58625877
runWithSufficientStackSpace(Loc, [&] {
58635878
Res = Immediate.TransformInitializer(Field->getInClassInitializer(),
58645879
/*CXXDirectInit=*/false);
58655880
});
5866-
if (!Res.isInvalid())
5881+
if (Res.isUsable())
58675882
Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
58685883
if (Res.isInvalid()) {
58695884
Field->setInvalidDecl();

0 commit comments

Comments
 (0)