Skip to content

Commit ec075f3

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:f58d54ab969b into amd-gfx:25a5d3ddbc50
Local branch amd-gfx 25a5d3d Merged main:0502d8347020 into amd-gfx:4191fabcf57f Remote branch main f58d54a [clang][Interp] Diagnose uninitialized bases (llvm#67131)
2 parents 25a5d3d + f58d54a commit ec075f3

File tree

15 files changed

+307
-51
lines changed

15 files changed

+307
-51
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
561561
if (!this->visitInitializer(Init))
562562
return false;
563563

564-
if (!this->emitPopPtr(E))
564+
if (!this->emitInitPtrPop(E))
565565
return false;
566566
// Base initializers don't increase InitIndex, since they don't count
567567
// into the Record's fields.
@@ -1718,7 +1718,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
17181718
return false;
17191719
if (!this->visitZeroRecordInitializer(B.R, E))
17201720
return false;
1721-
if (!this->emitPopPtr(E))
1721+
if (!this->emitInitPtrPop(E))
17221722
return false;
17231723
}
17241724

clang/lib/AST/Interp/ByteCodeStmtGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
191191
return false;
192192
if (!this->visitInitializer(InitExpr))
193193
return false;
194-
if (!this->emitPopPtr(InitExpr))
194+
if (!this->emitInitPtrPop(InitExpr))
195195
return false;
196196
}
197197
}

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ template <unsigned Bits, bool Signed> class Integral;
3232
class Boolean;
3333

3434
template <bool Signed> class IntegralAP final {
35-
public:
35+
private:
36+
friend IntegralAP<!Signed>;
3637
APSInt V;
3738

39+
template <typename T> static T truncateCast(const APSInt &V) {
40+
return std::is_signed_v<T> ? V.trunc(sizeof(T) * 8).getSExtValue()
41+
: V.trunc(sizeof(T) * 8).getZExtValue();
42+
}
43+
3844
public:
3945
using AsUnsigned = IntegralAP<false>;
4046

@@ -55,14 +61,14 @@ template <bool Signed> class IntegralAP final {
5561
bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
5662

5763
explicit operator bool() const { return !V.isZero(); }
58-
explicit operator int8_t() const { return V.getSExtValue(); }
59-
explicit operator uint8_t() const { return V.getZExtValue(); }
60-
explicit operator int16_t() const { return V.getSExtValue(); }
61-
explicit operator uint16_t() const { return V.getZExtValue(); }
62-
explicit operator int32_t() const { return V.getSExtValue(); }
63-
explicit operator uint32_t() const { return V.getZExtValue(); }
64-
explicit operator int64_t() const { return V.getSExtValue(); }
65-
explicit operator uint64_t() const { return V.getZExtValue(); }
64+
explicit operator int8_t() const { return truncateCast<int8_t>(V); }
65+
explicit operator uint8_t() const { return truncateCast<uint8_t>(V); }
66+
explicit operator int16_t() const { return truncateCast<int16_t>(V); }
67+
explicit operator uint16_t() const { return truncateCast<uint16_t>(V); }
68+
explicit operator int32_t() const { return truncateCast<int32_t>(V); }
69+
explicit operator uint32_t() const { return truncateCast<uint32_t>(V); }
70+
explicit operator int64_t() const { return truncateCast<int64_t>(V); }
71+
explicit operator uint64_t() const { return truncateCast<uint64_t>(V); }
6672

6773
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
6874
assert(NumBits > 0);

clang/lib/AST/Interp/Interp.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
467467
// Check Fields in all bases
468468
for (const Record::Base &B : R->bases()) {
469469
Pointer P = BasePtr.atField(B.Offset);
470+
if (!P.isInitialized()) {
471+
S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
472+
diag::note_constexpr_uninitialized_base)
473+
<< B.Desc->getType();
474+
return false;
475+
}
470476
Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
471477
}
472478

clang/lib/AST/Interp/Interp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,12 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
12451245
return true;
12461246
}
12471247

1248+
inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
1249+
const Pointer &Ptr = S.Stk.pop<Pointer>();
1250+
Ptr.initialize();
1251+
return true;
1252+
}
1253+
12481254
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
12491255
const Pointer &Ptr) {
12501256
Pointer Base = Ptr;

clang/lib/AST/Interp/Opcodes.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ def GetPtrBasePop : Opcode {
304304
let Args = [ArgUint32];
305305
}
306306

307+
def InitPtrPop : Opcode {
308+
let Args = [];
309+
}
310+
307311
def GetPtrDerivedPop : Opcode {
308312
let Args = [ArgUint32];
309313
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
2+
3+
/// This is like the version in test/SemaCXX/, but some of the
4+
/// output types and their location has been adapted.
5+
/// Differences:
6+
/// 1) The type of the uninitialized base class is printed WITH the namespace,
7+
/// i.e. 'baseclass_uninit::DelBase' instead of just 'DelBase'.
8+
/// 2) The location is not the base specifier declaration, but the call site
9+
/// of the constructor.
10+
11+
12+
namespace baseclass_uninit {
13+
struct DelBase {
14+
constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}}
15+
};
16+
17+
struct Foo : DelBase {
18+
constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}}
19+
};
20+
constexpr Foo f; // expected-error {{must be initialized by a constant expression}} \
21+
// expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
22+
23+
struct Bar : Foo {
24+
constexpr Bar() {};
25+
};
26+
constexpr Bar bar; // expected-error {{must be initialized by a constant expression}} \
27+
// expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
28+
29+
struct Base {};
30+
struct A : Base {
31+
constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
32+
};
33+
34+
constexpr A a; // expected-error {{must be initialized by a constant expression}} \
35+
// expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
36+
37+
38+
struct B : Base {
39+
constexpr B() : {} // expected-error {{expected class member or base class name}}
40+
};
41+
42+
constexpr B b; // expected-error {{must be initialized by a constant expression}} \
43+
// expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
44+
} // namespace baseclass_uninit
45+
46+
47+
struct Foo {
48+
constexpr Foo(); // expected-note 2{{declared here}}
49+
};
50+
51+
constexpr Foo ff; // expected-error {{must be initialized by a constant expression}} \
52+
// expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
53+
54+
struct Bar : protected Foo {
55+
int i;
56+
constexpr Bar() : i(12) {} // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
57+
};
58+
59+
constexpr Bar bb; // expected-error {{must be initialized by a constant expression}} \
60+
// expected-note {{in call to 'Bar()'}}
61+
62+
template <typename Ty>
63+
struct Baz {
64+
constexpr Baz(); // expected-note {{declared here}}
65+
};
66+
67+
struct Quux : Baz<Foo>, private Bar {
68+
int i;
69+
constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}}
70+
};
71+
72+
constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \
73+
// expected-note {{in call to 'Quux()'}}

clang/test/AST/Interp/literals.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ namespace i128 {
5353
static_assert(Two == 2, "");
5454

5555
constexpr uint128_t AllOnes = ~static_cast<uint128_t>(0);
56-
static_assert(AllOnes == static_cast<uint128_t>(-1), "");
56+
static_assert(AllOnes == UINT128_MAX, "");
5757

5858
#if __cplusplus >= 201402L
5959
template <typename T>
@@ -70,6 +70,14 @@ namespace i128 {
7070
static_assert(CastFrom<double>(12) == 12, "");
7171
static_assert(CastFrom<long double>(12) == 12, "");
7272

73+
static_assert(CastFrom<char>(AllOnes) == -1, "");
74+
static_assert(CastFrom<unsigned char>(AllOnes) == 0xFF, "");
75+
static_assert(CastFrom<long>(AllOnes) == -1, "");
76+
static_assert(CastFrom<unsigned short>(AllOnes) == 0xFFFF, "");
77+
static_assert(CastFrom<int>(AllOnes) == -1, "");
78+
static_assert(CastFrom<int128_t>(AllOnes) == -1, "");
79+
static_assert(CastFrom<uint128_t>(AllOnes) == AllOnes, "");
80+
7381
template <typename T>
7482
constexpr __int128 CastTo(T A) {
7583
int128_t B = (int128_t)A;

llvm/include/llvm/Analysis/TargetTransformInfo.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ class TargetTransformInfo {
348348
/// individual classes of instructions would be better.
349349
unsigned getInliningThresholdMultiplier() const;
350350

351+
unsigned getInliningCostBenefitAnalysisSavingsMultiplier() const;
352+
unsigned getInliningCostBenefitAnalysisProfitableMultiplier() const;
353+
351354
/// \returns A value to be added to the inlining threshold.
352355
unsigned adjustInliningThreshold(const CallBase *CB) const;
353356

@@ -1696,6 +1699,9 @@ class TargetTransformInfo::Concept {
16961699
const TTI::PointersChainInfo &Info, Type *AccessTy,
16971700
TTI::TargetCostKind CostKind) = 0;
16981701
virtual unsigned getInliningThresholdMultiplier() const = 0;
1702+
virtual unsigned getInliningCostBenefitAnalysisSavingsMultiplier() const = 0;
1703+
virtual unsigned
1704+
getInliningCostBenefitAnalysisProfitableMultiplier() const = 0;
16991705
virtual unsigned adjustInliningThreshold(const CallBase *CB) = 0;
17001706
virtual int getInlinerVectorBonusPercent() const = 0;
17011707
virtual unsigned getCallerAllocaCost(const CallBase *CB,
@@ -2068,6 +2074,12 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
20682074
unsigned adjustInliningThreshold(const CallBase *CB) override {
20692075
return Impl.adjustInliningThreshold(CB);
20702076
}
2077+
unsigned getInliningCostBenefitAnalysisSavingsMultiplier() const override {
2078+
return Impl.getInliningCostBenefitAnalysisSavingsMultiplier();
2079+
}
2080+
unsigned getInliningCostBenefitAnalysisProfitableMultiplier() const override {
2081+
return Impl.getInliningCostBenefitAnalysisProfitableMultiplier();
2082+
}
20712083
int getInlinerVectorBonusPercent() const override {
20722084
return Impl.getInlinerVectorBonusPercent();
20732085
}

llvm/include/llvm/Analysis/TargetTransformInfoImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class TargetTransformInfoImplBase {
6969
}
7070

7171
unsigned getInliningThresholdMultiplier() const { return 1; }
72+
unsigned getInliningCostBenefitAnalysisSavingsMultiplier() const { return 8; }
73+
unsigned getInliningCostBenefitAnalysisProfitableMultiplier() const {
74+
return 8;
75+
}
7276
unsigned adjustInliningThreshold(const CallBase *CB) const { return 0; }
7377
unsigned getCallerAllocaCost(const CallBase *CB, const AllocaInst *AI) const {
7478
return 0;

llvm/include/llvm/Config/llvm-config.h.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* Indicate that this is LLVM compiled from the amd-gfx branch. */
1818
#define LLVM_HAVE_BRANCH_AMD_GFX
19-
#define LLVM_MAIN_REVISION 476604
19+
#define LLVM_MAIN_REVISION 476609
2020

2121
/* Define if LLVM_ENABLE_DUMP is enabled */
2222
#cmakedefine LLVM_ENABLE_DUMP

llvm/lib/Analysis/InlineCost.cpp

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,21 @@ static cl::opt<bool> InlineEnableCostBenefitAnalysis(
8888
"inline-enable-cost-benefit-analysis", cl::Hidden, cl::init(false),
8989
cl::desc("Enable the cost-benefit analysis for the inliner"));
9090

91+
// InlineSavingsMultiplier overrides per TTI multipliers iff it is
92+
// specified explicitly in command line options. This option is exposed
93+
// for tuning and testing.
9194
static cl::opt<int> InlineSavingsMultiplier(
9295
"inline-savings-multiplier", cl::Hidden, cl::init(8),
9396
cl::desc("Multiplier to multiply cycle savings by during inlining"));
9497

98+
// InlineSavingsProfitableMultiplier overrides per TTI multipliers iff it is
99+
// specified explicitly in command line options. This option is exposed
100+
// for tuning and testing.
101+
static cl::opt<int> InlineSavingsProfitableMultiplier(
102+
"inline-savings-profitable-multiplier", cl::Hidden, cl::init(4),
103+
cl::desc("A multiplier on top of cycle savings to decide whether the "
104+
"savings won't justify the cost"));
105+
95106
static cl::opt<int>
96107
InlineSizeAllowance("inline-size-allowance", cl::Hidden, cl::init(100),
97108
cl::desc("The maximum size of a callee that get's "
@@ -815,6 +826,32 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
815826
return true;
816827
}
817828

829+
// A helper function to choose between command line override and default.
830+
unsigned getInliningCostBenefitAnalysisSavingsMultiplier() const {
831+
if (InlineSavingsMultiplier.getNumOccurrences())
832+
return InlineSavingsMultiplier;
833+
return TTI.getInliningCostBenefitAnalysisSavingsMultiplier();
834+
}
835+
836+
// A helper function to choose between command line override and default.
837+
unsigned getInliningCostBenefitAnalysisProfitableMultiplier() const {
838+
if (InlineSavingsProfitableMultiplier.getNumOccurrences())
839+
return InlineSavingsProfitableMultiplier;
840+
return TTI.getInliningCostBenefitAnalysisProfitableMultiplier();
841+
}
842+
843+
void OverrideCycleSavingsAndSizeForTesting(APInt &CycleSavings, int &Size) {
844+
if (std::optional<int> AttrCycleSavings = getStringFnAttrAsInt(
845+
CandidateCall, "inline-cycle-savings-for-test")) {
846+
CycleSavings = *AttrCycleSavings;
847+
}
848+
849+
if (std::optional<int> AttrRuntimeCost = getStringFnAttrAsInt(
850+
CandidateCall, "inline-runtime-cost-for-test")) {
851+
Size = *AttrRuntimeCost;
852+
}
853+
}
854+
818855
// Determine whether we should inline the given call site, taking into account
819856
// both the size cost and the cycle savings. Return std::nullopt if we don't
820857
// have sufficient profiling information to determine.
@@ -884,29 +921,55 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
884921
CycleSavings += getCallsiteCost(this->CandidateCall, DL);
885922
CycleSavings *= *CallerBFI->getBlockProfileCount(CallerBB);
886923

887-
// Remove the cost of the cold basic blocks.
924+
// Remove the cost of the cold basic blocks to model the runtime cost more
925+
// accurately. Both machine block placement and function splitting could
926+
// place cold blocks further from hot blocks.
888927
int Size = Cost - ColdSize;
889928

890929
// Allow tiny callees to be inlined regardless of whether they meet the
891930
// savings threshold.
892931
Size = Size > InlineSizeAllowance ? Size - InlineSizeAllowance : 1;
893932

933+
OverrideCycleSavingsAndSizeForTesting(CycleSavings, Size);
894934
CostBenefit.emplace(APInt(128, Size), CycleSavings);
895935

896-
// Return true if the savings justify the cost of inlining. Specifically,
897-
// we evaluate the following inequality:
936+
// Let R be the ratio of CycleSavings to Size. We accept the inlining
937+
// opportunity if R is really high and reject if R is really low. If R is
938+
// somewhere in the middle, we fall back to the cost-based analysis.
898939
//
899-
// CycleSavings PSI->getOrCompHotCountThreshold()
900-
// -------------- >= -----------------------------------
901-
// Size InlineSavingsMultiplier
940+
// Specifically, let R = CycleSavings / Size, we accept the inlining
941+
// opportunity if:
902942
//
903-
// Note that the left hand side is specific to a call site. The right hand
904-
// side is a constant for the entire executable.
905-
APInt LHS = CycleSavings;
906-
LHS *= InlineSavingsMultiplier;
907-
APInt RHS(128, PSI->getOrCompHotCountThreshold());
908-
RHS *= Size;
909-
return LHS.uge(RHS);
943+
// PSI->getOrCompHotCountThreshold()
944+
// R > -------------------------------------------------
945+
// getInliningCostBenefitAnalysisSavingsMultiplier()
946+
//
947+
// and reject the inlining opportunity if:
948+
//
949+
// PSI->getOrCompHotCountThreshold()
950+
// R <= ----------------------------------------------------
951+
// getInliningCostBenefitAnalysisProfitableMultiplier()
952+
//
953+
// Otherwise, we fall back to the cost-based analysis.
954+
//
955+
// Implementation-wise, use multiplication (CycleSavings * Multiplier,
956+
// HotCountThreshold * Size) rather than division to avoid precision loss.
957+
APInt Threshold(128, PSI->getOrCompHotCountThreshold());
958+
Threshold *= Size;
959+
960+
APInt UpperBoundCycleSavings = CycleSavings;
961+
UpperBoundCycleSavings *= getInliningCostBenefitAnalysisSavingsMultiplier();
962+
if (UpperBoundCycleSavings.uge(Threshold))
963+
return true;
964+
965+
APInt LowerBoundCycleSavings = CycleSavings;
966+
LowerBoundCycleSavings *=
967+
getInliningCostBenefitAnalysisProfitableMultiplier();
968+
if (LowerBoundCycleSavings.ult(Threshold))
969+
return false;
970+
971+
// Otherwise, fall back to the cost-based analysis.
972+
return std::nullopt;
910973
}
911974

912975
InlineResult finalizeAnalysis() override {

llvm/lib/Analysis/TargetTransformInfo.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,17 @@ unsigned TargetTransformInfo::getInliningThresholdMultiplier() const {
212212
return TTIImpl->getInliningThresholdMultiplier();
213213
}
214214

215+
unsigned
216+
TargetTransformInfo::getInliningCostBenefitAnalysisSavingsMultiplier() const {
217+
return TTIImpl->getInliningCostBenefitAnalysisSavingsMultiplier();
218+
}
219+
220+
unsigned
221+
TargetTransformInfo::getInliningCostBenefitAnalysisProfitableMultiplier()
222+
const {
223+
return TTIImpl->getInliningCostBenefitAnalysisProfitableMultiplier();
224+
}
225+
215226
unsigned
216227
TargetTransformInfo::adjustInliningThreshold(const CallBase *CB) const {
217228
return TTIImpl->adjustInliningThreshold(CB);

0 commit comments

Comments
 (0)