Skip to content

Commit 76e38ca

Browse files
authored
[clang][bytecode] Try to load primitive values directly (#151833)
Instead of doing a GetPtrLocal + Load or GetPtrGlobal + Load pair, try to load the value directly.
1 parent 4b5b36e commit 76e38ca

File tree

5 files changed

+75
-30
lines changed

5 files changed

+75
-30
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,28 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
201201
return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE);
202202

203203
OptPrimType SubExprT = classify(SubExpr->getType());
204+
// Try to load the value directly. This is purely a performance
205+
// optimization.
206+
if (SubExprT) {
207+
if (const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
208+
const ValueDecl *D = DRE->getDecl();
209+
bool IsReference = D->getType()->isReferenceType();
210+
211+
if (!IsReference) {
212+
if (Context::shouldBeGloballyIndexed(D)) {
213+
if (auto GlobalIndex = P.getGlobal(D))
214+
return this->emitGetGlobal(*SubExprT, *GlobalIndex, CE);
215+
} else if (auto It = Locals.find(D); It != Locals.end()) {
216+
return this->emitGetLocal(*SubExprT, It->second.Offset, CE);
217+
} else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
218+
if (auto It = this->Params.find(PVD); It != this->Params.end()) {
219+
return this->emitGetParam(*SubExprT, It->second.Offset, CE);
220+
}
221+
}
222+
}
223+
}
224+
}
225+
204226
// Prepare storage for the result.
205227
if (!Initializing && !SubExprT) {
206228
std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
@@ -3857,10 +3879,7 @@ template <class Emitter>
38573879
bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
38583880
assert(E->getType()->isVoidPointerType());
38593881

3860-
unsigned Offset =
3861-
allocateLocalPrimitive(E->getLabel(), PT_Ptr, /*IsConst=*/true);
3862-
3863-
return this->emitGetLocal(PT_Ptr, Offset, E);
3882+
return this->emitDummyPtr(E, E);
38643883
}
38653884

38663885
template <class Emitter>

clang/lib/AST/ByteCode/EvalEmitter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
282282
using T = typename PrimConv<OpType>::T;
283283

284284
Block *B = getLocal(I);
285+
286+
if (!CheckLocalLoad(S, OpPC, Pointer(B)))
287+
return false;
288+
285289
S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
286290
return true;
287291
}

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -715,23 +715,6 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
715715
return false;
716716
}
717717

718-
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
719-
if (Ptr.isInitialized())
720-
return true;
721-
722-
assert(S.getLangOpts().CPlusPlus);
723-
const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
724-
if ((!VD->hasConstantInitialization() &&
725-
VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||
726-
(S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
727-
!VD->hasICEInitializer(S.getASTContext()))) {
728-
const SourceInfo &Loc = S.Current->getSource(OpPC);
729-
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
730-
S.Note(VD->getLocation(), diag::note_declared_at);
731-
}
732-
return false;
733-
}
734-
735718
static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
736719
if (!Ptr.isWeak())
737720
return true;
@@ -745,6 +728,37 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
745728
return false;
746729
}
747730

731+
// The list of checks here is just the one from CheckLoad, but with the
732+
// ones removed that are impossible on primitive global values.
733+
// For example, since those can't be members of structs, they also can't
734+
// be mutable.
735+
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
736+
if (!CheckExtern(S, OpPC, Ptr))
737+
return false;
738+
if (!CheckConstant(S, OpPC, Ptr))
739+
return false;
740+
if (!CheckDummy(S, OpPC, Ptr, AK_Read))
741+
return false;
742+
if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
743+
return false;
744+
if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
745+
return false;
746+
if (!CheckWeak(S, OpPC, Ptr))
747+
return false;
748+
if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
749+
return false;
750+
return true;
751+
}
752+
753+
// Similarly, for local loads.
754+
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
755+
if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
756+
return false;
757+
if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
758+
return false;
759+
return true;
760+
}
761+
748762
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
749763
AccessKinds AK) {
750764
if (!CheckLive(S, OpPC, Ptr, AK))

clang/lib/AST/ByteCode/Interp.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
9191

9292
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
9393
AccessKinds AK);
94-
/// Check if a global variable is initialized.
95-
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
94+
/// Checks a direct load of a primitive value from a global or local variable.
95+
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
96+
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
9697

9798
/// Checks if a value can be stored in a block.
9899
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
@@ -1465,14 +1466,8 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
14651466
template <PrimType Name, class T = typename PrimConv<Name>::T>
14661467
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
14671468
const Pointer &Ptr = S.P.getPtrGlobal(I);
1468-
if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1469-
return false;
1470-
if (Ptr.isExtern())
1471-
return false;
14721469

1473-
// If a global variable is uninitialized, that means the initializer we've
1474-
// compiled for it wasn't a constant expression. Diagnose that.
1475-
if (!CheckGlobalInitialized(S, OpPC, Ptr))
1470+
if (!CheckGlobalLoad(S, OpPC, Ptr))
14761471
return false;
14771472

14781473
S.Stk.push<T>(Ptr.deref<T>());

clang/test/AST/ByteCode/cxx11.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,16 @@ namespace OverlappingStrings {
289289

290290

291291
}
292+
293+
namespace NonConstLocal {
294+
int a() {
295+
const int t=t; // both-note {{declared here}}
296+
297+
switch(1) {
298+
case t:; // both-note {{initializer of 't' is not a constant expression}} \
299+
// both-error {{case value is not a constant expression}}
300+
}
301+
}
302+
}
303+
304+

0 commit comments

Comments
 (0)