Skip to content

Commit

Permalink
merge main into amd-staging
Browse files Browse the repository at this point in the history
Change-Id: I186fd1dca00b163890ca5b3c163b5b7961306646
  • Loading branch information
ronlieb committed Jun 17, 2024
2 parents 541655a + 7439072 commit ee20c73
Show file tree
Hide file tree
Showing 227 changed files with 11,318 additions and 4,910 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-code-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Install clang-format
uses: aminya/setup-cpp@v1
with:
clangformat: 18.1.1
clangformat: 18.1.7

- name: Setup Python env
uses: actions/setup-python@v5
Expand Down
8 changes: 8 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,12 @@ Resolutions to C++ Defect Reports
- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.

- Clang now requires a template argument list after a template keyword.
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).

- Clang now considers ``noexcept(typeid(expr))`` more carefully, instead of always assuming that ``std::bad_typeid`` can be thrown.
(`CWG2191: Incorrect result for noexcept(typeid(v)) <https://cplusplus.github.io/CWG/issues/2191.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -861,6 +867,8 @@ Bug Fixes to C++ Support
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
- Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368).
- Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849)
- Fixed a failed assertion when attempting to convert an integer representing the difference
between the addresses of two labels (a GNU extension) to a pointer within a constant expression. (#GH95366).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,10 @@ class CXXTypeidExpr : public Expr {
reinterpret_cast<Stmt **>(&const_cast<CXXTypeidExpr *>(this)->Operand);
return const_child_range(begin, begin + 1);
}

/// Whether this is of a form like "typeid(*ptr)" that can throw a
/// std::bad_typeid if a pointer is a null pointer ([expr.typeid]p2)
bool hasNullCheck() const;
};

/// A member reference to an MSPropertyDecl.
Expand Down
9 changes: 6 additions & 3 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7149,6 +7149,12 @@ def as_secure_log_file : Separate<["-"], "as-secure-log-file">,

} // let Visibility = [CC1Option, CC1AsOption]

let Visibility = [CC1Option, FC1Option] in {
def mlink_builtin_bitcode : Separate<["-"], "mlink-builtin-bitcode">,
HelpText<"Link and internalize needed symbols from the given bitcode file "
"before performing optimizations.">;
} // let Visibility = [CC1Option, FC1Option]

let Visibility = [CC1Option] in {

def llvm_verify_each : Flag<["-"], "llvm-verify-each">,
Expand Down Expand Up @@ -7251,9 +7257,6 @@ defm constructor_aliases : BoolMOption<"constructor-aliases",
" emitting complete constructors and destructors as aliases when possible">>;
def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">,
HelpText<"Link the given bitcode file before performing optimizations.">;
def mlink_builtin_bitcode : Separate<["-"], "mlink-builtin-bitcode">,
HelpText<"Link and internalize needed symbols from the given bitcode file "
"before performing optimizations.">;
defm link_builtin_bitcode_postopt: BoolMOption<"link-builtin-bitcode-postopt",
CodeGenOpts<"LinkBitcodePostopt">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Link builtin bitcodes after the "
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3769,10 +3769,18 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
break;
}

case CXXTypeidExprClass:
// typeid might throw if its subexpression is potentially-evaluated, so has
// side-effects in that case whether or not its subexpression does.
return cast<CXXTypeidExpr>(this)->isPotentiallyEvaluated();
case CXXTypeidExprClass: {
const auto *TE = cast<CXXTypeidExpr>(this);
if (!TE->isPotentiallyEvaluated())
return false;

// If this type id expression can throw because of a null pointer, that is a
// side-effect independent of if the operand has a side-effect
if (IncludePossibleEffects && TE->hasNullCheck())
return true;

break;
}

case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
Expand Down
47 changes: 47 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,53 @@ QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const {
Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}

static bool isGLValueFromPointerDeref(const Expr *E) {
E = E->IgnoreParens();

if (const auto *CE = dyn_cast<CastExpr>(E)) {
if (!CE->getSubExpr()->isGLValue())
return false;
return isGLValueFromPointerDeref(CE->getSubExpr());
}

if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
return isGLValueFromPointerDeref(OVE->getSourceExpr());

if (const auto *BO = dyn_cast<BinaryOperator>(E))
if (BO->getOpcode() == BO_Comma)
return isGLValueFromPointerDeref(BO->getRHS());

if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(E))
return isGLValueFromPointerDeref(ACO->getTrueExpr()) ||
isGLValueFromPointerDeref(ACO->getFalseExpr());

// C++11 [expr.sub]p1:
// The expression E1[E2] is identical (by definition) to *((E1)+(E2))
if (isa<ArraySubscriptExpr>(E))
return true;

if (const auto *UO = dyn_cast<UnaryOperator>(E))
if (UO->getOpcode() == UO_Deref)
return true;

return false;
}

bool CXXTypeidExpr::hasNullCheck() const {
if (!isPotentiallyEvaluated())
return false;

// C++ [expr.typeid]p2:
// If the glvalue expression is obtained by applying the unary * operator to
// a pointer and the pointer is a null pointer value, the typeid expression
// throws the std::bad_typeid exception.
//
// However, this paragraph's intent is not clear. We choose a very generous
// interpretation which implores us to consider comma operators, conditional
// operators, parentheses and other such constructs.
return isGLValueFromPointerDeref(getExprOperand());
}

QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
Qualifiers Quals;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/ExprConstShared.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
#define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H

namespace llvm {
class APFloat;
}
namespace clang {
class QualType;
class LangOptions;
Expand Down Expand Up @@ -56,4 +59,8 @@ enum class GCCTypeClass {
GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
const LangOptions &LangOpts);

void HandleComplexComplexMul(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C,
llvm::APFloat D, llvm::APFloat &ResR,
llvm::APFloat &ResI);

#endif
113 changes: 64 additions & 49 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9325,6 +9325,13 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
Result.IsNullPtr = false;
return true;
} else {
// In rare instances, the value isn't an lvalue.
// For example, when the value is the difference between the addresses of
// two labels. We reject that as a constant expression because we can't
// compute a valid offset to convert into a pointer.
if (!Value.isLValue())
return false;

// Cast is of an lvalue, no need to change value.
Result.setFrom(Info.Ctx, Value);
return true;
Expand Down Expand Up @@ -15126,6 +15133,62 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
llvm_unreachable("unknown cast resulting in complex value");
}

void HandleComplexComplexMul(APFloat A, APFloat B, APFloat C, APFloat D,
APFloat &ResR, APFloat &ResI) {
// This is an implementation of complex multiplication according to the
// constraints laid out in C11 Annex G. The implementation uses the
// following naming scheme:
// (a + ib) * (c + id)

APFloat AC = A * C;
APFloat BD = B * D;
APFloat AD = A * D;
APFloat BC = B * C;
ResR = AC - BD;
ResI = AD + BC;
if (ResR.isNaN() && ResI.isNaN()) {
bool Recalc = false;
if (A.isInfinity() || B.isInfinity()) {
A = APFloat::copySign(APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0),
A);
B = APFloat::copySign(APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0),
B);
if (C.isNaN())
C = APFloat::copySign(APFloat(C.getSemantics()), C);
if (D.isNaN())
D = APFloat::copySign(APFloat(D.getSemantics()), D);
Recalc = true;
}
if (C.isInfinity() || D.isInfinity()) {
C = APFloat::copySign(APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0),
C);
D = APFloat::copySign(APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0),
D);
if (A.isNaN())
A = APFloat::copySign(APFloat(A.getSemantics()), A);
if (B.isNaN())
B = APFloat::copySign(APFloat(B.getSemantics()), B);
Recalc = true;
}
if (!Recalc && (AC.isInfinity() || BD.isInfinity() || AD.isInfinity() ||
BC.isInfinity())) {
if (A.isNaN())
A = APFloat::copySign(APFloat(A.getSemantics()), A);
if (B.isNaN())
B = APFloat::copySign(APFloat(B.getSemantics()), B);
if (C.isNaN())
C = APFloat::copySign(APFloat(C.getSemantics()), C);
if (D.isNaN())
D = APFloat::copySign(APFloat(D.getSemantics()), D);
Recalc = true;
}
if (Recalc) {
ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D);
ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C);
}
}
}

bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
Expand Down Expand Up @@ -15225,55 +15288,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
!handleFloatFloatBinOp(Info, E, ResI, BO_Mul, B))
return false;
} else {
// In the fully general case, we need to handle NaNs and infinities
// robustly.
APFloat AC = A * C;
APFloat BD = B * D;
APFloat AD = A * D;
APFloat BC = B * C;
ResR = AC - BD;
ResI = AD + BC;
if (ResR.isNaN() && ResI.isNaN()) {
bool Recalc = false;
if (A.isInfinity() || B.isInfinity()) {
A = APFloat::copySign(
APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A);
B = APFloat::copySign(
APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B);
if (C.isNaN())
C = APFloat::copySign(APFloat(C.getSemantics()), C);
if (D.isNaN())
D = APFloat::copySign(APFloat(D.getSemantics()), D);
Recalc = true;
}
if (C.isInfinity() || D.isInfinity()) {
C = APFloat::copySign(
APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C);
D = APFloat::copySign(
APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D);
if (A.isNaN())
A = APFloat::copySign(APFloat(A.getSemantics()), A);
if (B.isNaN())
B = APFloat::copySign(APFloat(B.getSemantics()), B);
Recalc = true;
}
if (!Recalc && (AC.isInfinity() || BD.isInfinity() ||
AD.isInfinity() || BC.isInfinity())) {
if (A.isNaN())
A = APFloat::copySign(APFloat(A.getSemantics()), A);
if (B.isNaN())
B = APFloat::copySign(APFloat(B.getSemantics()), B);
if (C.isNaN())
C = APFloat::copySign(APFloat(C.getSemantics()), C);
if (D.isNaN())
D = APFloat::copySign(APFloat(D.getSemantics()), D);
Recalc = true;
}
if (Recalc) {
ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D);
ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C);
}
}
HandleComplexComplexMul(A, B, C, D, ResR, ResI);
}
} else {
ComplexValue LHS = Result;
Expand Down
55 changes: 45 additions & 10 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,22 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (const auto *AT = RHSType->getAs<AtomicType>())
RHSType = AT->getValueType();

// For ComplexComplex Mul, we have special ops to make their implementation
// easier.
BinaryOperatorKind Op = E->getOpcode();
if (Op == BO_Mul && LHSType->isAnyComplexType() &&
RHSType->isAnyComplexType()) {
assert(classifyPrim(LHSType->getAs<ComplexType>()->getElementType()) ==
classifyPrim(RHSType->getAs<ComplexType>()->getElementType()));
PrimType ElemT =
classifyPrim(LHSType->getAs<ComplexType>()->getElementType());
if (!this->visit(LHS))
return false;
if (!this->visit(RHS))
return false;
return this->emitMulc(ElemT, E);
}

// Evaluate LHS and save value to LHSOffset.
bool LHSIsComplex;
unsigned LHSOffset;
Expand Down Expand Up @@ -919,38 +935,37 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
// For both LHS and RHS, either load the value from the complex pointer, or
// directly from the local variable. For index 1 (i.e. the imaginary part),
// just load 0 and do the operation anyway.
auto loadComplexValue = [this](bool IsComplex, unsigned ElemIndex,
unsigned Offset, const Expr *E) -> bool {
auto loadComplexValue = [this](bool IsComplex, bool LoadZero,
unsigned ElemIndex, unsigned Offset,
const Expr *E) -> bool {
if (IsComplex) {
if (!this->emitGetLocal(PT_Ptr, Offset, E))
return false;
return this->emitArrayElemPop(classifyComplexElementType(E->getType()),
ElemIndex, E);
}
if (ElemIndex == 0)
if (ElemIndex == 0 || !LoadZero)
return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
return this->visitZeroInitializer(classifyPrim(E->getType()), E->getType(),
E);
};

// Now we can get pointers to the LHS and RHS from the offsets above.
BinaryOperatorKind Op = E->getOpcode();
for (unsigned ElemIndex = 0; ElemIndex != 2; ++ElemIndex) {
// Result pointer for the store later.
if (!this->DiscardResult) {
if (!this->emitGetLocal(PT_Ptr, ResultOffset, E))
return false;
}

if (!loadComplexValue(LHSIsComplex, ElemIndex, LHSOffset, LHS))
return false;

if (!loadComplexValue(RHSIsComplex, ElemIndex, RHSOffset, RHS))
return false;

// The actual operation.
switch (Op) {
case BO_Add:
if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
return false;

if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
return false;
if (ResultElemT == PT_Float) {
if (!this->emitAddf(getRoundingMode(E), E))
return false;
Expand All @@ -960,6 +975,11 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
}
break;
case BO_Sub:
if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
return false;

if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
return false;
if (ResultElemT == PT_Float) {
if (!this->emitSubf(getRoundingMode(E), E))
return false;
Expand All @@ -968,6 +988,21 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;
}
break;
case BO_Mul:
if (!loadComplexValue(LHSIsComplex, false, ElemIndex, LHSOffset, LHS))
return false;

if (!loadComplexValue(RHSIsComplex, false, ElemIndex, RHSOffset, RHS))
return false;

if (ResultElemT == PT_Float) {
if (!this->emitMulf(getRoundingMode(E), E))
return false;
} else {
if (!this->emitMul(ResultElemT, E))
return false;
}
break;

default:
return false;
Expand Down
Loading

0 comments on commit ee20c73

Please sign in to comment.