140 changes: 140 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,146 @@ the configuration (without a prefix: ``Auto``).
bbb >>= 2;


.. _AlignConsecutiveTableGenDefinitionColons:

**AlignConsecutiveTableGenDefinitionColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`ΒΆ <AlignConsecutiveTableGenDefinitionColons>`
Style of aligning consecutive TableGen definition colons.
This aligns the inheritance colons of consecutive definitions.

.. code-block:: c++

def Def : Parent {}
def DefDef : Parent {}
def DefDefDef : Parent {}

Nested configuration flags:

Alignment options.

They can also be read as a whole for compatibility. The choices are:
- None
- Consecutive
- AcrossEmptyLines
- AcrossComments
- AcrossEmptyLinesAndComments

For example, to align across empty lines and not across comments, either
of these work.

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines

AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false

* ``bool Enabled`` Whether aligning is enabled.

.. code-block:: c++

#define SHORT_NAME 42
#define LONGER_NAME 0x007f
#define EVEN_LONGER_NAME (2)
#define foo(x) (x * x)
#define bar(y, z) (y + z)

int a = 1;
int somelongname = 2;
double c = 3;

int aaaa : 1;
int b : 12;
int ccc : 8;

int aaaa = 12;
float b = 23;
std::string ccc;

* ``bool AcrossEmptyLines`` Whether to align across empty lines.

.. code-block:: c++

true:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

false:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

* ``bool AcrossComments`` Whether to align across comments.

.. code-block:: c++

true:
int d = 3;
/* A comment. */
double e = 4;
false:
int d = 3;
/* A comment. */
double e = 4;
* ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments
like ``+=`` are aligned along with ``=``.

.. code-block:: c++

true:
a &= 2;
bbb = 2;

false:
a &= 2;
bbb = 2;

* ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are
aligned.

.. code-block:: c++

true:
unsigned i;
int &r;
int *p;
int (*f)();
false:
unsigned i;
int &r;
int *p;
int (*f)();
* ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment
operators are left-padded to the same length as long ones in order to
put all assignment operators to the right of the left hand side.

.. code-block:: c++

true:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;

false:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;


.. _AlignEscapedNewlines:

**AlignEscapedNewlines** (``EscapedNewlineAlignmentStyle``) :versionbadge:`clang-format 5` :ref:`ΒΆ <AlignEscapedNewlines>`
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ Improvements to Clang's time-trace

Bug Fixes in This Version
-------------------------
- Fixed missing warnings when comparing mismatched enumeration constants
in C (`#29217 <https://github.com/llvm/llvm-project/issues/29217>`).

- Clang now accepts elaborated-type-specifiers that explicitly specialize
a member class template for an implicit instantiation of a class template.

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2981,6 +2981,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
// corresponding saturated type for a given fixed point type.
QualType getCorrespondingSaturatedType(QualType Ty) const;

// Per ISO N1169, this method accepts fixed point types and returns the
// corresponding non-saturated type for a given fixed point type.
QualType getCorrespondingUnsaturatedType(QualType Ty) const;

// This method accepts fixed point types and returns the corresponding signed
// type. Unlike getCorrespondingUnsignedType(), this only accepts unsigned
// fixed point types because there are unsigned integer types like bool and
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ class Expr : public ValueStmt {
TR = t;
}

/// If this expression is an enumeration constant, return the
/// enumeration type under which said constant was declared.
/// Otherwise return the expression's type.
/// Note this effectively circumvents the weak typing of C's enum constants
QualType getEnumCoercedType(const ASTContext &Ctx) const;

ExprDependence getDependence() const {
return static_cast<ExprDependence>(ExprBits.Dependent);
}
Expand Down Expand Up @@ -471,6 +477,13 @@ class Expr : public ValueStmt {
/// bit-fields, but it will return null for a conditional bit-field.
FieldDecl *getSourceBitField();

/// If this expression refers to an enum constant, retrieve its declaration
EnumConstantDecl *getEnumConstantDecl();

const EnumConstantDecl *getEnumConstantDecl() const {
return const_cast<Expr *>(this)->getEnumConstantDecl();
}

const FieldDecl *getSourceBitField() const {
return const_cast<Expr*>(this)->getSourceBitField();
}
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/FormatString.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ class ConversionSpecifier {

ZArg, // MS extension

// ISO/IEC TR 18037 (fixed-point) specific specifiers.
kArg, // %k for signed accum types
KArg, // %K for unsigned accum types
rArg, // %r for signed fract types
RArg, // %R for unsigned fract types
FixedPointArgBeg = kArg,
FixedPointArgEnd = RArg,

// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg,
Expand Down Expand Up @@ -237,6 +245,9 @@ class ConversionSpecifier {
bool isDoubleArg() const {
return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
}
bool isFixedPointArg() const {
return kind >= FixedPointArgBeg && kind <= FixedPointArgEnd;
}

const char *toString() const;

Expand Down
7 changes: 3 additions & 4 deletions clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ namespace dataflow {
/// Environment &Env)` - applies the analysis transfer
/// function for a given edge from a CFG block of a conditional statement.
///
/// `Derived` can optionally override the following members:
/// * `bool merge(QualType, const Value &, const Value &, Value &,
/// Environment &)` - joins distinct values. This could be a strict
/// lattice join or a more general widening operation.
/// `Derived` can optionally override the virtual functions in the
/// `Environment::ValueModel` interface (which is an indirect base class of
/// this class).
///
/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must
/// provide the following public members:
Expand Down
32 changes: 1 addition & 31 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,6 @@ class Environment {
return ComparisonResult::Unknown;
}

/// DEPRECATED. Override `join` and/or `widen`, instead.
///
/// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could
/// be a strict lattice join or a more general widening operation.
///
/// If this function returns true, `MergedVal` will be assigned to a storage
/// location of type `Type` in `MergedEnv`.
///
/// `Env1` and `Env2` can be used to query child values and path condition
/// implications of `Val1` and `Val2` respectively.
///
/// Requirements:
///
/// `Val1` and `Val2` must be distinct.
///
/// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`.
///
/// `Val1` and `Val2` must be assigned to the same storage location in
/// `Env1` and `Env2` respectively.
virtual bool merge(QualType Type, const Value &Val1,
const Environment &Env1, const Value &Val2,
const Environment &Env2, Value &MergedVal,
Environment &MergedEnv) {
return true;
}

/// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
/// obey the properties of a lattice join.
///
Expand All @@ -121,11 +95,7 @@ class Environment {
/// `Env1` and `Env2` respectively.
virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
const Value &Val2, const Environment &Env2,
Value &JoinedVal, Environment &JoinedEnv) {
[[maybe_unused]] bool ShouldKeep =
merge(Type, Val1, Env1, Val2, Env2, JoinedVal, JoinedEnv);
assert(ShouldKeep && "dropping merged value is unsupported");
}
Value &JoinedVal, Environment &JoinedEnv) {}

/// This function may widen the current value -- replace it with an
/// approximation that can reach a fixed point more quickly than iterated
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,16 @@ struct FormatStyle {
/// \version 19
AlignConsecutiveStyle AlignConsecutiveTableGenCondOperatorColons;

/// Style of aligning consecutive TableGen definition colons.
/// This aligns the inheritance colons of consecutive definitions.
/// \code
/// def Def : Parent {}
/// def DefDef : Parent {}
/// def DefDefDef : Parent {}
/// \endcode
/// \version 19
AlignConsecutiveStyle AlignConsecutiveTableGenDefinitionColons;

/// Different styles for aligning escaped newlines.
enum EscapedNewlineAlignmentStyle : int8_t {
/// Don't align escaped newlines.
Expand Down Expand Up @@ -4817,6 +4827,8 @@ struct FormatStyle {
R.AlignConsecutiveShortCaseStatements &&
AlignConsecutiveTableGenCondOperatorColons ==
R.AlignConsecutiveTableGenCondOperatorColons &&
AlignConsecutiveTableGenDefinitionColons ==
R.AlignConsecutiveTableGenDefinitionColons &&
AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&
AlignTrailingComments == R.AlignTrailingComments &&
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/APINotes/APINotesReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ class VersionedTableInfo {
auto version = ReadVersionTuple(Data);
const auto *DataBefore = Data;
(void)DataBefore;
auto UnversionedData = Derived::readUnversioned(Key, Data);
assert(Data != DataBefore &&
"Unversioned data reader didn't move pointer");
auto UnversionedData = Derived::readUnversioned(Key, Data);
Result.push_back({version, UnversionedData});
}
return Result;
Expand Down Expand Up @@ -148,7 +148,7 @@ class IdentifierTableInfo {
external_key_type GetExternalKey(internal_key_type Key) { return Key; }

hash_value_type ComputeHash(internal_key_type Key) {
return llvm::hash_value(Key);
return llvm::djbHash(Key);
}

static bool EqualKey(internal_key_type LHS, internal_key_type RHS) {
Expand Down Expand Up @@ -1797,8 +1797,8 @@ APINotesReader::Create(std::unique_ptr<llvm::MemoryBuffer> InputBuffer,
template <typename T>
APINotesReader::VersionedInfo<T>::VersionedInfo(
llvm::VersionTuple Version,
llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1> Results)
: Results(std::move(Results)) {
llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1> R)
: Results(std::move(R)) {

assert(!Results.empty());
assert(std::is_sorted(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/APINotes/APINotesWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class APINotesWriter::Implementation {
SelectorID getSelector(ObjCSelectorRef SelectorRef) {
// Translate the selector reference into a stored selector.
StoredObjCSelector Selector;
Selector.NumArgs = SelectorRef.NumArgs;
Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
for (auto piece : SelectorRef.Identifiers)
Selector.Identifiers.push_back(getIdentifier(piece));
Expand Down
36 changes: 36 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13314,6 +13314,42 @@ QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
return R;
}

QualType ASTContext::getCorrespondingUnsaturatedType(QualType Ty) const {
assert(Ty->isFixedPointType());

if (Ty->isUnsaturatedFixedPointType())
return Ty;

switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a saturated fixed point type!");
case BuiltinType::SatShortAccum:
return ShortAccumTy;
case BuiltinType::SatAccum:
return AccumTy;
case BuiltinType::SatLongAccum:
return LongAccumTy;
case BuiltinType::SatUShortAccum:
return UnsignedShortAccumTy;
case BuiltinType::SatUAccum:
return UnsignedAccumTy;
case BuiltinType::SatULongAccum:
return UnsignedLongAccumTy;
case BuiltinType::SatShortFract:
return ShortFractTy;
case BuiltinType::SatFract:
return FractTy;
case BuiltinType::SatLongFract:
return LongFractTy;
case BuiltinType::SatUShortFract:
return UnsignedShortFractTy;
case BuiltinType::SatUFract:
return UnsignedFractTy;
case BuiltinType::SatULongFract:
return UnsignedLongFractTy;
}
}

QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
assert(Ty->isFixedPointType());

Expand Down
15 changes: 15 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ namespace {
}
}

QualType Expr::getEnumCoercedType(const ASTContext &Ctx) const {
if (isa<EnumType>(this->getType()))
return this->getType();
else if (const auto *ECD = this->getEnumConstantDecl())
return Ctx.getTypeDeclType(cast<EnumDecl>(ECD->getDeclContext()));
return this->getType();
}

SourceLocation Expr::getExprLoc() const {
switch (getStmtClass()) {
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
Expand Down Expand Up @@ -4098,6 +4106,13 @@ FieldDecl *Expr::getSourceBitField() {
return nullptr;
}

EnumConstantDecl *Expr::getEnumConstantDecl() {
Expr *E = this->IgnoreParenImpCasts();
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
return dyn_cast<EnumConstantDecl>(DRE->getDecl());
return nullptr;
}

bool Expr::refersToVectorElement() const {
// FIXME: Why do we not just look at the ObjectKind here?
const Expr *E = this->IgnoreParens();
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/AST/FormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,10 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
else if (ETy->isUnscopedEnumerationType())
argTy = ETy->getDecl()->getIntegerType();
}

if (argTy->isSaturatedFixedPointType())
argTy = C.getCorrespondingUnsaturatedType(argTy);

argTy = C.getCanonicalType(argTy).getUnqualifiedType();

if (T == argTy)
Expand Down Expand Up @@ -761,6 +765,16 @@ const char *ConversionSpecifier::toString() const {

// MS specific specifiers.
case ZArg: return "Z";

// ISO/IEC TR 18037 (fixed-point) specific specifiers.
case rArg:
return "r";
case RArg:
return "R";
case kArg:
return "k";
case KArg:
return "K";
}
return nullptr;
}
Expand Down Expand Up @@ -825,6 +839,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
if (LO.OpenCL && CS.isDoubleArg())
return !VectorNumElts.isInvalid();

if (CS.isFixedPointArg())
return true;

if (Target.getTriple().isOSMSVCRT()) {
switch (CS.getKind()) {
case ConversionSpecifier::cArg:
Expand Down Expand Up @@ -877,6 +894,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
return true;
}

if (CS.isFixedPointArg())
return true;

switch (CS.getKind()) {
case ConversionSpecifier::bArg:
case ConversionSpecifier::BArg:
Expand Down Expand Up @@ -1043,6 +1063,11 @@ bool FormatSpecifier::hasStandardConversionSpecifier(
case ConversionSpecifier::UArg:
case ConversionSpecifier::ZArg:
return false;
case ConversionSpecifier::rArg:
case ConversionSpecifier::RArg:
case ConversionSpecifier::kArg:
case ConversionSpecifier::KArg:
return LangOpt.FixedPoint;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
}
Expand Down
63 changes: 52 additions & 11 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (!this->visitInitializer(Init))
return false;

if (!this->emitInitPtrPop(E))
if (!this->emitFinishInitPop(E))
return false;
// Base initializers don't increase InitIndex, since they don't count
// into the Record's fields.
Expand Down Expand Up @@ -940,7 +940,7 @@ bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex,
return false;
if (!this->visitInitializer(Init))
return false;
return this->emitInitPtrPop(Init);
return this->emitFinishInitPop(Init);
}

template <class Emitter>
Expand Down Expand Up @@ -1700,19 +1700,35 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
}

// Otherwise, use a local variable.
if (T) {
if (T && !E->isLValue()) {
// For primitive types, we just visit the initializer.
return this->delegate(Init);
} else {
if (std::optional<unsigned> LocalIndex = allocateLocal(Init)) {
if (!this->emitGetPtrLocal(*LocalIndex, E))
unsigned LocalIndex;

if (T)
LocalIndex = this->allocateLocalPrimitive(Init, *T, false, false);
else if (std::optional<unsigned> MaybeIndex = this->allocateLocal(Init))
LocalIndex = *MaybeIndex;
else
return false;

if (!this->emitGetPtrLocal(LocalIndex, E))
return false;

if (T) {
if (!this->visit(Init)) {
return false;
}
return this->emitInit(*T, E);
} else {
if (!this->visitInitializer(Init))
return false;
if (DiscardResult)
return this->emitPopPtr(E);
return true;
}

if (DiscardResult)
return this->emitPopPtr(E);
return true;
}

return false;
Expand Down Expand Up @@ -2151,7 +2167,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
}
}

return this->emitInitPtr(E);
return this->emitFinishInit(E);
}

template <class Emitter>
Expand All @@ -2173,6 +2189,31 @@ bool ByteCodeExprGen<Emitter>::VisitCXXRewrittenBinaryOperator(
return this->delegate(E->getSemanticForm());
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr(
const PseudoObjectExpr *E) {

for (const Expr *SemE : E->semantics()) {
if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) {
if (SemE == E->getResultExpr())
return false;

if (OVE->isUnique())
continue;

if (!this->discard(OVE))
return false;
} else if (SemE == E->getResultExpr()) {
if (!this->delegate(SemE))
return false;
} else {
if (!this->discard(SemE))
return false;
}
}
return true;
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand Down Expand Up @@ -2364,7 +2405,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
return false;
if (!this->visitZeroRecordInitializer(B.R, E))
return false;
if (!this->emitInitPtrPop(E))
if (!this->emitFinishInitPop(E))
return false;
}

Expand Down Expand Up @@ -2544,7 +2585,7 @@ bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
if (!visitInitializer(E))
return false;

if (!this->emitInitPtr(E))
if (!this->emitFinishInit(E))
return false;
return this->emitRetValue(E);
}
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitRequiresExpr(const RequiresExpr *E);
bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down Expand Up @@ -182,7 +183,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
if (!visitInitializer(Init))
return false;

if (!this->emitInitPtr(Init))
if (!this->emitFinishInit(Init))
return false;

return this->emitPopPtr(Init);
Expand All @@ -196,7 +197,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
if (!visitInitializer(Init))
return false;

if (!this->emitInitPtr(Init))
if (!this->emitFinishInit(Init))
return false;

return this->emitPopPtr(Init);
Expand All @@ -210,7 +211,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
if (!visitInitializer(I))
return false;

return this->emitInitPtrPop(I);
return this->emitFinishInitPop(I);
}

bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E);
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 @@ -200,7 +200,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
return false;
if (!this->visitInitializer(InitExpr))
return false;
if (!this->emitInitPtrPop(InitExpr))
if (!this->emitFinishInitPop(InitExpr))
return false;
} else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) {
assert(IFD->getChainingSize() >= 2);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
} else if (FieldType->isIncompleteArrayType()) {
// Nothing to do here.
} else if (F.Decl->isUnnamedBitfield()) {
// Nothing do do here.
} else if (FieldType->isArrayType()) {
const auto *CAT =
cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
Expand Down
17 changes: 15 additions & 2 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1280,14 +1280,14 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return true;
}

inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.canBeInitialized())
Ptr.initialize();
return true;
}

inline bool InitPtr(InterpState &S, CodePtr OpPC) {
inline bool FinishInit(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (Ptr.canBeInitialized())
Expand Down Expand Up @@ -1399,6 +1399,19 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Init(InterpState &S, CodePtr OpPC) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckInit(S, OpPC, Ptr)) {
assert(false);
return false;
}
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitPop(InterpState &S, CodePtr OpPC) {
const T &Value = S.Stk.pop<T>();
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,6 @@ static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
const CallExpr *Call) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
// pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigned=*/true));
pushInteger(S, Val.reverseBits(), Call->getType());
return true;
}
Expand Down Expand Up @@ -552,7 +551,6 @@ static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC,
Result = APSInt(Value.rotl(Amount.urem(Value.getBitWidth())),
/*IsUnsigned=*/true);

// pushAPSInt(S, Result);
pushInteger(S, Result, Call->getType());
return true;
}
Expand Down Expand Up @@ -785,7 +783,6 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
CarryOutPtr.initialize();

assert(Call->getType() == Call->getArg(0)->getType());
// pushAPSInt(S, Result);
pushInteger(S, Result, Call->getType());
return true;
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ def GetPtrBasePop : Opcode {
let Args = [ArgUint32];
}

def InitPtrPop : Opcode;
def InitPtr : Opcode;
def FinishInitPop : Opcode;
def FinishInit : Opcode;

def GetPtrDerivedPop : Opcode {
let Args = [ArgUint32];
Expand Down Expand Up @@ -476,6 +476,7 @@ def StoreBitField : StoreBitFieldOpcode {}
def StoreBitFieldPop : StoreBitFieldOpcode {}

// [Pointer, Value] -> []
def Init : StoreOpcode {}
def InitPop : StoreOpcode {}
// [Pointer, Value] -> [Pointer]
def InitElem : Opcode {
Expand Down
85 changes: 82 additions & 3 deletions clang/lib/AST/PrintfFormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case 'r':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDrArg; // int
else if (LO.FixedPoint)
k = ConversionSpecifier::rArg;
break;
case 'y':
if (isFreeBSDKPrintf)
Expand All @@ -373,6 +375,20 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (Target.getTriple().isOSMSVCRT())
k = ConversionSpecifier::ZArg;
break;
// ISO/IEC TR 18037 (fixed-point) specific.
// NOTE: 'r' is handled up above since FreeBSD also supports %r.
case 'k':
if (LO.FixedPoint)
k = ConversionSpecifier::kArg;
break;
case 'K':
if (LO.FixedPoint)
k = ConversionSpecifier::KArg;
break;
case 'R':
if (LO.FixedPoint)
k = ConversionSpecifier::RArg;
break;
}

// Check to see if we used the Objective-C modifier flags with
Expand Down Expand Up @@ -627,6 +643,9 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
}
}

if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
return ArgType::Invalid();

switch (CS.getKind()) {
case ConversionSpecifier::sArg:
if (LM.getKind() == LengthModifier::AsWideChar) {
Expand Down Expand Up @@ -658,6 +677,50 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
return ArgType::CPointerTy;
case ConversionSpecifier::ObjCObjArg:
return ArgType::ObjCPointerTy;
case ConversionSpecifier::kArg:
switch (LM.getKind()) {
case LengthModifier::None:
return Ctx.AccumTy;
case LengthModifier::AsShort:
return Ctx.ShortAccumTy;
case LengthModifier::AsLong:
return Ctx.LongAccumTy;
default:
return ArgType::Invalid();
}
case ConversionSpecifier::KArg:
switch (LM.getKind()) {
case LengthModifier::None:
return Ctx.UnsignedAccumTy;
case LengthModifier::AsShort:
return Ctx.UnsignedShortAccumTy;
case LengthModifier::AsLong:
return Ctx.UnsignedLongAccumTy;
default:
return ArgType::Invalid();
}
case ConversionSpecifier::rArg:
switch (LM.getKind()) {
case LengthModifier::None:
return Ctx.FractTy;
case LengthModifier::AsShort:
return Ctx.ShortFractTy;
case LengthModifier::AsLong:
return Ctx.LongFractTy;
default:
return ArgType::Invalid();
}
case ConversionSpecifier::RArg:
switch (LM.getKind()) {
case LengthModifier::None:
return Ctx.UnsignedFractTy;
case LengthModifier::AsShort:
return Ctx.UnsignedShortFractTy;
case LengthModifier::AsLong:
return Ctx.UnsignedLongFractTy;
default:
return ArgType::Invalid();
}
default:
break;
}
Expand Down Expand Up @@ -955,6 +1018,8 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
case ConversionSpecifier::AArg:
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
case ConversionSpecifier::rArg:
case ConversionSpecifier::kArg:
return true;

default:
Expand All @@ -966,7 +1031,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
if (!HasAlternativeForm)
return true;

// Alternate form flag only valid with the bBoxXaAeEfFgG conversions
// Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
switch (CS.getKind()) {
case ConversionSpecifier::bArg:
case ConversionSpecifier::BArg:
Expand All @@ -984,6 +1049,10 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
case ConversionSpecifier::GArg:
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
case ConversionSpecifier::rArg:
case ConversionSpecifier::RArg:
case ConversionSpecifier::kArg:
case ConversionSpecifier::KArg:
return true;

default:
Expand All @@ -995,7 +1064,7 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
if (!HasLeadingZeroes)
return true;

// Leading zeroes flag only valid with the bBdiouxXaAeEfFgG conversions
// Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
switch (CS.getKind()) {
case ConversionSpecifier::bArg:
case ConversionSpecifier::BArg:
Expand All @@ -1018,6 +1087,10 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
case ConversionSpecifier::GArg:
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
case ConversionSpecifier::rArg:
case ConversionSpecifier::RArg:
case ConversionSpecifier::kArg:
case ConversionSpecifier::KArg:
return true;

default:
Expand All @@ -1044,6 +1117,8 @@ bool PrintfSpecifier::hasValidSpacePrefix() const {
case ConversionSpecifier::AArg:
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
case ConversionSpecifier::rArg:
case ConversionSpecifier::kArg:
return true;

default:
Expand Down Expand Up @@ -1089,7 +1164,7 @@ bool PrintfSpecifier::hasValidPrecision() const {
if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
return true;

// Precision is only valid with the bBdiouxXaAeEfFgGsP conversions
// Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
switch (CS.getKind()) {
case ConversionSpecifier::bArg:
case ConversionSpecifier::BArg:
Expand All @@ -1114,6 +1189,10 @@ bool PrintfSpecifier::hasValidPrecision() const {
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
case ConversionSpecifier::PArg:
case ConversionSpecifier::rArg:
case ConversionSpecifier::RArg:
case ConversionSpecifier::kArg:
case ConversionSpecifier::KArg:
return true;

default:
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Basic/Targets/Mips.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,14 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {
case 'r': // CPU registers.
case 'd': // Equivalent to "r" unless generating MIPS16 code.
case 'y': // Equivalent to "r", backward compatibility only.
case 'f': // floating-point registers.
case 'c': // $25 for indirect jumps
case 'l': // lo register
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
case 'f': // floating-point registers.
Info.setAllowsRegister();
return FloatABI != SoftFloat;
case 'I': // Signed 16-bit constant
case 'J': // Integer 0
case 'K': // Unsigned 16-bit constant
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4479,9 +4479,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
options::OPT_gpubnames, options::OPT_gno_pubnames);
if (DwarfFission != DwarfFissionKind::None ||
(PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC)))
if (!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
!PubnamesArg->getOption().matches(options::OPT_gno_pubnames)))
if (DebuggerTuning != llvm::DebuggerKind::LLDB &&
(!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
!PubnamesArg->getOption().matches(options::OPT_gno_pubnames))))
CmdArgs.push_back(PubnamesArg && PubnamesArg->getOption().matches(
options::OPT_gpubnames)
? "-gpubnames"
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.AlignConsecutiveShortCaseStatements);
IO.mapOptional("AlignConsecutiveTableGenCondOperatorColons",
Style.AlignConsecutiveTableGenCondOperatorColons);
IO.mapOptional("AlignConsecutiveTableGenDefinitionColons",
Style.AlignConsecutiveTableGenDefinitionColons);
IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Expand Down Expand Up @@ -1423,6 +1425,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignConsecutiveMacros = {};
LLVMStyle.AlignConsecutiveShortCaseStatements = {};
LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {};
LLVMStyle.AlignConsecutiveTableGenDefinitionColons = {};
LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = {};
Expand Down Expand Up @@ -3923,7 +3926,7 @@ FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
auto Extension = llvm::sys::path::extension(FileName);
// If there's no file extension (or it's .h), we need to check the contents
// of the code to see if it contains Objective-C.
if (Extension.empty() || Extension == ".h") {
if (!Code.empty() && (Extension.empty() || Extension == ".h")) {
auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName;
Environment Env(Code, NonEmptyFileName, /*Ranges=*/{});
ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle());
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
alignConsecutiveDeclarations();
alignConsecutiveBitFields();
alignConsecutiveAssignments();
if (Style.isTableGen())
if (Style.isTableGen()) {
alignConsecutiveTableGenCondOperatorColons();
alignConsecutiveTableGenDefinitions();
}
alignChainedConditionals();
alignTrailingComments();
alignEscapedNewlines();
Expand Down Expand Up @@ -984,6 +986,11 @@ void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
TT_TableGenCondOperatorColon);
}

void WhitespaceManager::alignConsecutiveTableGenDefinitions() {
alignConsecutiveColons(Style.AlignConsecutiveTableGenDefinitionColons,
TT_InheritanceColon);
}

void WhitespaceManager::alignConsecutiveDeclarations() {
if (!Style.AlignConsecutiveDeclarations.Enabled)
return;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/WhitespaceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ class WhitespaceManager {
/// Align consecutive TableGen cond operator colon over all \c Changes.
void alignConsecutiveTableGenCondOperatorColons();

/// Align consecutive TableGen definitions over all \c Changes.
void alignConsecutiveTableGenDefinitions();

/// Align trailing comments over all \c Changes.
void alignTrailingComments();

Expand Down
72 changes: 66 additions & 6 deletions clang/lib/Headers/__clang_hip_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -1306,15 +1306,75 @@ float min(float __x, float __y) { return __builtin_fminf(__x, __y); }
__DEVICE__
double min(double __x, double __y) { return __builtin_fmin(__x, __y); }

#if !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__)
__host__ inline static int min(int __arg1, int __arg2) {
return __arg1 < __arg2 ? __arg1 : __arg2;
// Define host min/max functions.
#if !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) && \
!defined(__HIP_NO_HOST_MIN_MAX_IN_GLOBAL_NAMESPACE__)

#pragma push_macro("DEFINE_MIN_MAX_FUNCTIONS")
#pragma push_macro("DEFINE_MIN_MAX_FUNCTIONS")
#define DEFINE_MIN_MAX_FUNCTIONS(ret_type, type1, type2) \
inline ret_type min(const type1 __a, const type2 __b) { \
return (__a < __b) ? __a : __b; \
} \
inline ret_type max(const type1 __a, const type2 __b) { \
return (__a > __b) ? __a : __b; \
}

// Define min and max functions for same type comparisons
DEFINE_MIN_MAX_FUNCTIONS(int, int, int)
DEFINE_MIN_MAX_FUNCTIONS(unsigned int, unsigned int, unsigned int)
DEFINE_MIN_MAX_FUNCTIONS(long, long, long)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long, unsigned long, unsigned long)
DEFINE_MIN_MAX_FUNCTIONS(long long, long long, long long)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long long, unsigned long long,
unsigned long long)

// The host min/max functions below accept mixed signed/unsigned integer
// parameters and perform unsigned comparisons, which may produce unexpected
// results if a signed integer was passed unintentionally. To avoid this
// happening silently, these overloaded functions are not defined by default.
// However, for compatibility with CUDA, they will be defined if users define
// __HIP_DEFINE_MIXED_HOST_MIN_MAX__.
#ifdef __HIP_DEFINE_MIXED_HOST_MIN_MAX__
DEFINE_MIN_MAX_FUNCTIONS(unsigned int, int, unsigned int)
DEFINE_MIN_MAX_FUNCTIONS(unsigned int, unsigned int, int)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long, long, unsigned long)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long, unsigned long, long)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long long, long long, unsigned long long)
DEFINE_MIN_MAX_FUNCTIONS(unsigned long long, unsigned long long, long long)
#endif // ifdef __HIP_DEFINE_MIXED_HOST_MIN_MAX__

// Floating-point comparisons using built-in functions
inline float min(float const __a, float const __b) {
return __builtin_fminf(__a, __b);
}
inline double min(double const __a, double const __b) {
return __builtin_fmin(__a, __b);
}
inline double min(float const __a, double const __b) {
return __builtin_fmin(__a, __b);
}
inline double min(double const __a, float const __b) {
return __builtin_fmin(__a, __b);
}

__host__ inline static int max(int __arg1, int __arg2) {
return __arg1 > __arg2 ? __arg1 : __arg2;
inline float max(float const __a, float const __b) {
return __builtin_fmaxf(__a, __b);
}
inline double max(double const __a, double const __b) {
return __builtin_fmax(__a, __b);
}
inline double max(float const __a, double const __b) {
return __builtin_fmax(__a, __b);
}
#endif // !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__)
inline double max(double const __a, float const __b) {
return __builtin_fmax(__a, __b);
}

#pragma pop_macro("DEFINE_MIN_MAX_FUNCTIONS")

#endif // !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) &&
// !defined(__HIP_NO_HOST_MIN_MAX_IN_GLOBAL_NAMESPACE__)
#endif

#pragma pop_macro("__DEVICE__")
Expand Down
11 changes: 2 additions & 9 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16148,15 +16148,8 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Diagnose conversions between different enumeration types.
// In C, we pretend that the type of an EnumConstantDecl is its enumeration
// type, to give us better diagnostics.
QualType SourceType = E->getType();
if (!S.getLangOpts().CPlusPlus) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
SourceType = S.Context.getTypeDeclType(Enum);
Source = S.Context.getCanonicalType(SourceType).getTypePtr();
}
}
QualType SourceType = E->getEnumCoercedType(S.Context);
Source = S.Context.getCanonicalType(SourceType).getTypePtr();

if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,7 +1497,8 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
//
// Warn on this in all language modes. Produce a deprecation warning in C++20.
// Eventually we will presumably reject these cases (in C++23 onwards?).
QualType L = LHS->getType(), R = RHS->getType();
QualType L = LHS->getEnumCoercedType(S.Context),
R = RHS->getEnumCoercedType(S.Context);
bool LEnum = L->isUnscopedEnumerationType(),
REnum = R->isUnscopedEnumerationType();
bool IsCompAssign = ACK == Sema::ACK_CompAssign;
Expand Down
16 changes: 16 additions & 0 deletions clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,19 @@ void test4(void) {
t1 = sizeof(int);
}

void localCompoundLiteral(void) {
struct S { int x, y; } s = {}; // pedantic-expected-warning {{use of an empty initializer}} \
// pedantic-ref-warning {{use of an empty initializer}}
struct T {
int i;
struct S s;
} t1 = { 1, {} }; // pedantic-expected-warning {{use of an empty initializer}} \
// pedantic-ref-warning {{use of an empty initializer}}

struct T t3 = {
(int){}, // pedantic-expected-warning {{use of an empty initializer}} \
// pedantic-ref-warning {{use of an empty initializer}}
{} // pedantic-expected-warning {{use of an empty initializer}} \
// pedantic-ref-warning {{use of an empty initializer}}
};
}
23 changes: 23 additions & 0 deletions clang/test/AST/Interp/cxx20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,3 +776,26 @@ namespace RewrittenBinaryOperators {
};
static_assert(X() < X(), "");
}

namespace GH61417 {
struct A {
unsigned x : 1;
unsigned : 0;
unsigned y : 1;

constexpr A() : x(0), y(0) {}
bool operator==(const A& rhs) const noexcept = default;
};

void f1() {
constexpr A a, b;
constexpr bool c = (a == b); // no diagnostic, we should not be comparing the
// unnamed bit-field which is indeterminate
}

void f2() {
A a, b;
bool c = (a == b); // no diagnostic nor crash during codegen attempting to
// access info for unnamed bit-field
}
}
232 changes: 232 additions & 0 deletions clang/test/AST/Interp/spaceship.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
// RUN: %clang_cc1 -std=c++2a -verify=both,ref %s -fcxx-exceptions
// RUN: %clang_cc1 -std=c++2a -verify=both,expected %s -fcxx-exceptions -fexperimental-new-constant-interpreter

namespace std {
struct strong_ordering { // both-note 6{{candidate}}
int n;
constexpr operator int() const { return n; }
static const strong_ordering less, equal, greater;
};
constexpr strong_ordering strong_ordering::less{-1},
strong_ordering::equal{0}, strong_ordering::greater{1};

struct weak_ordering {
int n;
constexpr weak_ordering(int n) : n(n) {}
constexpr weak_ordering(strong_ordering o) : n(o.n) {}
constexpr operator int() const { return n; }
static const weak_ordering less, equivalent, greater;
};
constexpr weak_ordering weak_ordering::less{-1},
weak_ordering::equivalent{0}, weak_ordering::greater{1};

struct partial_ordering {
double d;
constexpr partial_ordering(double d) : d(d) {}
constexpr partial_ordering(strong_ordering o) : d(o.n) {}
constexpr partial_ordering(weak_ordering o) : d(o.n) {}
constexpr operator double() const { return d; }
static const partial_ordering less, equivalent, greater, unordered;
};
constexpr partial_ordering partial_ordering::less{-1},
partial_ordering::equivalent{0}, partial_ordering::greater{1},
partial_ordering::unordered{__builtin_nan("")};

static_assert(!(partial_ordering::unordered < 0));
static_assert(!(partial_ordering::unordered == 0));
static_assert(!(partial_ordering::unordered > 0));
}

namespace Deletedness {
struct A {
std::strong_ordering operator<=>(const A&) const;
};
struct B {
bool operator==(const B&) const;
bool operator<(const B&) const;
};
struct C {
std::strong_ordering operator<=>(const C&) const = delete; // both-note 2{{deleted}}
};
struct D1 {
bool operator==(const D1&) const;
std::strong_ordering operator<=>(int) const; // both-note 2{{function not viable}} both-note 2{{function (with reversed parameter order) not viable}}
bool operator<(int) const; // both-note 2{{function not viable}}
};
struct D2 {
bool operator<(const D2&) const;
std::strong_ordering operator<=>(int) const; // both-note 2{{function not viable}} both-note 2{{function (with reversed parameter order) not viable}}
bool operator==(int) const; // both-note 2{{function not viable}}
};
struct E {
bool operator==(const E&) const;
bool operator<(const E&) const = delete; // both-note 2{{deleted}}
};
struct F {
std::strong_ordering operator<=>(const F&) const; // both-note 2{{candidate}}
std::strong_ordering operator<=>(F) const; // both-note 2{{candidate}}
};
struct G1 {
bool operator==(const G1&) const;
void operator<(const G1&) const;
};
struct G2 {
void operator==(const G2&) const;
bool operator<(const G2&) const;
};
struct H {
void operator<=>(const H&) const;
};

// both-note@#base {{deleted comparison function for base class 'C'}}
// both-note@#base {{no viable three-way comparison function for base class 'D1'}}
// both-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}
// both-note@#base {{no viable 'operator==' for base class 'D2'}}
// both-note@#base {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}
// both-note@#base {{deleted comparison function for base class 'E'}}
// both-note@#base {{implied comparison for base class 'F' is ambiguous}}
template<typename T> struct Cmp : T { // #base
std::strong_ordering operator<=>(const Cmp&) const = default; // #cmp both-note 5{{here}}
};

void use(...);
void f() {
use(
Cmp<A>() <=> Cmp<A>(),
Cmp<B>() <=> Cmp<B>(),
Cmp<C>() <=> Cmp<C>(), // both-error {{deleted}}
Cmp<D1>() <=> Cmp<D1>(), // both-error {{deleted}}
Cmp<D2>() <=> Cmp<D2>(), // both-error {{deleted}}
Cmp<E>() <=> Cmp<E>(), // both-error {{deleted}}
Cmp<F>() <=> Cmp<F>(), // both-error {{deleted}}
// FIXME: The following three errors are not very good.
// both-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}
Cmp<G1>() <=> Cmp<G1>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G1>' first required here}}j
// both-error@#cmp {{value of type 'void' is not contextually convertible to 'bool'}}
Cmp<G2>() <=> Cmp<G2>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}G2>' first required here}}j
// both-error@#cmp {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
Cmp<H>() <=> Cmp<H>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}Cmp<{{.*}}H>' first required here}}j
0
);
}

// both-note@#arr {{deleted comparison function for member 'arr'}}
// both-note@#arr {{no viable three-way comparison function for member 'arr'}}
// both-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '<' comparison}}
// both-note@#arr {{no viable 'operator==' for member 'arr'}}
// both-note@#arr {{three-way comparison cannot be synthesized because there is no viable function for '==' comparison}}
// both-note@#arr {{deleted comparison function for member 'arr'}}
// both-note@#arr {{implied comparison for member 'arr' is ambiguous}}
template<typename T> struct CmpArray {
T arr[3]; // #arr
std::strong_ordering operator<=>(const CmpArray&) const = default; // #cmparray both-note 5{{here}}
};
void g() {
use(
CmpArray<A>() <=> CmpArray<A>(),
CmpArray<B>() <=> CmpArray<B>(),
CmpArray<C>() <=> CmpArray<C>(), // both-error {{deleted}}
CmpArray<D1>() <=> CmpArray<D1>(), // both-error {{deleted}}
CmpArray<D2>() <=> CmpArray<D2>(), // both-error {{deleted}}
CmpArray<E>() <=> CmpArray<E>(), // both-error {{deleted}}
CmpArray<F>() <=> CmpArray<F>(), // both-error {{deleted}}
// FIXME: The following three errors are not very good.
// both-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}
CmpArray<G1>() <=> CmpArray<G1>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G1>' first required here}}j
// both-error@#cmparray {{value of type 'void' is not contextually convertible to 'bool'}}
CmpArray<G2>() <=> CmpArray<G2>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}G2>' first required here}}j
// both-error@#cmparray {{no matching conversion for static_cast from 'void' to 'std::strong_ordering'}}
CmpArray<H>() <=> CmpArray<H>(), // both-note-re {{in defaulted three-way comparison operator for '{{.*}}CmpArray<{{.*}}H>' first required here}}j
0
);
}
}

namespace Access {
class A {
std::strong_ordering operator<=>(const A &) const; // both-note {{here}}
public:
bool operator==(const A &) const;
bool operator<(const A &) const;
};
struct B {
A a; // both-note {{would invoke a private 'operator<=>'}}
friend std::strong_ordering operator<=>(const B &, const B &) = default; // both-warning {{deleted}} both-note{{replace 'default'}}
};

class C {
std::strong_ordering operator<=>(const C &); // not viable (not const)
bool operator==(const C &) const; // both-note {{here}}
bool operator<(const C &) const;
};
struct D {
C c; // both-note {{would invoke a private 'operator=='}}
friend std::strong_ordering operator<=>(const D &, const D &) = default; // both-warning {{deleted}} both-note{{replace 'default'}}
};
}

namespace Synthesis {
enum Result { False, True, Mu };

constexpr bool toBool(Result R) {
if (R == Mu) throw "should not ask this question";
return R == True;
}

struct Val {
Result equal, less;
constexpr bool operator==(const Val&) const { return toBool(equal); }
constexpr bool operator<(const Val&) const { return toBool(less); }
};

template<typename T> struct Cmp {
Val val;
friend T operator<=>(const Cmp&, const Cmp&) = default; // both-note {{deleted}}
};

template<typename T> constexpr auto cmp(Result equal, Result less = Mu, Result reverse_less = Mu) {
return Cmp<T>{equal, less} <=> Cmp<T>{Mu, reverse_less};
}

static_assert(cmp<std::strong_ordering>(True) == 0);
static_assert(cmp<std::strong_ordering>(False, True) < 0);
static_assert(cmp<std::strong_ordering>(False, False) > 0);

static_assert(cmp<std::weak_ordering>(True) == 0);
static_assert(cmp<std::weak_ordering>(False, True) < 0);
static_assert(cmp<std::weak_ordering>(False, False) > 0);

static_assert(cmp<std::partial_ordering>(True) == 0);
static_assert(cmp<std::partial_ordering>(False, True) < 0);
static_assert(cmp<std::partial_ordering>(False, False, True) > 0);
static_assert(!(cmp<std::partial_ordering>(False, False, False) > 0));
static_assert(!(cmp<std::partial_ordering>(False, False, False) == 0));
static_assert(!(cmp<std::partial_ordering>(False, False, False) < 0));

// No synthesis is performed for a custom return type, even if it can be
// converted from a standard ordering.
struct custom_ordering {
custom_ordering(std::strong_ordering o);
};
void f(Cmp<custom_ordering> c) {
c <=> c; // both-error {{deleted}}
}
}

namespace Preference {
struct A {
A(const A&) = delete; // both-note {{deleted}}
// "usable" candidate that can't actually be called
friend void operator<=>(A, A); // both-note {{passing}}
// Callable candidates for synthesis not considered.
friend bool operator==(A, A);
friend bool operator<(A, A);
};

struct B {
B();
A a;
std::strong_ordering operator<=>(const B&) const = default; // both-error {{call to deleted constructor of 'A'}}
};
bool x = B() < B(); // both-note {{in defaulted three-way comparison operator for 'B' first required here}}
}
11 changes: 11 additions & 0 deletions clang/test/CodeGen/Mips/inline-asm-constraints.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 -emit-llvm -triple mips -target-feature +soft-float %s -o - | FileCheck %s --check-prefix=SOFT_FLOAT

// SOFT_FLOAT: call void asm sideeffect "", "r,~{$1}"(float %1)
void read_float(float *p) {
__asm__("" ::"r"(*p));
}

// SOFT_FLOAT: call void asm sideeffect "", "r,~{$1}"(double %1)
void read_double(double *p) {
__asm__("" :: "r"(*p));
}
6 changes: 3 additions & 3 deletions clang/test/CodeGenHLSL/semantics/GroupIndex-codegen.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s | FileCheck %s

[numthreads(1,1,1)]
void main(unsigned GI : SV_GroupIndex) {
Expand All @@ -10,7 +10,7 @@ void main(unsigned GI : SV_GroupIndex) {
// semantic parameters and provides the expected void(void) signature that
// drivers expect for entry points.

//CHECK: define void @main() #[[ENTRY_ATTR:#]]{
//CHECK: define void @main() #[[#ENTRY_ATTR:]] {
//CHECK-NEXT: entry:
//CHECK-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
//CHECK-NEXT: call void @"?main@@YAXI@Z"(i32 %0)
Expand All @@ -19,4 +19,4 @@ void main(unsigned GI : SV_GroupIndex) {

// Verify that the entry had the expected dx.shader attribute

//CHECK: attributes #[[ENTRY_ATTR]] = { {{.*}}"dx.shader"="compute"{{.*}} }
//CHECK: attributes #[[#ENTRY_ATTR]] = { {{.*}}"hlsl.shader"="compute"{{.*}} }
5 changes: 5 additions & 0 deletions clang/test/Driver/split-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,8 @@
// G1_NOSPLIT: "-debug-info-kind=line-tables-only"
// G1_NOSPLIT-NOT: "-split-dwarf-file"
// G1_NOSPLIT-NOT: "-split-dwarf-output"

/// Do not generate -ggnu-pubnames for -glldb
// RUN: %clang -### -c -target x86_64 -gsplit-dwarf -g -glldb %s 2>&1 | FileCheck %s --check-prefixes=GLLDBSPLIT

// GLLDBSPLIT-NOT: "-ggnu-pubnames"
4 changes: 4 additions & 0 deletions clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ void test_builtin_elementwise_add_sat(int i, short s, double d, float4 v, int3 i

enum f { three };
enum f x = __builtin_elementwise_add_sat(one, three);
// expected-warning@-1 {{comparison of different enumeration types ('enum e' and 'enum f')}}

_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
ext = __builtin_elementwise_add_sat(ext, ext);
Expand Down Expand Up @@ -134,6 +135,7 @@ void test_builtin_elementwise_sub_sat(int i, short s, double d, float4 v, int3 i

enum f { three };
enum f x = __builtin_elementwise_sub_sat(one, three);
// expected-warning@-1 {{comparison of different enumeration types ('enum e' and 'enum f')}}

_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
ext = __builtin_elementwise_sub_sat(ext, ext);
Expand Down Expand Up @@ -189,6 +191,7 @@ void test_builtin_elementwise_max(int i, short s, double d, float4 v, int3 iv, u

enum f { three };
enum f x = __builtin_elementwise_max(one, three);
// expected-warning@-1 {{comparison of different enumeration types ('enum e' and 'enum f')}}

_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
ext = __builtin_elementwise_max(ext, ext);
Expand Down Expand Up @@ -244,6 +247,7 @@ void test_builtin_elementwise_min(int i, short s, double d, float4 v, int3 iv, u

enum f { three };
enum f x = __builtin_elementwise_min(one, three);
// expected-warning@-1 {{comparison of different enumeration types ('enum e' and 'enum f')}}

_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
ext = __builtin_elementwise_min(ext, ext);
Expand Down
148 changes: 148 additions & 0 deletions clang/test/Sema/format-fixed-point.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// RUN: %clang_cc1 -ffixed-point -fsyntax-only -verify -Wformat -isystem %S/Inputs %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat -isystem %S/Inputs %s -DWITHOUT_FIXED_POINT

int printf(const char *restrict, ...);

short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float fl;
double d;
char c;
unsigned char uc;

#ifndef WITHOUT_FIXED_POINT
short _Fract sf;
_Fract f;
long _Fract lf;
unsigned short _Fract usf;
unsigned _Fract uf;
unsigned long _Fract ulf;
short _Accum sa;
_Accum a;
long _Accum la;
unsigned short _Accum usa;
unsigned _Accum ua;
unsigned long _Accum ula;
_Sat short _Fract sat_sf;
_Sat _Fract sat_f;
_Sat long _Fract sat_lf;
_Sat unsigned short _Fract sat_usf;
_Sat unsigned _Fract sat_uf;
_Sat unsigned long _Fract sat_ulf;
_Sat short _Accum sat_sa;
_Sat _Accum sat_a;
_Sat long _Accum sat_la;
_Sat unsigned short _Accum sat_usa;
_Sat unsigned _Accum sat_ua;
_Sat unsigned long _Accum sat_ula;

void test_invalid_args(void) {
/// None of these should match against a fixed point type.
printf("%r", s); // expected-warning{{format specifies type '_Fract' but the argument has type 'short'}}
printf("%r", us); // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned short'}}
printf("%r", i); // expected-warning{{format specifies type '_Fract' but the argument has type 'int'}}
printf("%r", ui); // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned int'}}
printf("%r", l); // expected-warning{{format specifies type '_Fract' but the argument has type 'long'}}
printf("%r", ul); // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned long'}}
printf("%r", fl); // expected-warning{{format specifies type '_Fract' but the argument has type 'float'}}
printf("%r", d); // expected-warning{{format specifies type '_Fract' but the argument has type 'double'}}
printf("%r", c); // expected-warning{{format specifies type '_Fract' but the argument has type 'char'}}
printf("%r", uc); // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned char'}}
}

void test_fixed_point_specifiers(void) {
printf("%r", f);
printf("%R", uf);
printf("%k", a);
printf("%K", ua);

/// Test different sizes.
printf("%r", sf); // expected-warning{{format specifies type '_Fract' but the argument has type 'short _Fract'}}
printf("%r", lf); // expected-warning{{format specifies type '_Fract' but the argument has type 'long _Fract'}}
printf("%R", usf); // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned short _Fract'}}
printf("%R", ulf); // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned long _Fract'}}
printf("%k", sa); // expected-warning{{format specifies type '_Accum' but the argument has type 'short _Accum'}}
printf("%k", la); // expected-warning{{format specifies type '_Accum' but the argument has type 'long _Accum'}}
printf("%K", usa); // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned short _Accum'}}
printf("%K", ula); // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned long _Accum'}}

/// Test signs.
printf("%r", uf); // expected-warning{{format specifies type '_Fract' but the argument has type 'unsigned _Fract'}}
printf("%R", f); // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type '_Fract'}}
printf("%k", ua); // expected-warning{{format specifies type '_Accum' but the argument has type 'unsigned _Accum'}}
printf("%K", a); // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type '_Accum'}}

/// Test between types.
printf("%r", a); // expected-warning{{format specifies type '_Fract' but the argument has type '_Accum'}}
printf("%R", ua); // expected-warning{{format specifies type 'unsigned _Fract' but the argument has type 'unsigned _Accum'}}
printf("%k", f); // expected-warning{{format specifies type '_Accum' but the argument has type '_Fract'}}
printf("%K", uf); // expected-warning{{format specifies type 'unsigned _Accum' but the argument has type 'unsigned _Fract'}}

/// Test saturated types.
printf("%r", sat_f);
printf("%R", sat_uf);
printf("%k", sat_a);
printf("%K", sat_ua);
}

void test_length_modifiers_and_flags(void) {
printf("%hr", sf);
printf("%lr", lf);
printf("%hR", usf);
printf("%lR", ulf);
printf("%hk", sa);
printf("%lk", la);
printf("%hK", usa);
printf("%lK", ula);

printf("%hr", sat_sf);
printf("%lr", sat_lf);
printf("%hR", sat_usf);
printf("%lR", sat_ulf);
printf("%hk", sat_sa);
printf("%lk", sat_la);
printf("%hK", sat_usa);
printf("%lK", sat_ula);

printf("%10r", f);
printf("%10.10r", f);
printf("%010r", f);
printf("%-10r", f);
printf("%.10r", f);
printf("%+r", f);
printf("% r", f);
printf("%#r", f);
printf("%#.r", f);
printf("%#.0r", f);

/// Test some invalid length modifiers.
printf("%zr", f); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'r' conversion specifier}}
printf("%llr", f); // expected-warning{{length modifier 'll' results in undefined behavior or no effect with 'r' conversion specifier}}
printf("%hhr", f); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 'r' conversion specifier}}

// + on an unsigned fixed point type.
printf("%+hR", usf); // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
printf("%+R", uf); // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
printf("%+lR", ulf); // expected-warning{{flag '+' results in undefined behavior with 'R' conversion specifier}}
printf("%+hK", usa); // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
printf("%+K", ua); // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
printf("%+lK", ula); // expected-warning{{flag '+' results in undefined behavior with 'K' conversion specifier}}
printf("% hR", usf); // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
printf("% R", uf); // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
printf("% lR", ulf); // expected-warning{{flag ' ' results in undefined behavior with 'R' conversion specifier}}
printf("% hK", usa); // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
printf("% K", ua); // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
printf("% lK", ula); // expected-warning{{flag ' ' results in undefined behavior with 'K' conversion specifier}}
}
#else
void test_fixed_point_specifiers_no_printf() {
printf("%k", i); // expected-warning{{invalid conversion specifier 'k'}}
printf("%K", i); // expected-warning{{invalid conversion specifier 'K'}}
printf("%r", i); // expected-warning{{invalid conversion specifier 'r'}}
printf("%R", i); // expected-warning{{invalid conversion specifier 'R'}}
}
#endif // WITHOUT_FIXED_POINT
9 changes: 9 additions & 0 deletions clang/test/Sema/inline-asm-validate-mips.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -triple mips64 -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple mips64 -target-feature +soft-float -fsyntax-only -verify=softfloat %s

// expected-no-diagnostics

void test_f(float p) {
float result = p;
__asm__("" :: "f"(result)); // softfloat-error{{invalid input constraint 'f' in asm}}
}
42 changes: 42 additions & 0 deletions clang/test/Sema/warn-compare-enum-types-mismatch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wenum-compare -Wno-unused-comparison %s
// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wenum-compare -Wno-unused-comparison %s

typedef enum EnumA {
A
} EnumA;

enum EnumB {
B
};

enum {
C
};

void foo(void) {
enum EnumA a = A;
enum EnumB b = B;
A == B;
// expected-warning@-1 {{comparison of different enumeration types}}
a == (B);
// expected-warning@-1 {{comparison of different enumeration types}}
a == b;
// expected-warning@-1 {{comparison of different enumeration types}}
A > B;
// expected-warning@-1 {{comparison of different enumeration types}}
A >= b;
// expected-warning@-1 {{comparison of different enumeration types}}
a > b;
// expected-warning@-1 {{comparison of different enumeration types}}
(A) <= ((B));
// expected-warning@-1 {{comparison of different enumeration types}}
a < B;
// expected-warning@-1 {{comparison of different enumeration types}}
a < b;
// expected-warning@-1 {{comparison of different enumeration types}}

// In the following cases we purposefully differ from GCC and dont warn
a == C;
A < C;
b >= C;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ int get_flag(int cond) {
#ifdef __cplusplus
// expected-warning@-2 {{conditional expression between different enumeration types ('ro' and 'rw')}}
#else
// expected-no-diagnostics
// expected-warning@-4 {{conditional expression between different enumeration types ('enum ro' and 'enum rw')}}
#endif
}

Expand Down
4 changes: 2 additions & 2 deletions clang/test/Sema/warn-overlap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-overlap-compare %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wall -Wno-unused -Wno-loop-analysis %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-overlap-compare -Wno-enum-compare %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wall -Wno-unused -Wno-loop-analysis -Wno-enum-compare %s

#define mydefine 2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ static Error unbundleImages() {

if (Error E = writeArchive(
Args["file"], Members, SymtabWritingMode::NormalSymtab,
Archive::getDefaultKindForHost(), true, false, nullptr))
Archive::getDefaultKind(), true, false, nullptr))
return E;
} else if (Args.count("file")) {
if (Extracted.size() > 1)
Expand Down
14 changes: 14 additions & 0 deletions clang/unittests/Format/FormatTestTableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,5 +346,19 @@ TEST_F(FormatTestTableGen, CondOperatorAlignment) {
Style);
}

TEST_F(FormatTestTableGen, DefAlignment) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_TableGen);
Style.ColumnLimit = 60;
verifyFormat("def Def : Parent {}\n"
"def DefDef : Parent {}\n"
"def DefDefDef : Parent {}\n",
Style);
Style.AlignConsecutiveTableGenDefinitionColons.Enabled = true;
verifyFormat("def Def : Parent {}\n"
"def DefDef : Parent {}\n"
"def DefDefDef : Parent {}\n",
Style);
}

} // namespace format
} // end namespace clang
3 changes: 0 additions & 3 deletions compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -591,9 +591,6 @@ if (COMPILER_RT_TEST_STANDALONE_BUILD_LIBS)
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir)
list(APPEND COMPILER_RT_UNITTEST_LINK_FLAGS "-Wl,-rpath,${output_dir}")
endif()
message(WARNING "COMPILER_RT_UNITTEST_LINK_FLAGS=${COMPILER_RT_UNITTEST_LINK_FLAGS}, COMPILER_RT_TEST_STANDALONE_BUILD_LIBS=${COMPILER_RT_TEST_STANDALONE_BUILD_LIBS} COMPILER_RT_TEST_COMPILER_ID=${COMPILER_RT_TEST_COMPILER_ID}")



if(COMPILER_RT_USE_LLVM_UNWINDER)
# We're linking directly against the libunwind that we're building so don't
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/cmake/Modules/AddCompilerRT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ function(configure_compiler_rt_lit_site_cfg input output)
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir)

string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER})
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_OUTPUT_DIR ${COMPILER_RT_OUTPUT_DIR})
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${output_dir})

configure_lit_site_cfg(${input} ${output})
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/cmake/Modules/CompilerRTCompile.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function(clang_compile object_file source)

add_custom_command(
OUTPUT ${object_file}
COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
COMMAND ${compiler} ${compile_flags} -c
-o "${object_file}"
${source_rpath}
MAIN_DEPENDENCY ${source}
Expand Down
54 changes: 51 additions & 3 deletions compiler-rt/include/profile/InstrProfData.inc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumBitmapBytes, \
#undef INSTR_PROF_DATA
/* INSTR_PROF_DATA end. */

/* For a virtual table object, record the name hash to associate profiled
* addresses with global variables, and record {starting address, size in bytes}
* to map the profiled virtual table (which usually have an offset from the
* starting address) back to a virtual table object. */
#ifndef INSTR_PROF_VTABLE_DATA
#define INSTR_PROF_VTABLE_DATA(Type, LLVMType, Name, Initializer)
#else
#define INSTR_PROF_VTABLE_DATA_DEFINED
#endif
INSTR_PROF_VTABLE_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), \
VTableNameHash, ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
IndexedInstrProf::ComputeHash(PGOVTableName)))
INSTR_PROF_VTABLE_DATA(const IntPtrT, llvm::PointerType::getUnqual(Ctx), \
VTablePointer, VTableAddr)
INSTR_PROF_VTABLE_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), VTableSize, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \
VTableSizeVal))
#undef INSTR_PROF_VTABLE_DATA
/* INSTR_PROF_VTABLE_DATA end. */

/* This is an internal data structure used by value profiler. It
* is defined here to allow serialization code sharing by LLVM
Expand Down Expand Up @@ -147,6 +166,8 @@ INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta,
INSTR_PROF_RAW_HEADER(uint64_t, BitmapDelta,
(uintptr_t)BitmapBegin - (uintptr_t)DataBegin)
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
INSTR_PROF_RAW_HEADER(uint64_t, NumVTables, NumVTables)
INSTR_PROF_RAW_HEADER(uint64_t, VNamesSize, VNamesSize)
INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
#undef INSTR_PROF_RAW_HEADER
/* INSTR_PROF_RAW_HEADER end */
Expand Down Expand Up @@ -188,13 +209,26 @@ VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0, "indirect call target")
/* For memory intrinsic functions size profiling. */
VALUE_PROF_KIND(IPVK_MemOPSize, 1, "memory intrinsic functions size")
/* For virtual table address profiling, the address point of the virtual table
* (i.e., the address contained in objects pointing to a virtual table) are
* profiled. Note this may not be the address of the per C++ class virtual table
* object (e.g., there might be an offset).
*
* The profiled addresses are stored in raw profile, together with the following
* two types of information.
* 1. The (starting and ending) addresses of per C++ class virtual table objects.
* 2. The (compressed) virtual table object names.
* RawInstrProfReader converts profiled virtual table addresses to virtual table
* objects' MD5 hash.
*/
VALUE_PROF_KIND(IPVK_VTableTarget, 2, "The profiled address point of the vtable")
/* These two kinds must be the last to be
* declared. This is to make sure the string
* array created with the template can be
* indexed with the kind value.
*/
VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget, "first")
VALUE_PROF_KIND(IPVK_Last, IPVK_MemOPSize, "last")
VALUE_PROF_KIND(IPVK_Last, IPVK_VTableTarget, "last")

#undef VALUE_PROF_KIND
/* VALUE_PROF_KIND end */
Expand Down Expand Up @@ -284,12 +318,18 @@ INSTR_PROF_SECT_ENTRY(IPSK_bitmap, \
INSTR_PROF_SECT_ENTRY(IPSK_name, \
INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \
INSTR_PROF_NAME_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_vname, \
INSTR_PROF_QUOTE(INSTR_PROF_VNAME_COMMON), \
INSTR_PROF_VNAME_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_vals, \
INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \
INSTR_PROF_VALS_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \
INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \
INSTR_PROF_VNODES_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_vtab, \
INSTR_PROF_QUOTE(INSTR_PROF_VTAB_COMMON), \
INSTR_PROF_VTAB_COFF, "__DATA,")
INSTR_PROF_SECT_ENTRY(IPSK_covmap, \
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \
INSTR_PROF_COVMAP_COFF, "__LLVM_COV,")
Expand Down Expand Up @@ -668,9 +708,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129

/* Raw profile format version (start from 1). */
#define INSTR_PROF_RAW_VERSION 9
#define INSTR_PROF_RAW_VERSION 10
/* Indexed profile format version (start from 1). */
#define INSTR_PROF_INDEX_VERSION 11
#define INSTR_PROF_INDEX_VERSION 12
/* Coverage mapping format version (start from 0). */
#define INSTR_PROF_COVMAP_VERSION 6

Expand Down Expand Up @@ -708,10 +748,12 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
than WIN32 */
#define INSTR_PROF_DATA_COMMON __llvm_prf_data
#define INSTR_PROF_NAME_COMMON __llvm_prf_names
#define INSTR_PROF_VNAME_COMMON __llvm_prf_vns
#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts
#define INSTR_PROF_BITS_COMMON __llvm_prf_bits
#define INSTR_PROF_VALS_COMMON __llvm_prf_vals
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
#define INSTR_PROF_VTAB_COMMON __llvm_prf_vtab
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
#define INSTR_PROF_COVFUN_COMMON __llvm_covfun
#define INSTR_PROF_COVDATA_COMMON __llvm_covdata
Expand All @@ -722,10 +764,12 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
*/
#define INSTR_PROF_DATA_COFF ".lprfd$M"
#define INSTR_PROF_NAME_COFF ".lprfn$M"
#define INSTR_PROF_VNAME_COFF ".lprfvn$M"
#define INSTR_PROF_CNTS_COFF ".lprfc$M"
#define INSTR_PROF_BITS_COFF ".lprfb$M"
#define INSTR_PROF_VALS_COFF ".lprfv$M"
#define INSTR_PROF_VNODES_COFF ".lprfnd$M"
#define INSTR_PROF_VTAB_COFF ".lprfvt$M"
#define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
#define INSTR_PROF_COVFUN_COFF ".lcovfun$M"
/* Since cov data and cov names sections are not allocated, we don't need to
Expand All @@ -741,6 +785,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_BITS_COFF
#define INSTR_PROF_VTAB_SECT_NAME INSTR_PROF_VTAB_COFF
#define INSTR_PROF_VNAME_SECT_NAME INSTR_PROF_VNAME_COFF
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/
Expand All @@ -758,6 +804,8 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON)
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON)
#define INSTR_PROF_BITS_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_BITS_COMMON)
#define INSTR_PROF_VTAB_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VTAB_COMMON)
#define INSTR_PROF_VNAME_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNAME_COMMON)
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/
Expand Down
35 changes: 28 additions & 7 deletions compiler-rt/lib/profile/InstrProfiling.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ typedef struct ValueProfNode {
#include "profile/InstrProfData.inc"
} ValueProfNode;

typedef void *IntPtrT;
typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) VTableProfData {
#define INSTR_PROF_VTABLE_DATA(Type, LLVMType, Name, Initializer) Type Name;
#include "profile/InstrProfData.inc"
} VTableProfData;

/*!
* \brief Return 1 if profile counters are continuously synced to the raw
* profile via an mmap(). This is in contrast to the default mode, in which
Expand Down Expand Up @@ -103,12 +109,16 @@ const __llvm_profile_data *__llvm_profile_begin_data(void);
const __llvm_profile_data *__llvm_profile_end_data(void);
const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void);
const char *__llvm_profile_begin_vtabnames(void);
const char *__llvm_profile_end_vtabnames(void);
char *__llvm_profile_begin_counters(void);
char *__llvm_profile_end_counters(void);
char *__llvm_profile_begin_bitmap(void);
char *__llvm_profile_end_bitmap(void);
ValueProfNode *__llvm_profile_begin_vnodes();
ValueProfNode *__llvm_profile_end_vnodes();
const VTableProfData *__llvm_profile_begin_vtables();
const VTableProfData *__llvm_profile_end_vtables();
uint32_t *__llvm_profile_begin_orderfile();

/*!
Expand Down Expand Up @@ -252,20 +262,31 @@ uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
/*! \brief Get the size of the profile name section in bytes. */
uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End);

/* ! \brief Given the sizes of the data and counter information, return the
* number of padding bytes before and after the counters, and after the names,
* in the raw profile.
/*! \brief Get the number of virtual table profile data entries */
uint64_t __llvm_profile_get_num_vtable(const VTableProfData *Begin,
const VTableProfData *End);

/*! \brief Get the size of virtual table profile data in bytes. */
uint64_t __llvm_profile_get_vtable_section_size(const VTableProfData *Begin,
const VTableProfData *End);

/* ! \brief Given the sizes of the data and counter information, computes the
* number of padding bytes before and after the counter section, as well as the
* number of padding bytes after other setions in the raw profile.
* Returns -1 upon errors and 0 upon success. Output parameters should be used
* iff return value is 0.
*
* Note: When mmap() mode is disabled, no padding bytes before/after counters
* are needed. However, in mmap() mode, the counter section in the raw profile
* must be page-aligned: this API computes the number of padding bytes
* needed to achieve that.
*/
void __llvm_profile_get_padding_sizes_for_counters(
int __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmap,
uint64_t *PaddingBytesAfterNames);
uint64_t NamesSize, uint64_t VTableSize, uint64_t VNameSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t *PaddingBytesAfterBitmap, uint64_t *PaddingBytesAfterNames,
uint64_t *PaddingBytesAfterVTable, uint64_t *PaddingBytesAfterVNames);

/*!
* \brief Set the flag that profile data has been dumped to the file.
Expand Down
96 changes: 81 additions & 15 deletions compiler-rt/lib/profile/InstrProfilingBuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,29 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
const char *BitmapEnd = __llvm_profile_end_bitmap();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
const VTableProfData *VTableBegin = __llvm_profile_begin_vtables();
const VTableProfData *VTableEnd = __llvm_profile_end_vtables();
const char *VNamesBegin = __llvm_profile_begin_vtabnames();
const char *VNamesEnd = __llvm_profile_end_vtabnames();

return __llvm_profile_get_size_for_buffer_internal(
DataBegin, DataEnd, CountersBegin, CountersEnd, BitmapBegin, BitmapEnd,
NamesBegin, NamesEnd);
NamesBegin, NamesEnd, VTableBegin, VTableEnd, VNamesBegin, VNamesEnd);
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
const __llvm_profile_data *End) {
intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
// `sizeof(__llvm_profile_data) - 1` is required in the numerator when
// [Begin, End] represents an inclusive range.
// For ELF, [Begin, End) represents the address of linker-inserted
// symbols `__start__<elf-section>` and `__stop_<elf-section>`.
// Thereby, `End` is one byte past the inclusive range, and
// `sizeof(__llvm_profile_data) - 1` is not necessary in the numerator to get
// the correct number of profile data.
// FIXME: Consider removing `sizeof(__llvm_profile_data) - 1` if this is true
// across platforms.
return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) /
sizeof(__llvm_profile_data);
}
Expand All @@ -71,6 +84,26 @@ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data);
}

// Counts the number of `VTableProfData` elements within the range of [Begin,
// End). Caller should guarantee that End points to one byte past the inclusive
// range.
// FIXME: Add a compiler-rt test to make sure the number of vtables in the
// raw profile is the same as the number of vtable elements in the instrumented
// binary.
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_num_vtable(const VTableProfData *Begin,
const VTableProfData *End) {
// Convert pointers to intptr_t to use integer arithmetic.
intptr_t EndI = (intptr_t)End, BeginI = (intptr_t)Begin;
return (EndI - BeginI) / sizeof(VTableProfData);
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_vtable_section_size(const VTableProfData *Begin,
const VTableProfData *End) {
return (intptr_t)(End) - (intptr_t)(Begin);
}

COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
return sizeof(uint8_t);
Expand Down Expand Up @@ -119,21 +152,33 @@ static int needsCounterPadding(void) {
}

COMPILER_RT_VISIBILITY
void __llvm_profile_get_padding_sizes_for_counters(
int __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmapBytes,
uint64_t *PaddingBytesAfterNames) {
uint64_t NamesSize, uint64_t VTableSize, uint64_t VNameSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t *PaddingBytesAfterBitmapBytes, uint64_t *PaddingBytesAfterNames,
uint64_t *PaddingBytesAfterVTable, uint64_t *PaddingBytesAfterVName) {
// Counter padding is needed only if continuous mode is enabled.
if (!needsCounterPadding()) {
*PaddingBytesBeforeCounters = 0;
*PaddingBytesAfterCounters =
__llvm_profile_get_num_padding_bytes(CountersSize);
*PaddingBytesAfterBitmapBytes =
__llvm_profile_get_num_padding_bytes(NumBitmapBytes);
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
return;
if (PaddingBytesAfterVTable != NULL)
*PaddingBytesAfterVTable =
__llvm_profile_get_num_padding_bytes(VTableSize);
if (PaddingBytesAfterVName != NULL)
*PaddingBytesAfterVName = __llvm_profile_get_num_padding_bytes(VNameSize);
return 0;
}

// Value profiling not supported in continuous mode at profile-write time.
// Return -1 to alert the incompatibility.
if (VTableSize != 0 || VNameSize != 0)
return -1;

// In continuous mode, the file offsets for headers and for the start of
// counter sections need to be page-aligned.
*PaddingBytesBeforeCounters =
Expand All @@ -142,34 +187,52 @@ void __llvm_profile_get_padding_sizes_for_counters(
*PaddingBytesAfterBitmapBytes =
calculateBytesNeededToPageAlign(NumBitmapBytes);
*PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
// Set these two variables to zero to avoid uninitialized variables
// even if VTableSize and VNameSize are known to be zero.
if (PaddingBytesAfterVTable != NULL)
*PaddingBytesAfterVTable = 0;
if (PaddingBytesAfterVName != NULL)
*PaddingBytesAfterVName = 0;
return 0;
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd) {
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd,
const VTableProfData *VTableBegin, const VTableProfData *VTableEnd,
const char *VNamesBegin, const char *VNamesEnd) {
/* Match logic in __llvm_profile_write_buffer(). */
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
uint64_t CountersSize =
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
const uint64_t NumBitmapBytes =
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
const uint64_t VTableSize =
__llvm_profile_get_vtable_section_size(VTableBegin, VTableEnd);
const uint64_t VNameSize =
__llvm_profile_get_name_size(VNamesBegin, VNamesEnd);

/* Determine how much padding is needed before/after the counters and after
* the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
PaddingBytesAfterVTable, PaddingBytesAfterVNames;
__llvm_profile_get_padding_sizes_for_counters(
DataSize, CountersSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
DataSize, CountersSize, NumBitmapBytes, NamesSize, 0 /* VTableSize */,
0 /* VNameSize */, &PaddingBytesBeforeCounters,
&PaddingBytesAfterCounters, &PaddingBytesAfterBitmapBytes,
&PaddingBytesAfterNames, &PaddingBytesAfterVTable,
&PaddingBytesAfterVNames);

return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
DataSize + PaddingBytesBeforeCounters + CountersSize +
PaddingBytesAfterCounters + NumBitmapBytes +
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames;
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames +
VTableSize + PaddingBytesAfterVTable + VNameSize +
PaddingBytesAfterVNames;
}

COMPILER_RT_VISIBILITY
Expand All @@ -191,7 +254,10 @@ COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
const char *NamesBegin, const char *NamesEnd) {
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, Buffer);
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
CountersEnd, BitmapBegin, BitmapEnd, 0, NamesBegin,
NamesEnd, 0);
// Set virtual table arguments to NULL since they are not supported yet.
return lprofWriteDataImpl(
&BufferWriter, DataBegin, DataEnd, CountersBegin, CountersEnd,
BitmapBegin, BitmapEnd, /*VPDataReader=*/0, NamesBegin, NamesEnd,
/*VTableBegin=*/NULL, /*VTableEnd=*/NULL, /*VNamesBegin=*/NULL,
/*VNamesEnd=*/NULL, /*SkipNameDataWrite=*/0);
}
11 changes: 7 additions & 4 deletions compiler-rt/lib/profile/InstrProfilingFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,18 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
DataBegin, PageSize);
return 1;
}

int Fileno = fileno(File);
/* Determine how much padding is needed before/after the counters and
* after the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
PaddingBytesAfterVTable, PaddingBytesAfterVNames;
__llvm_profile_get_padding_sizes_for_counters(
DataSize, CountersSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);
DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0,
/*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames,
&PaddingBytesAfterVTable, &PaddingBytesAfterVNames);

uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;
uint64_t FileOffsetToCounters = CurrentFileOffset +
Expand Down
8 changes: 6 additions & 2 deletions compiler-rt/lib/profile/InstrProfilingInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd);
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd,
const VTableProfData *VTableBegin, const VTableProfData *VTableEnd,
const char *VNamesBegin, const char *VNamesEnd);

/*!
* \brief Write instrumentation data to the given buffer, given explicit
Expand Down Expand Up @@ -156,7 +158,9 @@ int lprofWriteDataImpl(ProfDataWriter *Writer,
const char *CountersBegin, const char *CountersEnd,
const char *BitmapBegin, const char *BitmapEnd,
VPDataReaderType *VPDataReader, const char *NamesBegin,
const char *NamesEnd, int SkipNameDataWrite);
const char *NamesEnd, const VTableProfData *VTableBegin,
const VTableProfData *VTableEnd, const char *VNamesBegin,
const char *VNamesEnd, int SkipNameDataWrite);

/* Merge value profile data pointed to by SrcValueProfData into
* in-memory profile counters pointed by to DstData. */
Expand Down
23 changes: 21 additions & 2 deletions compiler-rt/lib/profile/InstrProfilingMerge.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ static uintptr_t signextIfWin64(void *V) {
#endif
}

// Skip names section, vtable profile data section and vtable names section
// for runtime profile merge. To merge runtime addresses from multiple
// profiles collected from the same instrumented binary, the binary should be
// loaded at fixed base address (e.g., build with -no-pie, or run with ASLR
// disabled). In this set-up these three sections remain unchanged.
static uint64_t
getDistanceFromCounterToValueProf(const __llvm_profile_header *const Header) {
const uint64_t VTableSectionSize =
Header->NumVTables * sizeof(VTableProfData);
const uint64_t PaddingBytesAfterVTableSection =
__llvm_profile_get_num_padding_bytes(VTableSectionSize);
const uint64_t VNamesSize = Header->VNamesSize;
const uint64_t PaddingBytesAfterVNamesSize =
__llvm_profile_get_num_padding_bytes(VNamesSize);
return Header->NamesSize +
__llvm_profile_get_num_padding_bytes(Header->NamesSize) +
VTableSectionSize + PaddingBytesAfterVTableSection + VNamesSize +
PaddingBytesAfterVNamesSize;
}

COMPILER_RT_VISIBILITY
int __llvm_profile_merge_from_buffer(const char *ProfileData,
uint64_t ProfileSize) {
Expand Down Expand Up @@ -137,8 +157,7 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
SrcBitmapStart = SrcCountersEnd;
SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes;
SrcValueProfDataStart =
SrcNameStart + Header->NamesSize +
__llvm_profile_get_num_padding_bytes(Header->NamesSize);
SrcNameStart + getDistanceFromCounterToValueProf(Header);
if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart)
return 1;

Expand Down
14 changes: 10 additions & 4 deletions compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ void __llvm_profile_register_names_function(void *NamesStart,
uint64_t NamesSize) {}

// The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in
// {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds"})
// {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds",
// "__llvm_prf_vns", "__llvm_prf_vtab"})
// are always live when linking on AIX, regardless if the .o's being linked
// reference symbols from the profile library (for example when no files were
// compiled with -fprofile-generate). That's because these symbols are kept
Expand All @@ -197,6 +198,10 @@ static int dummy_vnds[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
static int dummy_orderfile[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME);
static int dummy_vname[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);
static int dummy_vtab[0] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);

// To avoid GC'ing of the dummy variables by the linker, reference them in an
// array and reference the array in the runtime registration code
Expand All @@ -206,9 +211,10 @@ static int dummy_orderfile[0] COMPILER_RT_SECTION(
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
COMPILER_RT_VISIBILITY
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
(void *)&dummy_data, (void *)&dummy_name,
(void *)&dummy_vnds, (void *)&dummy_orderfile};
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
(void *)&dummy_data, (void *)&dummy_name,
(void *)&dummy_vnds, (void *)&dummy_orderfile,
(void *)&dummy_vname, (void *)&dummy_vtab};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
Expand Down
23 changes: 23 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ extern char
COMPILER_RT_VISIBILITY
extern char BitmapEnd __asm("section$end$__DATA$" INSTR_PROF_BITS_SECT_NAME);
COMPILER_RT_VISIBILITY
extern VTableProfData
VTableProfStart __asm("section$start$__DATA$" INSTR_PROF_VTAB_SECT_NAME);
COMPILER_RT_VISIBILITY
extern VTableProfData
VTableProfEnd __asm("section$end$__DATA$" INSTR_PROF_VTAB_SECT_NAME);
COMPILER_RT_VISIBILITY
extern char
VNameStart __asm("section$start$__DATA$" INSTR_PROF_VNAME_SECT_NAME);
COMPILER_RT_VISIBILITY
extern char VNameEnd __asm("section$end$__DATA$" INSTR_PROF_VNAME_SECT_NAME);
COMPILER_RT_VISIBILITY
extern uint32_t
OrderFileStart __asm("section$start$__DATA$" INSTR_PROF_ORDERFILE_SECT_NAME);

Expand Down Expand Up @@ -65,6 +76,18 @@ char *__llvm_profile_begin_bitmap(void) { return &BitmapStart; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_bitmap(void) { return &BitmapEnd; }
COMPILER_RT_VISIBILITY
const VTableProfData *__llvm_profile_begin_vtables(void) {
return &VTableProfStart;
}
COMPILER_RT_VISIBILITY
const VTableProfData *__llvm_profile_end_vtables(void) {
return &VTableProfEnd;
}
COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_vtabnames(void) { return &VNameStart; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_vtabnames(void) { return &VNameEnd; }
COMPILER_RT_VISIBILITY
uint32_t *__llvm_profile_begin_orderfile(void) { return &OrderFileStart; }

COMPILER_RT_VISIBILITY
Expand Down
21 changes: 21 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@
#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON)
#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_COMMON)
#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON)
#define PROF_VNAME_START INSTR_PROF_SECT_START(INSTR_PROF_VNAME_COMMON)
#define PROF_VNAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNAME_COMMON)
#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON)
#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON)
#define PROF_VTABLE_START INSTR_PROF_SECT_START(INSTR_PROF_VTAB_COMMON)
#define PROF_VTABLE_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VTAB_COMMON)
#define PROF_BITS_START INSTR_PROF_SECT_START(INSTR_PROF_BITS_COMMON)
#define PROF_BITS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_BITS_COMMON)
#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
Expand All @@ -41,6 +45,10 @@ extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY
COMPILER_RT_WEAK;
extern char PROF_CNTS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_CNTS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern VTableProfData PROF_VTABLE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern VTableProfData PROF_VTABLE_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_VNAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_VNAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_BITS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern char PROF_BITS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
Expand All @@ -63,6 +71,19 @@ COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
return &PROF_NAME_STOP;
}
COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_vtabnames(void) {
return &PROF_VNAME_START;
}
COMPILER_RT_VISIBILITY const char *__llvm_profile_end_vtabnames(void) {
return &PROF_VNAME_STOP;
}
COMPILER_RT_VISIBILITY const VTableProfData *
__llvm_profile_begin_vtables(void) {
return &PROF_VTABLE_START;
}
COMPILER_RT_VISIBILITY const VTableProfData *__llvm_profile_end_vtables(void) {
return &PROF_VTABLE_STOP;
}
COMPILER_RT_VISIBILITY char *__llvm_profile_begin_counters(void) {
return &PROF_CNTS_START;
}
Expand Down
15 changes: 15 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformOther.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@

static const __llvm_profile_data *DataFirst = NULL;
static const __llvm_profile_data *DataLast = NULL;
static const VTableProfData *VTableProfDataFirst = NULL;
static const VTableProfData *VTableProfDataLast = NULL;
static const char *NamesFirst = NULL;
static const char *NamesLast = NULL;
static const char *VNamesFirst = NULL;
static const char *VNamesLast = NULL;
static char *CountersFirst = NULL;
static char *CountersLast = NULL;
static uint32_t *OrderFileFirst = NULL;
Expand Down Expand Up @@ -80,11 +84,22 @@ COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; }
COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; }
COMPILER_RT_VISIBILITY const VTableProfData *
__llvm_profile_begin_vtables(void) {
return VTableProfDataFirst;
}
COMPILER_RT_VISIBILITY const VTableProfData *__llvm_profile_end_vtables(void) {
return VTableProfDataLast;
}
COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_names(void) { return NamesFirst; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_names(void) { return NamesLast; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_vtabnames(void) { return VNamesFirst; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_vtabnames(void) { return VNamesLast; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_begin_counters(void) { return CountersFirst; }
COMPILER_RT_VISIBILITY
char *__llvm_profile_end_counters(void) { return CountersLast; }
Expand Down
19 changes: 19 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
|*
\*===----------------------------------------------------------------------===*/

#include <stddef.h>

#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"

Expand Down Expand Up @@ -59,9 +61,26 @@ const __llvm_profile_data *__llvm_profile_begin_data(void) {
}
const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; }

// Type profiling isn't implemented under MSVC ABI, so return NULL (rather than
// implementing linker magic on Windows) to make it more explicit. To elaborate,
// the current type profiling implementation maps a profiled vtable address to a
// vtable variable through vtables mangled name. Under MSVC ABI, the variable
// name for vtables might not be the mangled name (see
// MicrosoftCXXABI::getAddrOfVTable in MicrosoftCXXABI.cpp for more details on
// how a vtable name is computed). Note the mangled name is still in the vtable
// IR (just not variable name) for mapping purpose, but more implementation work
// is required.
const VTableProfData *__llvm_profile_begin_vtables(void) { return NULL; }
const VTableProfData *__llvm_profile_end_vtables(void) { return NULL; }

const char *__llvm_profile_begin_names(void) { return &NamesStart + 1; }
const char *__llvm_profile_end_names(void) { return &NamesEnd; }

// Type profiling isn't supported on Windows, so return NULl to make it more
// explicit.
const char *__llvm_profile_begin_vtabnames(void) { return NULL; }
const char *__llvm_profile_end_vtabnames(void) { return NULL; }

char *__llvm_profile_begin_counters(void) { return &CountersStart + 1; }
char *__llvm_profile_end_counters(void) { return &CountersEnd; }
char *__llvm_profile_begin_bitmap(void) { return &BitmapStart + 1; }
Expand Down
Loading