63 changes: 9 additions & 54 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ class PseudoObjectExpr;
class QualType;
class SemaHLSL;
class SemaOpenACC;
class SemaSYCL;
class StandardConversionSequence;
class Stmt;
class StringLiteral;
Expand Down Expand Up @@ -467,7 +468,6 @@ class Sema final : public SemaBase {
// 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
// 38. CUDA (SemaCUDA.cpp)
// 39. OpenMP Directives and Clauses (SemaOpenMP.cpp)
// 40. SYCL Constructs (SemaSYCL.cpp)

/// \name Semantic Analysis
/// Implementations are in Sema.cpp
Expand Down Expand Up @@ -974,6 +974,11 @@ class Sema final : public SemaBase {
return *OpenACCPtr;
}

SemaSYCL &SYCL() {
assert(SYCLPtr);
return *SYCLPtr;
}

protected:
friend class Parser;
friend class InitializationSequence;
Expand Down Expand Up @@ -1006,6 +1011,7 @@ class Sema final : public SemaBase {

std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
std::unique_ptr<SemaSYCL> SYCLPtr;

///@}

Expand Down Expand Up @@ -5439,8 +5445,7 @@ class Sema final : public SemaBase {

ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
bool NeedsADL,
bool AcceptInvalidDecl = false,
bool NeedUnresolved = false);
bool AcceptInvalidDecl = false);
ExprResult BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
NamedDecl *FoundD = nullptr,
Expand All @@ -5456,15 +5461,6 @@ class Sema final : public SemaBase {
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);

ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI);
ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy);

bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);

ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
Expand Down Expand Up @@ -6592,10 +6588,7 @@ class Sema final : public SemaBase {
SourceLocation RParenLoc);

//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation Loc);

/// Check whether the type of 'this' is valid in the current context.
bool CheckCXXThisType(SourceLocation Loc, QualType Type);
ExprResult ActOnCXXThis(SourceLocation loc);

/// Build a CXXThisExpr and mark it referenced in the current context.
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
Expand Down Expand Up @@ -14520,44 +14513,6 @@ class Sema final : public SemaBase {
OpenMPDirectiveKind CancelRegion);

///@}

//
//
// -------------------------------------------------------------------------
//
//

/// \name SYCL Constructs
/// Implementations are in SemaSYCL.cpp
///@{

public:
/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as device code".
///
/// - If CurLexicalContext is a kernel function or it is known that the
/// function will be emitted for the device, emits the diagnostics
/// immediately.
/// - If CurLexicalContext is a function and we are compiling
/// for the device, but we don't know that this function will be codegen'ed
/// for devive yet, creates a diagnostic which is emitted if and when we
/// realize that the function will be codegen'ed.
///
/// Example usage:
///
/// Diagnose __float128 type usage only from SYCL device code if the current
/// target doesn't support it
/// if (!S.Context.getTargetInfo().hasFloat128Type() &&
/// S.getLangOpts().SYCLIsDevice)
/// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128";
SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID);

void deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck);

///@}
};

DeductionFailureInfo
Expand Down
19 changes: 18 additions & 1 deletion clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"
#include <variant>

namespace clang {
class OpenACCClause;
Expand All @@ -35,7 +36,11 @@ class SemaOpenACC : public SemaBase {
SourceRange ClauseRange;
SourceLocation LParenLoc;

// TODO OpenACC: Add variant here to store details of individual clauses.
struct DefaultDetails {
OpenACCDefaultClauseKind DefaultClauseKind;
};

std::variant<DefaultDetails> Details;

public:
OpenACCParsedClause(OpenACCDirectiveKind DirKind,
Expand All @@ -52,8 +57,20 @@ class SemaOpenACC : public SemaBase {

SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }

OpenACCDefaultClauseKind getDefaultClauseKind() const {
assert(ClauseKind == OpenACCClauseKind::Default &&
"Parsed clause is not a default clause");
return std::get<DefaultDetails>(Details).DefaultClauseKind;
}

void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }

void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
assert(ClauseKind == OpenACCClauseKind::Default &&
"Parsed clause is not a default clause");
Details = DefaultDetails{DefKind};
}
};

SemaOpenACC(Sema &S);
Expand Down
65 changes: 65 additions & 0 deletions clang/include/clang/Sema/SemaSYCL.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----- SemaSYCL.h ------- Semantic Analysis for SYCL constructs -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis for SYCL constructs.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMASYCL_H
#define LLVM_CLANG_SEMA_SEMASYCL_H

#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/DenseSet.h"

namespace clang {

class SemaSYCL : public SemaBase {
public:
SemaSYCL(Sema &S);

/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as device code".
///
/// - If CurLexicalContext is a kernel function or it is known that the
/// function will be emitted for the device, emits the diagnostics
/// immediately.
/// - If CurLexicalContext is a function and we are compiling
/// for the device, but we don't know yet that this function will be
/// codegen'ed for the devive, creates a diagnostic which is emitted if and
/// when we realize that the function will be codegen'ed.
///
/// Example usage:
///
/// Diagnose __float128 type usage only from SYCL device code if the current
/// target doesn't support it
/// if (!S.Context.getTargetInfo().hasFloat128Type() &&
/// S.getLangOpts().SYCLIsDevice)
/// DiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128";
SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);

void deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck);

ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy);
};

} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMASYCL_H
109 changes: 99 additions & 10 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,18 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastFloatingIntegral(*ToT, CE);
}

case CK_NullToPointer:
case CK_NullToPointer: {
if (DiscardResult)
return true;
return this->emitNull(classifyPrim(CE->getType()), CE);

const Descriptor *Desc = nullptr;
const QualType PointeeType = CE->getType()->getPointeeType();
if (!PointeeType.isNull()) {
if (std::optional<PrimType> T = classify(PointeeType))
Desc = P.createDescriptor(SubExpr, *T);
}
return this->emitNull(classifyPrim(CE->getType()), Desc, CE);
}

case CK_PointerToIntegral: {
if (DiscardResult)
Expand All @@ -199,6 +207,41 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return true;
}

case CK_IntegralToPointer: {
QualType IntType = SubExpr->getType();
assert(IntType->isIntegralOrEnumerationType());
if (!this->visit(SubExpr))
return false;
// FIXME: I think the discard is wrong since the int->ptr cast might cause a
// diagnostic.
PrimType T = classifyPrim(IntType);
if (DiscardResult)
return this->emitPop(T, CE);

QualType PtrType = CE->getType();
assert(PtrType->isPointerType());

const Descriptor *Desc;
if (std::optional<PrimType> T = classify(PtrType->getPointeeType()))
Desc = P.createDescriptor(SubExpr, *T);
else if (PtrType->getPointeeType()->isVoidType())
Desc = nullptr;
else
Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(),
Descriptor::InlineDescMD, true, false,
/*IsMutable=*/false, nullptr);

if (!this->emitGetIntPtr(T, Desc, CE))
return false;

PrimType DestPtrT = classifyPrim(PtrType);
if (DestPtrT == PT_Ptr)
return true;

// In case we're converting the integer to a non-Pointer.
return this->emitDecayPtr(PT_Ptr, DestPtrT, CE);
}

case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
case CK_FunctionToPointerDecay:
Expand All @@ -207,13 +250,31 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_UserDefinedConversion:
return this->delegate(SubExpr);

case CK_BitCast:
case CK_BitCast: {
// Reject bitcasts to atomic types.
if (CE->getType()->isAtomicType()) {
if (!this->discard(SubExpr))
return false;
return this->emitInvalidCast(CastKind::Reinterpret, CE);
}
return this->delegate(SubExpr);

if (DiscardResult)
return this->discard(SubExpr);

std::optional<PrimType> FromT = classify(SubExpr->getType());
std::optional<PrimType> ToT = classifyPrim(CE->getType());
if (!FromT || !ToT)
return false;

assert(isPtrType(*FromT));
assert(isPtrType(*ToT));
if (FromT == ToT)
return this->delegate(SubExpr);

if (!this->visit(SubExpr))
return false;
return this->emitDecayPtr(*FromT, *ToT, CE);
}

case CK_IntegralToBoolean:
case CK_IntegralCast: {
Expand Down Expand Up @@ -245,7 +306,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (!this->visit(SubExpr))
return false;

if (!this->emitNull(PtrT, CE))
if (!this->emitNull(PtrT, nullptr, CE))
return false;

return this->emitNE(PtrT, CE);
Expand Down Expand Up @@ -455,7 +516,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {

// Pointer arithmetic special case.
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr))
if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT)))
return this->VisitPointerArithBinOp(BO);
}

Expand Down Expand Up @@ -1033,6 +1094,34 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}

if (const auto *VecT = E->getType()->getAs<VectorType>()) {
unsigned NumVecElements = VecT->getNumElements();
assert(NumVecElements >= E->getNumInits());

QualType ElemQT = VecT->getElementType();
PrimType ElemT = classifyPrim(ElemQT);

// All initializer elements.
unsigned InitIndex = 0;
for (const Expr *Init : E->inits()) {
if (!this->visit(Init))
return false;

if (!this->emitInitElem(ElemT, InitIndex, E))
return false;
++InitIndex;
}

// Fill the rest with zeroes.
for (; InitIndex != NumVecElements; ++InitIndex) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, InitIndex, E))
return false;
}
return true;
}

return false;
}

Expand Down Expand Up @@ -2326,7 +2415,7 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {

// Convert pointers to bool.
if (T == PT_Ptr || T == PT_FnPtr) {
if (!this->emitNull(*T, E))
if (!this->emitNull(*T, nullptr, E))
return false;
return this->emitNE(*T, E);
}
Expand Down Expand Up @@ -2366,9 +2455,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
case PT_IntAPS:
return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E);
case PT_Ptr:
return this->emitNullPtr(E);
return this->emitNullPtr(nullptr, E);
case PT_FnPtr:
return this->emitNullFnPtr(E);
return this->emitNullFnPtr(nullptr, E);
case PT_Float: {
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
}
Expand Down Expand Up @@ -2952,7 +3041,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
if (DiscardResult)
return true;

return this->emitNullPtr(E);
return this->emitNullPtr(nullptr, E);
}

template <class Emitter>
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody(
// one here, and we don't need one either because the lambda cannot have
// any captures, as verified above. Emit a null pointer. This is then
// special-cased when interpreting to not emit any misleading diagnostics.
if (!this->emitNullPtr(MD))
if (!this->emitNullPtr(nullptr, MD))
return false;

// Forward all arguments from the static invoker to the lambda call operator.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isBooleanType())
return PT_Bool;

if (T->isAnyComplexType())
// We map these to primitive arrays.
if (T->isAnyComplexType() || T->isVectorType())
return std::nullopt;

if (T->isSignedIntegerOrEnumerationType()) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ struct Descriptor final {

const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
const DeclTy &getSource() const { return Source; }

const ValueDecl *asValueDecl() const {
return dyn_cast_if_present<ValueDecl>(asDecl());
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
this->CheckFullyInitialized = CheckFullyInitialized;
this->ConvertResultToRValue =
VD->getAnyInitializer() &&
(VD->getAnyInitializer()->getType()->isAnyComplexType());
(VD->getAnyInitializer()->getType()->isAnyComplexType() ||
VD->getAnyInitializer()->getType()->isVectorType());
EvalResult.setSource(VD);

if (!this->visitDecl(VD) && EvalResult.empty())
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ class FunctionPointer final {
const Function *Func;

public:
FunctionPointer() : Func(nullptr) {}
// FIXME: We might want to track the fact that the Function pointer
// has been created from an integer and is most likely garbage anyway.
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)) {}

FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }

const Function *getFunction() const { return Func; }
Expand Down Expand Up @@ -53,6 +57,10 @@ class FunctionPointer final {
return toAPValue().getAsString(Ctx, Func->getDecl()->getType());
}

uint64_t getIntegerRepresentation() const {
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Func));
}

ComparisonCategoryResult compare(const FunctionPointer &RHS) const {
if (Func == RHS.Func)
return ComparisonCategoryResult::Equal;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
}

static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (Ptr.isIntegralPointer())
return true;
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
}

Expand Down Expand Up @@ -335,6 +337,9 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}

if (!Ptr.isBlockPointer())
return false;

const QualType Ty = Ptr.getType();
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
Expand Down
85 changes: 60 additions & 25 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -804,8 +804,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
for (const auto &P : {LHS, RHS}) {
if (P.isZero())
continue;
if (const ValueDecl *VD = P.getDeclDesc()->asValueDecl();
VD && VD->isWeak()) {
if (P.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< P.toDiagnosticString(S.getCtx());
Expand All @@ -824,9 +823,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
// element in the same array are NOT equal. They have the same Base value,
// but a different Offset. This is a pretty rare case, so we fix this here
// by comparing pointers to the first elements.
if (!LHS.isDummy() && LHS.isArrayRoot())
if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
VL = LHS.atIndex(0).getByteOffset();
if (!RHS.isDummy() && RHS.isArrayRoot())
if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
VR = RHS.atIndex(0).getByteOffset();

S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
Expand Down Expand Up @@ -1387,6 +1386,8 @@ bool Load(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
if (!Ptr.isBlockPointer())
return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand All @@ -1396,6 +1397,8 @@ bool LoadPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
if (!Ptr.isBlockPointer())
return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand Down Expand Up @@ -1534,8 +1537,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
return true;
}

if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
return false;
if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
// The CheckNull will have emitted a note already, but we only
// abort in C++, since this is fine in C.
if (S.getLangOpts().CPlusPlus)
return false;
}

// Arrays of unknown bounds cannot have pointers into them.
if (!CheckArray(S, OpPC, Ptr))
Expand All @@ -1561,23 +1568,25 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
Invalid = true;
};

T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
if constexpr (Op == ArithOp::Add) {
// If the new offset would be negative, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isPositive() && Offset > MaxOffset)
DiagInvalidOffset();
} else {
// If the new offset would be negative, bail out.
if (Offset.isPositive() && Index < Offset)
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
DiagInvalidOffset();
if (Ptr.isBlockPointer()) {
T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
if constexpr (Op == ArithOp::Add) {
// If the new offset would be negative, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isPositive() && Offset > MaxOffset)
DiagInvalidOffset();
} else {
// If the new offset would be negative, bail out.
if (Offset.isPositive() && Index < Offset)
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
DiagInvalidOffset();
}
}

if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
Expand Down Expand Up @@ -1661,6 +1670,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &RHS = S.Stk.pop<Pointer>();

if (RHS.isZero()) {
S.Stk.push<T>(T::from(LHS.getIndex()));
return true;
}

if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
// TODO: Diagnose.
return false;
Expand Down Expand Up @@ -1839,8 +1853,9 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool Null(InterpState &S, CodePtr OpPC) {
S.Stk.push<T>();
inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
// Note: Desc can be null.
S.Stk.push<T>(0, Desc);
return true;
}

Expand Down Expand Up @@ -2244,6 +2259,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
const T &IntVal = S.Stk.pop<T>();

S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
return true;
}

/// Just emit a diagnostic. The expression that caused emission of this
/// op is not valid in a constant context.
inline bool Invalid(InterpState &S, CodePtr OpPC) {
Expand Down Expand Up @@ -2300,6 +2323,18 @@ inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
return false;
}

/// OldPtr -> Integer -> NewPtr.
template <PrimType TIn, PrimType TOut>
inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
static_assert(isPtrType(TIn) && isPtrType(TOut));
using FromT = typename PrimConv<TIn>::T;
using ToT = typename PrimConv<TOut>::T;

const FromT &OldPtr = S.Stk.pop<FromT>();
S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
return true;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/InterpBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void Block::replacePointer(Pointer *Old, Pointer *New) {
removePointer(Old);
addPointer(New);

Old->Pointee = nullptr;
Old->PointeeStorage.BS.Pointee = nullptr;

#ifndef NDEBUG
assert(!hasPointer(Old));
Expand Down Expand Up @@ -104,7 +104,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
// Transfer pointers.
B.Pointers = Blk->Pointers;
for (Pointer *P = Blk->Pointers; P; P = P->Next)
P->Pointee = &B;
P->PointeeStorage.BS.Pointee = &B;
}

void DeadBlock::free() {
Expand Down
46 changes: 40 additions & 6 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
namespace clang {
namespace interp {

static unsigned callArgSize(const InterpState &S, const CallExpr *C) {
unsigned O = 0;

for (const Expr *E : C->arguments()) {
O += align(primSize(*S.getContext().classify(E)));
}

return O;
}

template <typename T>
static T getParam(const InterpFrame *Frame, unsigned Index) {
assert(Frame->getFunction()->getNumParams() > Index);
Expand Down Expand Up @@ -816,18 +826,30 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
unsigned CallSize = callArgSize(S, Call);
unsigned BuiltinOp = Func->getBuiltinID();
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);

// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
BuiltinOp != Builtin::BI__lzcnt &&
BuiltinOp != Builtin::BI__lzcnt64;

if (ZeroIsUndefined && Val == 0)
return false;
if (Val == 0) {
if (Func->getBuiltinID() == Builtin::BI__builtin_clzg &&
Call->getNumArgs() == 2) {
// We have a fallback parameter.
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
pushInteger(S, Fallback, Call->getType());
return true;
}

if (ZeroIsUndefined)
return false;
}

pushInteger(S, Val.countl_zero(), Call->getType());
return true;
Expand All @@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
unsigned CallSize = callArgSize(S, Call);
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);

if (Val == 0)
const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);

if (Val == 0) {
if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg &&
Call->getNumArgs() == 2) {
// We have a fallback parameter.
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
pushInteger(S, Fallback, Call->getType());
return true;
}
return false;
}

pushInteger(S, Val.countr_zero(), Call->getType());
return true;
Expand Down Expand Up @@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll:
case Builtin::BI__builtin_clzs:
case Builtin::BI__builtin_clzg:
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
case Builtin::BI__lzcnt:
case Builtin::BI__lzcnt64:
Expand All @@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
case Builtin::BI__builtin_ctzs:
case Builtin::BI__builtin_ctzg:
if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
return false;
break;
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def ArgCastKind : ArgType { let Name = "CastKind"; }
def ArgCallExpr : ArgType { let Name = "const CallExpr *"; }
def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -272,6 +273,7 @@ def ZeroIntAPS : Opcode {
// [] -> [Pointer]
def Null : Opcode {
let Types = [PtrTypeClass];
let Args = [ArgDesc];
let HasGroup = 1;
}

Expand Down Expand Up @@ -530,6 +532,11 @@ def GetFnPtr : Opcode {
let Args = [ArgFunction];
}

def GetIntPtr : Opcode {
let Types = [AluTypeClass];
let Args = [ArgDesc];
let HasGroup = 1;
}

//===----------------------------------------------------------------------===//
// Binary operators.
Expand Down Expand Up @@ -662,6 +669,11 @@ def CastPointerIntegral : Opcode {
let HasGroup = 1;
}

def DecayPtr : Opcode {
let Types = [PtrTypeClass, PtrTypeClass];
let HasGroup = 1;
}

//===----------------------------------------------------------------------===//
// Comparison opcodes.
//===----------------------------------------------------------------------===//
Expand Down
187 changes: 148 additions & 39 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,60 +26,95 @@ Pointer::Pointer(Block *Pointee)
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
Pointer::Pointer(const Pointer &P)
: Offset(P.Offset), PointeeStorage(P.PointeeStorage),
StorageKind(P.StorageKind) {

Pointer::Pointer(Pointer &&P)
: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
if (Pointee)
Pointee->replacePointer(&P, this);
if (isBlockPointer() && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);
}

Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
: Pointee(Pointee), Base(Base), Offset(Offset) {
: Offset(Offset), StorageKind(Storage::Block) {
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");

PointeeStorage.BS = {Pointee, Base};

if (Pointee)
Pointee->addPointer(this);
}

Pointer::Pointer(Pointer &&P)
: Offset(P.Offset), PointeeStorage(P.PointeeStorage),
StorageKind(P.StorageKind) {

if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->replacePointer(&P, this);
}

Pointer::~Pointer() {
if (Pointee) {
Pointee->removePointer(this);
Pointee->cleanup();
if (isIntegralPointer())
return;

if (PointeeStorage.BS.Pointee) {
PointeeStorage.BS.Pointee->removePointer(this);
PointeeStorage.BS.Pointee->cleanup();
}
}

void Pointer::operator=(const Pointer &P) {
Block *Old = Pointee;

if (Pointee)
Pointee->removePointer(this);
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind);

Offset = P.Offset;
Base = P.Base;
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->removePointer(this);

Pointee = P.Pointee;
if (Pointee)
Pointee->addPointer(this);
Offset = P.Offset;
PointeeStorage.BS = P.PointeeStorage.BS;

if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (WasBlockPointer && Old)
Old->cleanup();

if (Old)
Old->cleanup();
} else if (StorageKind == Storage::Int) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
}
}

void Pointer::operator=(Pointer &&P) {
Block *Old = Pointee;
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind);

if (Pointee)
Pointee->removePointer(this);
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->removePointer(this);

Offset = P.Offset;
Base = P.Base;
Offset = P.Offset;
PointeeStorage.BS = P.PointeeStorage.BS;

Pointee = P.Pointee;
if (Pointee)
Pointee->replacePointer(&P, this);
if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (WasBlockPointer && Old)
Old->cleanup();

if (Old)
Old->cleanup();
} else if (StorageKind == Storage::Int) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
}
}

APValue Pointer::toAPValue() const {
Expand All @@ -88,6 +123,11 @@ APValue Pointer::toAPValue() const {
if (isZero())
return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
if (isIntegralPointer())
return APValue(static_cast<const Expr *>(nullptr),
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);

// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
Expand Down Expand Up @@ -137,19 +177,52 @@ APValue Pointer::toAPValue() const {
return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false);
}

void Pointer::print(llvm::raw_ostream &OS) const {
OS << PointeeStorage.BS.Pointee << " (";
if (isBlockPointer()) {
OS << "Block) {";

if (PointeeStorage.BS.Base == RootPtrMark)
OS << "rootptr, ";
else
OS << PointeeStorage.BS.Base << ", ";

if (Offset == PastEndMark)
OS << "pastend, ";
else
OS << Offset << ", ";

if (isBlockPointer() && PointeeStorage.BS.Pointee)
OS << PointeeStorage.BS.Pointee->getSize();
else
OS << "nullptr";
} else {
OS << "Int) {";
OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
}
OS << "}";
}

std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
if (!Pointee)
if (isZero())
return "nullptr";

if (isIntegralPointer())
return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();

return toAPValue().getAsString(Ctx, getType());
}

bool Pointer::isInitialized() const {
assert(Pointee && "Cannot check if null pointer was initialized");
if (isIntegralPointer())
return true;

assert(PointeeStorage.BS.Pointee &&
"Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
if (isStatic() && Base == 0)
if (isStatic() && PointeeStorage.BS.Base == 0)
return true;

InitMapPtr &IM = getInitMap();
Expand All @@ -164,17 +237,20 @@ bool Pointer::isInitialized() const {
}

// Field has its bit in an inline descriptor.
return Base == 0 || getInlineDesc()->IsInitialized;
return PointeeStorage.BS.Base == 0 || getInlineDesc()->IsInitialized;
}

void Pointer::initialize() const {
assert(Pointee && "Cannot initialize null pointer");
if (isIntegralPointer())
return;

assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
const Descriptor *Desc = getFieldDesc();

assert(Desc);
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
if (isStatic() && Base == 0)
if (isStatic() && PointeeStorage.BS.Base == 0)
return;

// Nothing to do for these.
Expand All @@ -200,13 +276,15 @@ void Pointer::initialize() const {
}

// Field has its bit in an inline descriptor.
assert(Base != 0 && "Only composite fields can be initialised");
assert(PointeeStorage.BS.Base != 0 &&
"Only composite fields can be initialised");
getInlineDesc()->IsInitialized = true;
}

void Pointer::activate() const {
// Field has its bit in an inline descriptor.
assert(Base != 0 && "Only composite fields can be initialised");
assert(PointeeStorage.BS.Base != 0 &&
"Only composite fields can be initialised");
getInlineDesc()->IsActive = true;
}

Expand All @@ -215,11 +293,23 @@ void Pointer::deactivate() const {
}

bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
return A.Pointee == B.Pointee;
// Two null pointers always have the same base.
if (A.isZero() && B.isZero())
return true;

if (A.isIntegralPointer() && B.isIntegralPointer())
return true;

if (A.isIntegralPointer() || B.isIntegralPointer())
return A.getSource() == B.getSource();

return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
}

bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
return hasSameBase(A, B) &&
A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
A.getFieldDesc()->IsArray;
}

std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
Expand Down Expand Up @@ -342,6 +432,25 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
return false;
}

// Vector types.
if (const auto *VT = Ty->getAs<VectorType>()) {
assert(Ptr.getFieldDesc()->isPrimitiveArray());
QualType ElemTy = VT->getElementType();
PrimType ElemT = *Ctx.classify(ElemTy);

SmallVector<APValue> Values;
Values.reserve(VT->getNumElements());
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
TYPE_SWITCH(ElemT, {
Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue());
});
}

assert(Values.size() == VT->getNumElements());
R = APValue(Values.data(), Values.size());
return true;
}

llvm_unreachable("invalid value to return");
};

Expand Down
383 changes: 279 additions & 104 deletions clang/lib/AST/Interp/Pointer.h

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ enum PrimType : unsigned {
PT_FnPtr,
};

inline constexpr bool isPtrType(PrimType T) {
return T == PT_Ptr || T == PT_FnPtr;
}

enum class CastKind : uint8_t {
Reinterpret,
Atomic,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,5 +411,12 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
IsMutable);
}

// Same with vector types.
if (const auto *VT = Ty->getAs<VectorType>()) {
PrimType ElemTy = *Ctx.classify(VT->getElementType());
return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst,
IsTemporary, IsMutable);
}

return nullptr;
}
19 changes: 19 additions & 0 deletions clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@
#include "clang/AST/ASTContext.h"

using namespace clang;

OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C,
OpenACCDefaultClauseKind K,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
void *Mem =
C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause));

return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc);
}

//===----------------------------------------------------------------------===//
// OpenACC clauses printing methods
//===----------------------------------------------------------------------===//
void OpenACCClausePrinter::VisitOpenACCDefaultClause(
const OpenACCDefaultClause &C) {
OS << "default(" << C.getDefaultClauseKind() << ")";
}
25 changes: 22 additions & 3 deletions clang/lib/AST/ParentMapContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,26 @@ class ParentMapContext::ParentMap {
template <typename, typename...> friend struct ::MatchParents;

/// Contains parents of a node.
using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
class ParentVector {
public:
ParentVector() = default;
explicit ParentVector(size_t N, const DynTypedNode &Value) {
Items.reserve(N);
for (; N > 0; --N)
push_back(Value);
}
bool contains(const DynTypedNode &Value) {
return Seen.contains(Value);
}
void push_back(const DynTypedNode &Value) {
if (!Value.getMemoizationData() || Seen.insert(Value).second)
Items.push_back(Value);
}
llvm::ArrayRef<DynTypedNode> view() const { return Items; }
private:
llvm::SmallVector<DynTypedNode, 2> Items;
llvm::SmallDenseSet<DynTypedNode, 2> Seen;
};

/// Maps from a node to its parents. This is used for nodes that have
/// pointer identity only, which are more common and we can save space by
Expand Down Expand Up @@ -99,7 +118,7 @@ class ParentMapContext::ParentMap {
return llvm::ArrayRef<DynTypedNode>();
}
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
return llvm::ArrayRef(*V);
return V->view();
}
return getSingleDynTypedNodeFromParentMap(I->second);
}
Expand Down Expand Up @@ -252,7 +271,7 @@ class ParentMapContext::ParentMap {
const auto *S = It->second.dyn_cast<const Stmt *>();
if (!S) {
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
return llvm::ArrayRef(*Vec);
return Vec->view();
return getSingleDynTypedNodeFromParentMap(It->second);
}
const auto *P = dyn_cast<Expr>(S);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/StmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C,
OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
const HelperExprs &Exprs, bool CanBeParallelFor) {
auto *Dir = createDirective<OMPTargetTeamsGenericLoopDirective>(
C, Clauses, AssociatedStmt,
numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc,
Expand Down Expand Up @@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond);
Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond);
Dir->setCanBeParallelFor(CanBeParallelFor);
return Dir;
}

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2456,7 +2456,12 @@ class OpenACCClauseProfiler
Visit(Clause);
}
}
void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
};

/// Nothing to do here, there are no sub-statements.
void OpenACCClauseProfiler::VisitOpenACCDefaultClause(
const OpenACCDefaultClause &Clause) {}
} // namespace

void StmtProfiler::VisitOpenACCComputeConstruct(
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,17 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
{
ColorScope Color(OS, ShowColors, AttrColor);
OS << C->getClauseKind();

// Handle clauses with parens for types that have no children, likely
// because there is no sub expression.
switch (C->getClauseKind()) {
case OpenACCClauseKind::Default:
OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
break;
default:
// Nothing to do here.
break;
}
}
dumpPointer(C);
dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,10 +1213,13 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {

void TypePrinter::printPackIndexingBefore(const PackIndexingType *T,
raw_ostream &OS) {
if (T->hasSelectedType())
if (T->hasSelectedType()) {
OS << T->getSelectedType();
else
OS << T->getPattern() << "...[" << T->getIndexExpr() << "]";
} else {
OS << T->getPattern() << "...[";
T->getIndexExpr()->printPretty(OS, nullptr, Policy);
OS << "]";
}
spaceBeforePlaceHolder(OS);
}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,10 +1543,13 @@ WindowsARM64TargetInfo::getBuiltinVaListKind() const {
TargetInfo::CallingConvCheckResult
WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
case CC_X86VectorCall:
if (getTriple().isWindowsArm64EC())
return CCCR_OK;
return CCCR_Ignore;
case CC_X86StdCall:
case CC_X86ThisCall:
case CC_X86FastCall:
case CC_X86VectorCall:
return CCCR_Ignore;
case CC_C:
case CC_OpenCLKernel:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5591,6 +5591,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
/*AttrOnCallSite=*/true,
/*IsThunk=*/false);

if (CallingConv == llvm::CallingConv::X86_VectorCall &&
getTarget().getTriple().isWindowsArm64EC()) {
CGM.Error(Loc, "__vectorcall calling convention is not currently "
"supported");
}

if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// - whether there's a fallthrough
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
bool HasFallthrough =
FallthroughSource != nullptr && (IsActive || HasExistingBranches);

// Branch-through fall-throughs leave the insertion point set to the
// end of the last cleanup, which points to the current scope. The
Expand All @@ -692,7 +693,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// If we have a prebranched fallthrough into an inactive normal
// cleanup, rewrite it so that it leads to the appropriate place.
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough &&
!RequiresNormalCleanup) {
// FIXME: Come up with a program which would need forwarding prebranched
// fallthrough and add tests. Otherwise delete this and assert against it.
assert(!IsActive);
llvm::BasicBlock *prebranchDest;

// If the prebranch is semantically branching through the next
Expand Down Expand Up @@ -765,6 +770,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EmitSehCppScopeEnd();
}
destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();
} else {
// If we have a fallthrough and no other need for the cleanup,
Expand All @@ -781,6 +787,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();

EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
Expand Down Expand Up @@ -916,6 +923,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

// IV. Pop the cleanup and emit it.
Scope.MarkEmitted();
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);

Expand Down
57 changes: 56 additions & 1 deletion clang/lib/CodeGen/CGCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#include "EHScopeStack.h"

#include "Address.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Instruction.h"

namespace llvm {
class BasicBlock;
Expand Down Expand Up @@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope {
};
mutable struct ExtInfo *ExtInfo;

/// Erases auxillary allocas and their usages for an unused cleanup.
/// Cleanups should mark these allocas as 'used' if the cleanup is
/// emitted, otherwise these instructions would be erased.
struct AuxillaryAllocas {
SmallVector<llvm::Instruction *, 1> AuxAllocas;
bool used = false;

// Records a potentially unused instruction to be erased later.
void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); }

// Mark all recorded instructions as used. These will not be erased later.
void MarkUsed() {
used = true;
AuxAllocas.clear();
}

~AuxillaryAllocas() {
if (used)
return;
llvm::SetVector<llvm::Instruction *> Uses;
for (auto *Inst : llvm::reverse(AuxAllocas))
CollectUses(Inst, Uses);
// Delete uses in the reverse order of insertion.
for (auto *I : llvm::reverse(Uses))
I->eraseFromParent();
}

private:
void CollectUses(llvm::Instruction *I,
llvm::SetVector<llvm::Instruction *> &Uses) {
if (!I || !Uses.insert(I))
return;
for (auto *User : I->users())
CollectUses(cast<llvm::Instruction>(User), Uses);
}
};
mutable struct AuxillaryAllocas *AuxAllocas;

AuxillaryAllocas &getAuxillaryAllocas() {
if (!AuxAllocas) {
AuxAllocas = new struct AuxillaryAllocas();
}
return *AuxAllocas;
}

/// The number of fixups required by enclosing scopes (not including
/// this one). If this is the top cleanup scope, all the fixups
/// from this index onwards belong to this scope.
Expand Down Expand Up @@ -298,7 +346,7 @@ class alignas(8) EHCleanupScope : public EHScope {
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH),
EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr),
FixupDepth(fixupDepth) {
CleanupBits.IsNormalCleanup = isNormal;
CleanupBits.IsEHCleanup = isEH;
Expand All @@ -312,8 +360,15 @@ class alignas(8) EHCleanupScope : public EHScope {
}

void Destroy() {
if (AuxAllocas)
delete AuxAllocas;
delete ExtInfo;
}
void AddAuxAllocas(llvm::SmallVector<llvm::AllocaInst *> Allocas) {
for (auto *Alloca : Allocas)
getAuxillaryAllocas().Add(Alloca);
}
void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); }
// Objects of EHCleanupScope are not destructed. Use Destroy().
~EHCleanupScope() = delete;

Expand Down
58 changes: 39 additions & 19 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "EHScopeStack.h"
#include "PatternInit.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -2201,6 +2202,24 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
destroyer, useEHCleanupForArray);
}

// Pushes a destroy and defers its deactivation until its
// CleanupDeactivationScope is exited.
void CodeGenFunction::pushDestroyAndDeferDeactivation(
QualType::DestructionKind dtorKind, Address addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");

CleanupKind cleanupKind = getCleanupKind(dtorKind);
pushDestroyAndDeferDeactivation(
cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
}

void CodeGenFunction::pushDestroyAndDeferDeactivation(
CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
pushCleanupAndDeferDeactivation<DestroyObject>(
cleanupKind, addr, type, destroyer, useEHCleanupForArray);
}

void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
}
Expand All @@ -2217,16 +2236,19 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
// If we're not in a conditional branch, we don't need to bother generating a
// conditional cleanup.
if (!isInConditionalBranch()) {
// Push an EH-only cleanup for the object now.
// FIXME: When popping normal cleanups, we need to keep this EH cleanup
// around in case a temporary's destructor throws an exception.
if (cleanupKind & EHCleanup)
EHStack.pushCleanup<DestroyObject>(
static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
destroyer, useEHCleanupForArray);

// Add the cleanup to the EHStack. After the full-expr, this would be
// deactivated before being popped from the stack.
pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
useEHCleanupForArray);

// Since this is lifetime-extended, push it once again to the EHStack after
// the full expression.
return pushCleanupAfterFullExprWithActiveFlag<DestroyObject>(
cleanupKind, Address::invalid(), addr, type, destroyer, useEHCleanupForArray);
cleanupKind, Address::invalid(), addr, type, destroyer,
useEHCleanupForArray);
}

// Otherwise, we should only destroy the object if it's been initialized.
Expand All @@ -2241,13 +2263,12 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
Address ActiveFlag = createCleanupActiveFlag();
SavedType SavedAddr = saveValueInCond(addr);

if (cleanupKind & EHCleanup) {
EHStack.pushCleanup<ConditionalCleanupType>(
static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), SavedAddr, type,
destroyer, useEHCleanupForArray);
initFullExprCleanupWithFlag(ActiveFlag);
}
pushCleanupAndDeferDeactivation<ConditionalCleanupType>(
cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray);
initFullExprCleanupWithFlag(ActiveFlag);

// Since this is lifetime-extended, push it once again to the EHStack after
// the full expression.
pushCleanupAfterFullExprWithActiveFlag<ConditionalCleanupType>(
cleanupKind, ActiveFlag, SavedAddr, type, destroyer,
useEHCleanupForArray);
Expand Down Expand Up @@ -2442,9 +2463,9 @@ namespace {
};
} // end anonymous namespace

/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
/// already-constructed elements of the given array. The cleanup
/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
/// pushIrregularPartialArrayCleanup - Push a NormalAndEHCleanup to
/// destroy already-constructed elements of the given array. The cleanup may be
/// popped with DeactivateCleanupBlock or PopCleanupBlock.
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
Expand All @@ -2453,10 +2474,9 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
QualType elementType,
CharUnits elementAlign,
Destroyer *destroyer) {
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer,
elementType, elementAlign,
destroyer);
pushFullExprCleanup<IrregularPartialArrayDestroy>(
NormalAndEHCleanup, arrayBegin, arrayEndPointer, elementType,
elementAlign, destroyer);
}

/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,16 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
const Twine &Name,
llvm::Value *ArraySize) {
llvm::AllocaInst *Alloca;
if (ArraySize)
return Builder.CreateAlloca(Ty, ArraySize, Name);
return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
ArraySize, Name, AllocaInsertPt);
Alloca = Builder.CreateAlloca(Ty, ArraySize, Name);
else
Alloca = new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
ArraySize, Name, AllocaInsertPt);
if (Allocas) {
Allocas->Add(Alloca);
}
return Alloca;
}

/// CreateDefaultAlignTempAlloca - This creates an alloca with the
Expand Down
87 changes: 26 additions & 61 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "EHScopeStack.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
Expand All @@ -24,6 +25,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
using namespace clang;
Expand Down Expand Up @@ -558,24 +560,27 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// For that, we'll need an EH cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
Address endOfInit = Address::invalid();
EHScopeStack::stable_iterator cleanup;
llvm::Instruction *cleanupDominator = nullptr;
if (CGF.needsEHCleanup(dtorKind)) {
CodeGenFunction::CleanupDeactivationScope deactivation(CGF);

if (dtorKind) {
CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF);
// In principle we could tell the cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
llvm::Instruction *dominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(CGF.Int8PtrTy));
endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
"arrayinit.endOfInit");
cleanupDominator = Builder.CreateStore(begin, endOfInit);
Builder.CreateStore(begin, endOfInit);
CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
cleanup = CGF.EHStack.stable_begin();
cast<EHCleanupScope>(*CGF.EHStack.find(CGF.EHStack.stable_begin()))
.AddAuxAllocas(allocaTracker.Take());

// Otherwise, remember that we didn't need a cleanup.
} else {
dtorKind = QualType::DK_none;
CGF.DeferredDeactivationCleanupStack.push_back(
{CGF.EHStack.stable_begin(), dominatingIP});
}

llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
Expand Down Expand Up @@ -671,9 +676,6 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,

CGF.EmitBlock(endBB);
}

// Leave the partial-array cleanup if we entered one.
if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1374,9 +1376,8 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType());

// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> Cleanups;
llvm::Instruction *CleanupDominator = nullptr;
// initializers throws an exception or contains branch out of the expressions.
CodeGenFunction::CleanupDeactivationScope scope(CGF);

CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
Expand All @@ -1395,28 +1396,12 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
if (QualType::DestructionKind DtorKind =
CurField->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(DtorKind)) {
if (!CleanupDominator)
CleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty,
llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One()); // placeholder

CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
Cleanups.push_back(CGF.EHStack.stable_begin());
}
if (DtorKind)
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
}
}

// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
for (unsigned i = Cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator);

// Destroy the placeholder if we made one.
if (CleanupDominator)
CleanupDominator->eraseFromParent();
}

void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
Expand Down Expand Up @@ -1705,14 +1690,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
llvm::Instruction *cleanupDominator = nullptr;
auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) {
cleanups.push_back(cleanup);
if (!cleanupDominator) // create placeholder once needed
cleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One());
};
CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF);

unsigned curInitIndex = 0;

Expand All @@ -1735,10 +1713,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);

if (QualType::DestructionKind dtorKind =
Base.getType().isDestructedType()) {
CGF.pushDestroy(dtorKind, V, Base.getType());
addCleanup(CGF.EHStack.stable_begin());
}
Base.getType().isDestructedType())
CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType());
}
}

Expand Down Expand Up @@ -1813,10 +1789,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (QualType::DestructionKind dtorKind
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
addCleanup(CGF.EHStack.stable_begin());
if (dtorKind) {
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
pushedCleanup = true;
}
}
Expand All @@ -1829,17 +1805,6 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (GEP->use_empty())
GEP->eraseFromParent();
}

// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
assert((cleanupDominator || cleanups.empty()) &&
"Missing cleanupDominator before deactivating cleanup blocks");
for (unsigned i = cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);

// Destroy the placeholder if we made one.
if (cleanupDominator)
cleanupDominator->eraseFromParent();
}

void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
Expand Down
38 changes: 19 additions & 19 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1008,8 +1008,8 @@ void CodeGenFunction::EmitNewArrayInitializer(
const Expr *Init = E->getInitializer();
Address EndOfInit = Address::invalid();
QualType::DestructionKind DtorKind = ElementType.isDestructedType();
EHScopeStack::stable_iterator Cleanup;
llvm::Instruction *CleanupDominator = nullptr;
CleanupDeactivationScope deactivation(*this);
bool pushedCleanup = false;

CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType);
CharUnits ElementAlign =
Expand Down Expand Up @@ -1105,19 +1105,24 @@ void CodeGenFunction::EmitNewArrayInitializer(
}

// Enter a partial-destruction Cleanup if necessary.
if (needsEHCleanup(DtorKind)) {
if (DtorKind) {
AllocaTrackerRAII AllocaTracker(*this);
// In principle we could tell the Cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(),
"array.init.end");
CleanupDominator =
Builder.CreateStore(BeginPtr.emitRawPointer(*this), EndOfInit);
pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
EndOfInit, ElementType, ElementAlign,
getDestroyer(DtorKind));
Cleanup = EHStack.stable_begin();
cast<EHCleanupScope>(*EHStack.find(EHStack.stable_begin()))
.AddAuxAllocas(AllocaTracker.Take());
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
pushedCleanup = true;
}

CharUnits StartAlign = CurPtr.getAlignment();
Expand Down Expand Up @@ -1164,9 +1169,6 @@ void CodeGenFunction::EmitNewArrayInitializer(
// initialization.
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
// If there was a Cleanup, deactivate it.
if (CleanupDominator)
DeactivateCleanupBlock(Cleanup, CleanupDominator);
return;
}

Expand Down Expand Up @@ -1281,24 +1283,22 @@ void CodeGenFunction::EmitNewArrayInitializer(
Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit);

// Enter a partial-destruction Cleanup if necessary.
if (!CleanupDominator && needsEHCleanup(DtorKind)) {
llvm::Value *BeginPtrRaw = BeginPtr.emitRawPointer(*this);
llvm::Value *CurPtrRaw = CurPtr.emitRawPointer(*this);
pushRegularPartialArrayCleanup(BeginPtrRaw, CurPtrRaw, ElementType,
if (!pushedCleanup && needsEHCleanup(DtorKind)) {
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
pushRegularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
CurPtr.emitRawPointer(*this), ElementType,
ElementAlign, getDestroyer(DtorKind));
Cleanup = EHStack.stable_begin();
CleanupDominator = Builder.CreateUnreachable();
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

// Emit the initializer into this element.
StoreAnyExprIntoOneUnit(*this, Init, Init->getType(), CurPtr,
AggValueSlot::DoesNotOverlap);

// Leave the Cleanup if we entered one.
if (CleanupDominator) {
DeactivateCleanupBlock(Cleanup, CleanupDominator);
CleanupDominator->eraseFromParent();
}
deactivation.ForceDeactivate();

// Advance to the next element by adjusting the pointer type as necessary.
llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32(
Expand Down
15 changes: 9 additions & 6 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2656,11 +2656,12 @@ void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc,
isOpenMPDistributeDirective(DKind)
isOpenMPDistributeDirective(DKind) ||
(DKind == OMPD_target_teams_loop)
? OMP_IDENT_WORK_DISTRIBUTE
: isOpenMPLoopDirective(DKind)
? OMP_IDENT_WORK_LOOP
: OMP_IDENT_WORK_SECTIONS),
: isOpenMPLoopDirective(DKind)
? OMP_IDENT_WORK_LOOP
: OMP_IDENT_WORK_SECTIONS),
getThreadID(CGF, Loc)};
auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc);
if (isOpenMPDistributeDirective(DKind) &&
Expand Down Expand Up @@ -8885,7 +8886,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
switch (D.getDirectiveKind()) {
case OMPD_target:
// For now, just treat 'target teams loop' as if it's distributed.
// For now, treat 'target' with nested 'teams loop' as if it's
// distributed (target teams distribute).
if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
return NestedDir;
if (DKind == OMPD_teams) {
Expand Down Expand Up @@ -9369,7 +9371,8 @@ llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall(
SizeEmitter) {
OpenMPDirectiveKind Kind = D.getDirectiveKind();
const OMPExecutableDirective *TD = &D;
// Get nested teams distribute kind directive, if any.
// Get nested teams distribute kind directive, if any. For now, treat
// 'target_teams_loop' as if it's really a target_teams_distribute.
if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
Kind != OMPD_target_teams_loop)
TD = getNestedDistributeDirective(CGM.getContext(), D);
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,6 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
case OMPD_target:
case OMPD_target_teams:
return hasNestedSPMDDirective(Ctx, D);
case OMPD_target_teams_loop:
case OMPD_target_parallel_loop:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
Expand All @@ -658,6 +657,12 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
return true;
case OMPD_target_teams_distribute:
return false;
case OMPD_target_teams_loop:
// Whether this is true or not depends on how the directive will
// eventually be emitted.
if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
return TTLD->canBeParallelFor();
return false;
case OMPD_parallel:
case OMPD_for:
case OMPD_parallel_for:
Expand Down
87 changes: 72 additions & 15 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
Expand All @@ -34,11 +35,14 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Debug.h"
#include <optional>
using namespace clang;
using namespace CodeGen;
using namespace llvm::omp;

#define TTL_CODEGEN_TYPE "target-teams-loop-codegen"

static const VarDecl *getBaseDecl(const Expr *Ref);

namespace {
Expand Down Expand Up @@ -1432,9 +1436,12 @@ void CodeGenFunction::EmitOMPReductionClauseFinal(
*this, D.getBeginLoc(),
isOpenMPWorksharingDirective(D.getDirectiveKind()));
}
bool TeamsLoopCanBeParallel = false;
if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
TeamsLoopCanBeParallel = TTLD->canBeParallelFor();
bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
isOpenMPParallelDirective(D.getDirectiveKind()) ||
ReductionKind == OMPD_simd;
TeamsLoopCanBeParallel || ReductionKind == OMPD_simd;
bool SimpleReduction = ReductionKind == OMPD_simd;
// Emit nowait reduction if nowait clause is present or directive is a
// parallel directive (it always has implicit barrier).
Expand Down Expand Up @@ -7928,11 +7935,9 @@ void CodeGenFunction::EmitOMPParallelGenericLoopDirective(
void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
const OMPTeamsGenericLoopDirective &S) {
// To be consistent with current behavior of 'target teams loop', emit
// 'teams loop' as if its constituent constructs are 'distribute,
// 'parallel, and 'for'.
// 'teams loop' as if its constituent constructs are 'teams' and 'distribute'.
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};

// Emit teams region as a standalone region.
Expand All @@ -7946,15 +7951,33 @@ void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}

static void
emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
const OMPTargetTeamsGenericLoopDirective &S,
PrePostActionTy &Action) {
static void emitTargetTeamsLoopCodegenStatus(CodeGenFunction &CGF,
std::string StatusMsg,
const OMPExecutableDirective &D) {
#ifndef NDEBUG
bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice;
if (IsDevice)
StatusMsg += ": DEVICE";
else
StatusMsg += ": HOST";
SourceLocation L = D.getBeginLoc();
auto &SM = CGF.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(L);
const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr;
unsigned LineNo =
PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L);
llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n";
#endif
}

static void emitTargetTeamsGenericLoopRegionAsParallel(
CodeGenFunction &CGF, PrePostActionTy &Action,
const OMPTargetTeamsGenericLoopDirective &S) {
Action.Enter(CGF);
// Emit 'teams loop' as if its constituent constructs are 'distribute,
// 'parallel, and 'for'.
Expand All @@ -7974,19 +7997,50 @@ emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};

DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
emitTargetTeamsLoopCodegenStatus(
CGF, TTL_CODEGEN_TYPE " as parallel for", S));
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
CodeGenTeams);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}

/// Emit combined directive 'target teams loop' as if its constituent
/// constructs are 'target', 'teams', 'distribute', 'parallel', and 'for'.
static void emitTargetTeamsGenericLoopRegionAsDistribute(
CodeGenFunction &CGF, PrePostActionTy &Action,
const OMPTargetTeamsGenericLoopDirective &S) {
Action.Enter(CGF);
// Emit 'teams loop' as if its constituent construct is 'distribute'.
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};

// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
emitTargetTeamsLoopCodegenStatus(
CGF, TTL_CODEGEN_TYPE " as distribute", S));
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}

void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDirective(
const OMPTargetTeamsGenericLoopDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsGenericLoopRegion(CGF, S, Action);
if (S.canBeParallelFor())
emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
else
emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
Expand All @@ -7996,7 +8050,10 @@ void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDeviceFunction(
const OMPTargetTeamsGenericLoopDirective &S) {
// Emit SPMD target parallel loop region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsGenericLoopRegion(CGF, S, Action);
if (S.canBeParallelFor())
emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
else
emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
};
llvm::Function *Fn;
llvm::Constant *Addr;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)

CodeGenFunction::~CodeGenFunction() {
assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
assert(DeferredDeactivationCleanupStack.empty() &&
"missed to deactivate a cleanup");

if (getLangOpts().OpenMP && CurFn)
CGM.getOpenMPRuntime().functionFinished(*this);
Expand Down Expand Up @@ -346,6 +348,10 @@ static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
assert(LifetimeExtendedCleanupStack.empty() &&
"mismatched push/pop of cleanups in EHStack!");
assert(DeferredDeactivationCleanupStack.empty() &&
"mismatched activate/deactivate of cleanups!");

bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
&& NumSimpleReturnExprs == NumReturnExprs
Expand Down
96 changes: 94 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
Expand Down Expand Up @@ -670,6 +671,51 @@ class CodeGenFunction : public CodeGenTypeCache {

EHScopeStack EHStack;
llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;

// A stack of cleanups which were added to EHStack but have to be deactivated
// later before being popped or emitted. These are usually deactivated on
// exiting a `CleanupDeactivationScope` scope. For instance, after a
// full-expr.
//
// These are specially useful for correctly emitting cleanups while
// encountering branches out of expression (through stmt-expr or coroutine
// suspensions).
struct DeferredDeactivateCleanup {
EHScopeStack::stable_iterator Cleanup;
llvm::Instruction *DominatingIP;
};
llvm::SmallVector<DeferredDeactivateCleanup> DeferredDeactivationCleanupStack;

// Enters a new scope for capturing cleanups which are deferred to be
// deactivated, all of which will be deactivated once the scope is exited.
struct CleanupDeactivationScope {
CodeGenFunction &CGF;
size_t OldDeactivateCleanupStackSize;
bool Deactivated;
CleanupDeactivationScope(CodeGenFunction &CGF)
: CGF(CGF), OldDeactivateCleanupStackSize(
CGF.DeferredDeactivationCleanupStack.size()),
Deactivated(false) {}

void ForceDeactivate() {
assert(!Deactivated && "Deactivating already deactivated scope");
auto &Stack = CGF.DeferredDeactivationCleanupStack;
for (size_t I = Stack.size(); I > OldDeactivateCleanupStackSize; I--) {
CGF.DeactivateCleanupBlock(Stack[I - 1].Cleanup,
Stack[I - 1].DominatingIP);
Stack[I - 1].DominatingIP->eraseFromParent();
}
Stack.resize(OldDeactivateCleanupStackSize);
Deactivated = true;
}

~CleanupDeactivationScope() {
if (Deactivated)
return;
ForceDeactivate();
}
};

llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;

llvm::Instruction *CurrentFuncletPad = nullptr;
Expand Down Expand Up @@ -875,6 +921,19 @@ class CodeGenFunction : public CodeGenTypeCache {
new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag);
}

// Push a cleanup onto EHStack and deactivate it later. It is usually
// deactivated when exiting a `CleanupDeactivationScope` (for example: after a
// full expression).
template <class T, class... As>
void pushCleanupAndDeferDeactivation(CleanupKind Kind, As... A) {
// Placeholder dominating IP for this cleanup.
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
EHStack.pushCleanup<T>(Kind, A...);
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

/// Set up the last cleanup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup() {
Expand Down Expand Up @@ -926,6 +985,7 @@ class CodeGenFunction : public CodeGenTypeCache {
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth;
size_t LifetimeExtendedCleanupStackSize;
CleanupDeactivationScope DeactivateCleanups;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
Expand All @@ -940,8 +1000,7 @@ class CodeGenFunction : public CodeGenTypeCache {
public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
: PerformCleanup(true), CGF(CGF)
{
: DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) {
CleanupStackDepth = CGF.EHStack.stable_begin();
LifetimeExtendedCleanupStackSize =
CGF.LifetimeExtendedCleanupStack.size();
Expand Down Expand Up @@ -971,6 +1030,7 @@ class CodeGenFunction : public CodeGenTypeCache {
void ForceCleanup(std::initializer_list<llvm::Value**> ValuesToReload = {}) {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
DeactivateCleanups.ForceDeactivate();
CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize,
ValuesToReload);
PerformCleanup = false;
Expand Down Expand Up @@ -2160,6 +2220,11 @@ class CodeGenFunction : public CodeGenTypeCache {
Address addr, QualType type);
void pushDestroy(CleanupKind kind, Address addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind,
Address addr, QualType type);
void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
Expand Down Expand Up @@ -2698,6 +2763,33 @@ class CodeGenFunction : public CodeGenTypeCache {
TBAAAccessInfo *TBAAInfo = nullptr);
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);

private:
struct AllocaTracker {
void Add(llvm::AllocaInst *I) { Allocas.push_back(I); }
llvm::SmallVector<llvm::AllocaInst *> Take() { return std::move(Allocas); }

private:
llvm::SmallVector<llvm::AllocaInst *> Allocas;
};
AllocaTracker *Allocas = nullptr;

public:
// Captures all the allocas created during the scope of its RAII object.
struct AllocaTrackerRAII {
AllocaTrackerRAII(CodeGenFunction &CGF)
: CGF(CGF), OldTracker(CGF.Allocas) {
CGF.Allocas = &Tracker;
}
~AllocaTrackerRAII() { CGF.Allocas = OldTracker; }

llvm::SmallVector<llvm::AllocaInst *> Take() { return Tracker.Take(); }

private:
CodeGenFunction &CGF;
AllocaTracker *OldTracker;
AllocaTracker Tracker;
};

/// CreateTempAlloca - This creates an alloca and inserts it into the entry
/// block if \p ArraySize is nullptr, otherwise inserts it at the current
/// insertion point of the builder. The caller is responsible for setting an
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,14 @@ void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
llvm::AttributeList PAL;
ConstructAttributeList(F->getName(), Info, GD, PAL, CallingConv,
/*AttrOnCallSite=*/false, IsThunk);
if (CallingConv == llvm::CallingConv::X86_VectorCall &&
getTarget().getTriple().isWindowsArm64EC()) {
SourceLocation Loc;
if (const Decl *D = GD.getDecl())
Loc = D->getLocation();

Error(Loc, "__vectorcall calling convention is not currently supported");
}
F->setAttributes(PAL);
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CodeGen/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2106,8 +2106,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
postMerge(Size, Lo, Hi);
return;
}

bool IsInMemory =
Offset % getContext().getTypeAlign(i->getType().getCanonicalType());
// Note, skip this test for bit-fields, see below.
if (!BitField && Offset % getContext().getTypeAlign(i->getType())) {
if (!BitField && IsInMemory) {
Lo = Memory;
postMerge(Size, Lo, Hi);
return;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,10 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
options::OPT_mno_wavefrontsize64, false))
Features.push_back("+wavefrontsize64");

if (Args.hasFlag(options::OPT_mamdgpu_precise_memory_op,
options::OPT_mno_amdgpu_precise_memory_op, false))
Features.push_back("+precise-memory");

handleTargetFeaturesGroup(D, Triple, Args, Features,
options::OPT_m_amdgpu_Features_Group);
}
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ static void addVSDefines(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver)));
CmdArgs.push_back(Args.MakeArgString("-D_WIN32"));

llvm::Triple triple = TC.getTriple();
const llvm::Triple &triple = TC.getTriple();
if (triple.isAArch64()) {
CmdArgs.push_back("-D_M_ARM64=1");
} else if (triple.isX86() && triple.isArch32Bit()) {
Expand Down Expand Up @@ -589,7 +589,7 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,

if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
ApproxFunc && !SignedZeros &&
(FPContract == "fast" || FPContract == "")) {
(FPContract == "fast" || FPContract.empty())) {
CmdArgs.push_back("-ffast-math");
return;
}
Expand Down Expand Up @@ -679,7 +679,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(TripleStr));

if (isa<PreprocessJobAction>(JA)) {
CmdArgs.push_back("-E");
CmdArgs.push_back("-E");
if (Args.getLastArg(options::OPT_dM)) {
CmdArgs.push_back("-dM");
}
} else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
if (JA.getType() == types::TY_Nothing) {
CmdArgs.push_back("-fsyntax-only");
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2354,7 +2354,8 @@ class AnnotatingParser {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found. In this case, 'Current' is a
// trailing token of this declaration and thus cannot be a name.
if (Current.is(Keywords.kw_instanceof)) {
if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) &&
Current.is(Keywords.kw_instanceof)) {
Current.setType(TT_BinaryOperator);
} else if (isStartOfName(Current) &&
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
Expand Down
20 changes: 10 additions & 10 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,16 +538,6 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
if (Style.Language == FormatStyle::LK_Proto) {
ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
} else {
// Skip NextTok over preprocessor lines, otherwise we may not
// properly diagnose the block as a braced intializer
// if the comma separator appears after the pp directive.
while (NextTok->is(tok::hash)) {
ScopedMacroState MacroState(*Line, Tokens, NextTok);
do {
NextTok = Tokens->getNextToken();
} while (NextTok->isNot(tok::eof));
}

// Using OriginalColumn to distinguish between ObjC methods and
// binary operators is a bit hacky.
bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
Expand Down Expand Up @@ -606,6 +596,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
NextTok = Tokens->getNextToken();
ProbablyBracedList = NextTok->isNot(tok::l_square);
}

// Cpp macro definition body that is a nonempty braced list or block:
if (IsCpp && Line->InMacroBody && PrevTok != FormatTok &&
!FormatTok->Previous && NextTok->is(tok::eof) &&
// A statement can end with only `;` (simple statement), a block
// closing brace (compound statement), or `:` (label statement).
// If PrevTok is a block opening brace, Tok ends an empty block.
!PrevTok->isOneOf(tok::semi, BK_Block, tok::colon)) {
ProbablyBracedList = true;
}
}
if (ProbablyBracedList) {
Tok->setBlockKind(BK_BracedInit);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Headers/intrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <armintr.h>
#endif

#if defined(__aarch64__)
#if defined(__aarch64__) || defined(__arm64ec__)
#include <arm64intr.h>
#endif

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
Expand Down Expand Up @@ -2490,8 +2491,8 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
if (T.consumeClose())
return ExprError();

return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
T.getCloseLocation(), Ty.get());
return Actions.SYCL().ActOnUniqueStableNameExpr(
OpLoc, T.getOpenLocation(), T.getCloseLocation(), Ty.get());
}

/// Parse a sizeof or alignof expression.
Expand Down
14 changes: 8 additions & 6 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,16 +831,19 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(

ConsumeToken();

if (getOpenACCDefaultClauseKind(DefKindTok) ==
OpenACCDefaultClauseKind::Invalid)
OpenACCDefaultClauseKind DefKind =
getOpenACCDefaultClauseKind(DefKindTok);

if (DefKind == OpenACCDefaultClauseKind::Invalid)
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
else
ParsedClause.setDefaultDetails(DefKind);

break;
}
case OpenACCClauseKind::If: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.

if (CondExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
Expand Down Expand Up @@ -962,8 +965,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.

if (CondExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "clang/Sema/TypoCorrection.h"
Expand Down Expand Up @@ -201,6 +202,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CurScope(nullptr), Ident_super(nullptr),
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()),
Expand Down Expand Up @@ -1903,7 +1905,7 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) {
: CUDADiagIfHostCode(Loc, DiagID);

if (getLangOpts().SYCLIsDevice)
return SYCLDiagIfDeviceCode(Loc, DiagID);
return SYCL().DiagIfDeviceCode(Loc, DiagID);

return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, DiagID,
FD, *this);
Expand All @@ -1919,7 +1921,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
// constant byte size like zero length arrays. So, do a deep check for SYCL.
if (D && LangOpts.SYCLIsDevice) {
llvm::DenseSet<QualType> Visited;
deepTypeCheckForSYCLDevice(Loc, Visited, D);
SYCL().deepTypeCheckForDevice(Loc, Visited, D);
}

Decl *C = cast<Decl>(getCurLexicalContext());
Expand Down
22 changes: 21 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7938,6 +7938,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
// For variadic functions, we may have more args than parameters.
// For some K&R functions, we may have less args than parameters.
const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType();
for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
if (const Expr *Arg = Args[ArgIdx]) {
Expand All @@ -7951,6 +7952,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
checkAIXMemberAlignment((Arg->getExprLoc()), Arg);

QualType ParamTy = Proto->getParamType(ArgIdx);
if (ParamTy->isSizelessVectorType())
AnyScalableArgsOrRet = true;
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
ArgTy, ParamTy);
Expand All @@ -7971,6 +7974,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
}

// If the call requires a streaming-mode change and has scalable vector
// arguments or return values, then warn the user that the streaming and
// non-streaming vector lengths may be different.
const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) {
bool IsCalleeStreaming =
ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
bool IsCalleeStreamingCompatible =
ExtInfo.AArch64SMEAttributes &
FunctionType::SME_PStateSMCompatibleMask;
ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
if (!IsCalleeStreamingCompatible &&
(CallerFnType == ArmStreamingCompatible ||
((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
}

FunctionType::ArmStateValue CalleeArmZAState =
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
FunctionType::ArmStateValue CalleeArmZT0State =
Expand All @@ -7979,7 +7999,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
CalleeArmZT0State != FunctionType::ARM_None) {
bool CallerHasZAState = false;
bool CallerHasZT0State = false;
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
if (CallerFD) {
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
if (Attr && Attr->isNewZA())
CallerHasZAState = true;
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12395,12 +12395,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}

// Check if the function definition uses any AArch64 SME features without
// having the '+sme' feature enabled.
// having the '+sme' feature enabled and warn user if sme locally streaming
// function returns or uses arguments with VL-based types.
if (DeclIsDefn) {
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
bool UsesZA = Attr && Attr->isNewZA();
bool UsesZT0 = Attr && Attr->isNewZT0();

if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
if (NewFD->getReturnType()->isSizelessVectorType() ||
llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
return P->getOriginalType()->isSizelessVectorType();
}))
Diag(NewFD->getLocation(),
diag::warn_sme_locally_streaming_has_vl_args_returns);
}
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
UsesSM |=
Expand Down
27 changes: 2 additions & 25 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3442,11 +3442,10 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) {

ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R, bool NeedsADL,
bool AcceptInvalidDecl,
bool NeedUnresolved) {
bool AcceptInvalidDecl) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
if (!NeedUnresolved && !NeedsADL && R.isSingleResult() &&
if (!NeedsADL && R.isSingleResult() &&
!R.getAsSingle<FunctionTemplateDecl>() &&
!ShouldLookupResultBeMultiVersionOverload(R))
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
Expand Down Expand Up @@ -3795,28 +3794,6 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SL);
}

ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI) {
return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI);
}

ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy) {
TypeSourceInfo *TSI = nullptr;
QualType Ty = GetTypeFromParser(ParsedTy, &TSI);

if (Ty.isNull())
return ExprError();
if (!TSI)
TSI = Context.getTrivialTypeSourceInfo(Ty, LParen);

return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
}

ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind));
}
Expand Down
Loading