Skip to content

Commit

Permalink
Reland Implement _ExtInt as an extended int type specifier.
Browse files Browse the repository at this point in the history
I fixed the LLDB issue, so re-applying the patch.

This reverts commit a4b88c0.
  • Loading branch information
Erich Keane committed Apr 17, 2020
1 parent 5f6d93c commit 5f0903e
Show file tree
Hide file tree
Showing 56 changed files with 1,886 additions and 37 deletions.
53 changes: 53 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3461,3 +3461,56 @@ Since the size of ``buffer`` can't be known at compile time, Clang will fold
``__builtin_object_size(buffer, 0)`` into ``-1``. However, if this was written
as ``__builtin_dynamic_object_size(buffer, 0)``, Clang will fold it into
``size``, providing some extra runtime safety.
Extended Integer Types
======================
Clang supports a set of extended integer types under the syntax ``_ExtInt(N)``
where ``N`` is an integer that specifies the number of bits that are used to represent
the type, including the sign bit. The keyword ``_ExtInt`` is a type specifier, thus
it can be used in any place a type can, including as a non-type-template-parameter,
as the type of a bitfield, and as the underlying type of an enumeration.
An extended integer can be declared either signed, or unsigned by using the
``signed``/``unsigned`` keywords. If no sign specifier is used or if the ``signed``
keyword is used, the extended integer type is a signed integer and can represent
negative values.
The ``N`` expression is an integer constant expression, which specifies the number
of bits used to represent the type, following normal integer representations for
both signed and unsigned types. Both a signed and unsigned extended integer of the
same ``N`` value will have the same number of bits in its representation. Many
architectures don't have a way of representing non power-of-2 integers, so these
architectures emulate these types using larger integers. In these cases, they are
expected to follow the 'as-if' rule and do math 'as-if' they were done at the
specified number of bits.
In order to be consistent with the C language specification, and make the extended
integer types useful for their intended purpose, extended integers follow the C
standard integer conversion ranks. An extended integer type has a greater rank than
any integer type with less precision. However, they have lower rank than any
of the built in or other integer types (such as __int128). Usual arithmetic conversions
also work the same, where the smaller ranked integer is converted to the larger.
The one exception to the C rules for integers for these types is Integer Promotion.
Unary +, -, and ~ operators typically will promote operands to ``int``. Doing these
promotions would inflate the size of required hardware on some platforms, so extended
integer types aren't subject to the integer promotion rules in these cases.
In languages (such as OpenCL) that define shift by-out-of-range behavior as a mask,
non-power-of-two versions of these types use an unsigned remainder operation to constrain
the value to the proper range, preventing undefined behavior.
Extended integer types are aligned to the next greatest power-of-2 up to 64 bits.
The size of these types for the purposes of layout and ``sizeof`` are the number of
bits aligned to this calculated alignment. This permits the use of these types in
allocated arrays using common ``sizeof(Array)/sizeof(ElementType)`` pattern.
Extended integer types work with the C _Atomic type modifier, however only precisions
that are powers-of-2 greater than 8 bit are accepted.
Extended integer types align with existing calling conventions. They have the same size
and alignment as the smallest basic type that can contain them. Types that are larger
than 64 bits are handled in the same way as _int128 is handled; they are conceptually
treated as struct of register size chunks. They number of chunks are the smallest
number that can contain the types which does not necessarily mean a power-of-2 size.
8 changes: 8 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ Non-comprehensive list of changes in this release
in the Arm C Language Extensions.


* clang adds support for a set of extended integer types (``_ExtInt(N)``) that
permit non-power of 2 integers, exposing the LLVM integer types. Since a major
motivating use case for these types is to limit 'bit' usage, these types don't
automatically promote to 'int' when operations are done between two ``ExtInt(N)``
types, instead math occurs at the size of the largest ``ExtInt(N)`` type.



New Compiler Flags
------------------

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<ExtIntType> ExtIntTypes;
mutable llvm::FoldingSet<DependentExtIntType> DependentExtIntTypes;

mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
Expand Down Expand Up @@ -1203,6 +1205,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Return a write_only pipe type for the specified type.
QualType getWritePipeType(QualType T) const;

/// Return an extended integer type with the specified signedness and bit
/// count.
QualType getExtIntType(bool Unsigned, unsigned NumBits) const;

/// Return a dependent extended integer type with the specified signedness and
/// bit count.
QualType getDependentExtIntType(bool Unsigned, Expr *BitsExpr) const;

/// Gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,10 @@ DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); })

DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); })

DEF_TRAVERSE_TYPE(ExtIntType, {})
DEF_TRAVERSE_TYPE(DependentExtIntType,
{ TRY_TO(TraverseStmt(T->getNumBitsExpr())); })

#undef DEF_TRAVERSE_TYPE

// ----------------- TypeLoc traversal -----------------
Expand Down Expand Up @@ -1385,6 +1389,11 @@ DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })

DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })

DEF_TRAVERSE_TYPELOC(ExtIntType, {})
DEF_TRAVERSE_TYPELOC(DependentExtIntType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getNumBitsExpr()));
})

#undef DEF_TRAVERSE_TYPELOC

// ----------------- Decl traversal -----------------
Expand Down
70 changes: 67 additions & 3 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
bool isOCLExtOpaqueType() const; // Any OpenCL extension type

bool isPipeType() const; // OpenCL pipe type
bool isExtIntType() const; // Extended Int Type
bool isOpenCLSpecificType() const; // Any OpenCL specific type

/// Determines if this type, which must satisfy
Expand Down Expand Up @@ -6127,6 +6128,64 @@ class PipeType : public Type, public llvm::FoldingSetNode {
bool isReadOnly() const { return isRead; }
};

/// A fixed int type of a specified bitwidth.
class ExtIntType final : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
unsigned IsUnsigned : 1;
unsigned NumBits : 24;

protected:
ExtIntType(bool isUnsigned, unsigned NumBits);

public:
bool isUnsigned() const { return IsUnsigned; }
bool isSigned() const { return !IsUnsigned; }
unsigned getNumBits() const { return NumBits; }

bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, isUnsigned(), getNumBits());
}

static void Profile(llvm::FoldingSetNodeID &ID, bool IsUnsigned,
unsigned NumBits) {
ID.AddBoolean(IsUnsigned);
ID.AddInteger(NumBits);
}

static bool classof(const Type *T) { return T->getTypeClass() == ExtInt; }
};

class DependentExtIntType final : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
const ASTContext &Context;
llvm::PointerIntPair<Expr*, 1, bool> ExprAndUnsigned;

protected:
DependentExtIntType(const ASTContext &Context, bool IsUnsigned,
Expr *NumBits);

public:
bool isUnsigned() const;
bool isSigned() const { return !isUnsigned(); }
Expr *getNumBitsExpr() const;

bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Context, isUnsigned(), getNumBitsExpr());
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool IsUnsigned, Expr *NumBitsExpr);

static bool classof(const Type *T) {
return T->getTypeClass() == DependentExtInt;
}
};

/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {
public:
Expand Down Expand Up @@ -6646,6 +6705,10 @@ inline bool Type::isPipeType() const {
return isa<PipeType>(CanonicalType);
}

inline bool Type::isExtIntType() const {
return isa<ExtIntType>(CanonicalType);
}

#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
inline bool Type::is##Id##Type() const { \
return isSpecificBuiltinType(BuiltinType::Id); \
Expand Down Expand Up @@ -6741,7 +6804,7 @@ inline bool Type::isIntegerType() const {
return IsEnumDeclComplete(ET->getDecl()) &&
!IsEnumDeclScoped(ET->getDecl());
}
return false;
return isExtIntType();
}

inline bool Type::isFixedPointType() const {
Expand Down Expand Up @@ -6798,7 +6861,8 @@ inline bool Type::isScalarType() const {
isa<BlockPointerType>(CanonicalType) ||
isa<MemberPointerType>(CanonicalType) ||
isa<ComplexType>(CanonicalType) ||
isa<ObjCObjectPointerType>(CanonicalType);
isa<ObjCObjectPointerType>(CanonicalType) ||
isExtIntType();
}

inline bool Type::isIntegralOrEnumerationType() const {
Expand All @@ -6811,7 +6875,7 @@ inline bool Type::isIntegralOrEnumerationType() const {
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
return IsEnumDeclComplete(ET->getDecl());

return false;
return isExtIntType();
}

inline bool Type::isBooleanType() const {
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2450,6 +2450,12 @@ inline T TypeLoc::getAsAdjusted() const {
}
return Cur.getAs<T>();
}
class ExtIntTypeLoc final
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, ExtIntTypeLoc,
ExtIntType> {};
class DependentExtIntTypeLoc final
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DependentExtIntTypeLoc,
DependentExtIntType> {};

} // namespace clang

Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -833,3 +833,28 @@ let Class = PipeType in {
return ctx.getPipeType(elementType, isReadOnly);
}]>;
}

let Class = ExtIntType in {
def : Property<"isUnsigned", Bool> {
let Read = [{ node->isUnsigned() }];
}
def : Property <"numBits", UInt32> {
let Read = [{ node->getNumBits() }];
}

def : Creator<[{
return ctx.getExtIntType(isUnsigned, numBits);
}]>;
}

let Class = DependentExtIntType in {
def : Property<"isUnsigned", Bool> {
let Read = [{ node->isUnsigned() }];
}
def : Property <"numBitsExpr", ExprRef> {
let Read = [{ node->getNumBitsExpr() }];
}
def : Creator<[{
return ctx.getDependentExtIntType(isUnsigned, numBitsExpr);
}]>;
}
14 changes: 10 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5947,10 +5947,12 @@ def err_block_return_missing_expr : Error<
"non-void block should return a value">;
def err_func_def_incomplete_result : Error<
"incomplete result type %0 in function definition">;
def err_atomic_specifier_bad_type : Error<
"_Atomic cannot be applied to "
"%select{incomplete |array |function |reference |atomic |qualified |sizeless |}0type "
"%1 %select{|||||||which is not trivially copyable}0">;
def err_atomic_specifier_bad_type
: Error<"_Atomic cannot be applied to "
"%select{incomplete |array |function |reference |atomic |qualified "
"|sizeless ||integer |integer }0type "
"%1 %select{|||||||which is not trivially copyable|with less than "
"1 byte of precision|with a non power of 2 precision}0">;

// Expressions.
def select_unary_expr_or_type_trait_kind : TextSubstitution<
Expand Down Expand Up @@ -10711,4 +10713,8 @@ def warn_sycl_kernel_return_type : Warning<
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
InGroup<IgnoredAttributes>;

def err_ext_int_bad_size : Error<"%select{signed|unsigned}0 _ExtInt must "
"have a bit size of at least %select{2|1}0">;
def err_ext_int_max_size : Error<"%select{signed|unsigned}0 _ExtInt of bit "
"sizes greater than %1 not supported">;
} // end of sema component.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Specifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace clang {
TST_char32, // C++11 char32_t
TST_int,
TST_int128,
TST_extint, // Extended Int types.
TST_half, // OpenCL half, ARM NEON __fp16
TST_Float16, // C11 extension ISO/IEC TS 18661-3
TST_Accum, // ISO/IEC JTC1 SC22 WG14 N1169 Extension
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ KEYWORD(goto , KEYALL)
KEYWORD(if , KEYALL)
KEYWORD(inline , KEYC99|KEYCXX|KEYGNU)
KEYWORD(int , KEYALL)
KEYWORD(_ExtInt , KEYALL)
KEYWORD(long , KEYALL)
KEYWORD(register , KEYALL)
KEYWORD(restrict , KEYC99)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,5 @@ def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
def ObjCObjectPointerType : TypeNode<Type>;
def PipeType : TypeNode<Type>;
def AtomicType : TypeNode<Type>;
def ExtIntType : TypeNode<Type>;
def DependentExtIntType : TypeNode<Type>, AlwaysDependent;
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,7 @@ class Parser : public CodeCompletionHandler {
SourceLocation &EllipsisLoc);
void ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation *endLoc = nullptr);
ExprResult ParseExtIntegerArgument();

VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const;
VirtSpecifiers::Specifier isCXX11VirtSpecifier() const {
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class DeclSpec {
static const TST TST_char32 = clang::TST_char32;
static const TST TST_int = clang::TST_int;
static const TST TST_int128 = clang::TST_int128;
static const TST TST_extint = clang::TST_extint;
static const TST TST_half = clang::TST_half;
static const TST TST_float = clang::TST_float;
static const TST TST_double = clang::TST_double;
Expand Down Expand Up @@ -413,7 +414,7 @@ class DeclSpec {
T == TST_underlyingType || T == TST_atomic);
}
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
return (T == TST_typeofExpr || T == TST_decltype || T == TST_extint);
}
static bool isTemplateIdRep(TST T) {
return (T == TST_auto || T == TST_decltype_auto);
Expand Down Expand Up @@ -704,6 +705,9 @@ class DeclSpec {
bool SetTypePipe(bool isPipe, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy);
bool SetExtIntType(SourceLocation KWLoc, Expr *BitWidth,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy);
bool SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
bool SetTypeSpecError();
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,7 @@ class Sema final {
SourceLocation Loc);
QualType BuildWritePipeType(QualType T,
SourceLocation Loc);
QualType BuildExtIntType(bool IsUnsigned, Expr *BitWidth, SourceLocation Loc);

TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/TypeBitCodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,7 @@ TYPE_BIT_CODE(DependentSizedExtVector, DEPENDENT_SIZED_EXT_VECTOR, 46)
TYPE_BIT_CODE(DependentAddressSpace, DEPENDENT_ADDRESS_SPACE, 47)
TYPE_BIT_CODE(DependentVector, DEPENDENT_SIZED_VECTOR, 48)
TYPE_BIT_CODE(MacroQualified, MACRO_QUALIFIED, 49)
TYPE_BIT_CODE(ExtInt, EXT_INT, 50)
TYPE_BIT_CODE(DependentExtInt, DEPENDENT_EXT_INT, 51)

#undef TYPE_BIT_CODE
Loading

0 comments on commit 5f0903e

Please sign in to comment.