1//===--- ExprUtils.cpp - Shared expression emission queries ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/CodeGenUtils/ExprUtils.h"
10#include "clang/AST/Attr.h"
11#include "clang/AST/ExprCXX.h"
12
13namespace clang::CodeGenUtils {
14
15QualType getFixedSizeElementType(const ASTContext &Ctx,
16 const VariableArrayType *VLA) {
17 QualType EltType;
18 do {
19 EltType = VLA->getElementType();
20 } while ((VLA = Ctx.getAsVariableArrayType(T: EltType)));
21 return EltType;
22}
23
24bool isBlockVarRef(const Expr *E) {
25 // Make sure we look through parens.
26 E = E->IgnoreParens();
27
28 // Check for a direct reference to a __block variable.
29 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: E)) {
30 const VarDecl *Var = dyn_cast<VarDecl>(Val: DRE->getDecl());
31 return (Var && Var->hasAttr<BlocksAttr>());
32 }
33
34 // More complicated stuff.
35
36 // Binary operators.
37 if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(Val: E)) {
38 // For an assignment or pointer-to-member operation, just care
39 // about the LHS.
40 if (Op->isAssignmentOp() || Op->isPtrMemOp())
41 return isBlockVarRef(E: Op->getLHS());
42
43 // For a comma, just care about the RHS.
44 if (Op->getOpcode() == BO_Comma)
45 return isBlockVarRef(E: Op->getRHS());
46
47 // FIXME: pointer arithmetic?
48 return false;
49
50 // Check both sides of a conditional operator.
51 } else if (const AbstractConditionalOperator *Op =
52 dyn_cast<AbstractConditionalOperator>(Val: E)) {
53 return isBlockVarRef(E: Op->getTrueExpr()) ||
54 isBlockVarRef(E: Op->getFalseExpr());
55
56 // OVEs are required to support BinaryConditionalOperators.
57 } else if (const OpaqueValueExpr *Op = dyn_cast<OpaqueValueExpr>(Val: E)) {
58 if (const Expr *Src = Op->getSourceExpr())
59 return isBlockVarRef(E: Src);
60
61 // Casts are necessary to get things like (*(int*)&var) = foo().
62 // We don't really care about the kind of cast here, except
63 // we don't want to look through l2r casts, because it's okay
64 // to get the *value* in a __block variable.
65 } else if (const CastExpr *Cast = dyn_cast<CastExpr>(Val: E)) {
66 if (Cast->getCastKind() == CK_LValueToRValue)
67 return false;
68 return isBlockVarRef(E: Cast->getSubExpr());
69
70 // Handle unary operators. Again, just aggressively look through
71 // it, ignoring the operation.
72 } else if (const UnaryOperator *UOp = dyn_cast<UnaryOperator>(Val: E)) {
73 return isBlockVarRef(E: UOp->getSubExpr());
74
75 // Look into the base of a field access.
76 } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(Val: E)) {
77 return isBlockVarRef(E: Mem->getBase());
78
79 // Look into the base of a subscript.
80 } else if (const ArraySubscriptExpr *Sub = dyn_cast<ArraySubscriptExpr>(Val: E)) {
81 return isBlockVarRef(E: Sub->getBase());
82 }
83
84 return false;
85}
86
87bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
88 const ASTContext &Ctx) {
89 // Anything that is an integer or floating point constant is fine.
90 return E->IgnoreParens()->isEvaluatable(Ctx);
91
92 // Even non-volatile automatic variables can't be evaluated unconditionally.
93 // Referencing a thread_local may cause non-trivial initialization work to
94 // occur. If we're inside a lambda and one of the variables is from the scope
95 // outside the lambda, that function may have returned already. Reading its
96 // locals is a bad idea. Also, these reads may introduce races there didn't
97 // exist in the source-level program.
98}
99
100bool isTrivialFiller(const Expr *E) {
101 if (!E)
102 return true;
103
104 if (isa<ImplicitValueInitExpr>(Val: E))
105 return true;
106
107 if (const auto *ILE = dyn_cast<InitListExpr>(Val: E)) {
108 if (ILE->getNumInits())
109 return false;
110 return isTrivialFiller(E: ILE->getArrayFiller());
111 }
112
113 if (const auto *Cons = dyn_cast_or_null<CXXConstructExpr>(Val: E))
114 return Cons->getConstructor()->isDefaultConstructor() &&
115 Cons->getConstructor()->isTrivial();
116
117 // FIXME: Are there other cases where we can avoid emitting an initializer?
118 return false;
119}
120
121bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
122 for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
123 if (!PD->isInlineBuiltinDeclaration())
124 return false;
125 return true;
126}
127
128} // namespace clang::CodeGenUtils
129