diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2376,6 +2376,9 @@ bool isAlignmentRequired(const Type *T) const; bool isAlignmentRequired(QualType T) const; + /// More type predicates useful for type checking/promotion + bool isPromotableIntegerType(QualType T) const; // C99 6.3.1.1p2 + /// Return the "preferred" alignment of the specified type \p T for /// the current target, in bits. /// diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -305,7 +305,6 @@ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasSignedIntegerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasUnsignedIntegerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasFloatingRepresentation) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerOrEnumerationType) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2430,9 +2430,6 @@ /// removing any typedefs, typeofs, etc., as well as any qualifiers. const Type *getUnqualifiedDesugaredType() const; - /// More type predicates useful for type checking/promotion - bool isPromotableIntegerType() const; // C99 6.3.1.1p2 - /// Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// or an enum decl which has a signed representation. diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h @@ -676,14 +676,14 @@ assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!"); // Always perform integer promotion before checking type equality. // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion - if (LTy->isPromotableIntegerType()) { + if (Ctx.isPromotableIntegerType(LTy)) { QualType NewTy = Ctx.getPromotedIntegerType(LTy); uint64_t NewBitWidth = Ctx.getTypeSize(NewTy); LHS = (*doCast)(Solver, LHS, NewTy, NewBitWidth, LTy, LBitWidth); LTy = NewTy; LBitWidth = NewBitWidth; } - if (RTy->isPromotableIntegerType()) { + if (Ctx.isPromotableIntegerType(RTy)) { QualType NewTy = Ctx.getPromotedIntegerType(RTy); uint64_t NewBitWidth = Ctx.getTypeSize(NewTy); RHS = (*doCast)(Solver, RHS, NewTy, NewBitWidth, RTy, RBitWidth); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1895,6 +1895,44 @@ return getTypeInfoInChars(T.getTypePtr()); } +bool ASTContext::isPromotableIntegerType(QualType T) const { + // HLSL doesn't promote all small integer types to int, it + // just uses the rank-based promotion rules for all types. + if (getLangOpts().HLSL) + return false; + + if (const auto *BT = T->getAs()) + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + return true; + default: + return false; + } + + // Enumerated types are promotable to their compatible integer types + // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). + if (const auto *ET = T->getAs()) { + if (T->isDependentType() || ET->getDecl()->getPromotionType().isNull() || + ET->getDecl()->isScoped()) + return false; + + return true; + } + + return false; +} + bool ASTContext::isAlignmentRequired(const Type *T) const { return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None; } @@ -7080,7 +7118,7 @@ /// integer type. QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); - assert(Promotable->isPromotableIntegerType()); + assert(isPromotableIntegerType(Promotable)); if (const auto *ET = Promotable->getAs()) return ET->getDecl()->getPromotionType(); @@ -10277,7 +10315,7 @@ return {}; } - if (paramTy->isPromotableIntegerType() || + if (isPromotableIntegerType(paramTy) || getCanonicalType(paramTy).getUnqualifiedType() == FloatTy) return {}; } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -510,7 +510,7 @@ if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt) return Match; - QualType PromoArg = argTy->isPromotableIntegerType() + QualType PromoArg = C.isPromotableIntegerType(argTy) ? C.getPromotedIntegerType(argTy) : argTy; PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2777,39 +2777,6 @@ return false; } -bool Type::isPromotableIntegerType() const { - if (const auto *BT = getAs()) - switch (BT->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - case BuiltinType::Char8: - case BuiltinType::Char16: - case BuiltinType::Char32: - return true; - default: - return false; - } - - // Enumerated types are promotable to their compatible integer types - // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). - if (const auto *ET = getAs()){ - if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull() - || ET->getDecl()->isScoped()) - return false; - - return true; - } - - return false; -} - bool Type::isSpecifierType() const { // Note that this intentionally does not use the canonical type. switch (getTypeClass()) { diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -159,7 +159,7 @@ return llvm::None; QualType BaseTy = Base->getType(); - if (!BaseTy->isPromotableIntegerType() || + if (!Ctx.isPromotableIntegerType(BaseTy) || Ctx.getTypeSize(BaseTy) >= Ctx.getTypeSize(E->getType())) return llvm::None; @@ -2612,7 +2612,7 @@ } else if (type->isIntegerType()) { QualType promotedType; bool canPerformLossyDemotionCheck = false; - if (type->isPromotableIntegerType()) { + if (CGF.getContext().isPromotableIntegerType(type)) { promotedType = CGF.getContext().getPromotedIntegerType(type); assert(promotedType != type && "Shouldn't promote to the same type."); canPerformLossyDemotionCheck = true; diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -106,7 +106,7 @@ } bool ABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const { - if (Ty->isPromotableIntegerType()) + if (getContext().isPromotableIntegerType(Ty)) return true; if (const auto *EIT = Ty->getAs()) @@ -4581,7 +4581,7 @@ Ty = EnumTy->getDecl()->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. - if (Ty->isPromotableIntegerType()) + if (getContext().isPromotableIntegerType(Ty)) return true; if (!Is64Bit) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7170,7 +7170,7 @@ Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { // Promotable integers are UB, but enumerations need a bit of // extra checking to see what their promotable type actually is. - if (!Type->isPromotableIntegerType()) + if (!Context.isPromotableIntegerType(Type)) return false; if (!Type->isEnumeralType()) return true; @@ -10040,7 +10040,7 @@ // It's an integer promotion if the destination type is the promoted // source type. if (ICE->getCastKind() == CK_IntegralCast && - From->isPromotableIntegerType() && + S.Context.isPromotableIntegerType(From) && S.Context.getPromotedIntegerType(From) == To) return true; // Look through vector types, since we do default argument promotion for diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16373,7 +16373,7 @@ else ED->setIntegerType(QualType(EnumUnderlying.get(), 0)); QualType EnumTy = ED->getIntegerType(); - ED->setPromotionType(EnumTy->isPromotableIntegerType() + ED->setPromotionType(Context.isPromotableIntegerType(EnumTy) ? Context.getPromotedIntegerType(EnumTy) : EnumTy); } @@ -16999,7 +16999,7 @@ else ED->setIntegerType(QualType(EnumUnderlying.get(), 0)); QualType EnumTy = ED->getIntegerType(); - ED->setPromotionType(EnumTy->isPromotableIntegerType() + ED->setPromotionType(Context.isPromotableIntegerType(EnumTy) ? Context.getPromotedIntegerType(EnumTy) : EnumTy); assert(ED->isComplete() && "enum with type should be complete"); @@ -19231,7 +19231,7 @@ // target, promote that type instead of analyzing the enumerators. if (Enum->isComplete()) { BestType = Enum->getIntegerType(); - if (BestType->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(BestType)) BestPromotionType = Context.getPromotedIntegerType(BestType); else BestPromotionType = BestType; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -837,7 +837,7 @@ E = ImpCastExprToType(E, PTy, CK_IntegralCast).get(); return E; } - if (Ty->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(Ty)) { QualType PT = Context.getPromotedIntegerType(Ty); E = ImpCastExprToType(E, PT, CK_IntegralCast).get(); return E; @@ -1556,7 +1556,7 @@ // Apply unary and bitfield promotions to the LHS's type. QualType LHSUnpromotedType = LHSType; - if (LHSType->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSType)) LHSType = Context.getPromotedIntegerType(LHSType); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) @@ -11236,7 +11236,7 @@ QualType LHSTy = Context.isPromotableBitField(LHS.get()); if (LHSTy.isNull()) { LHSTy = LHS.get()->getType(); - if (LHSTy->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSTy)) LHSTy = Context.getPromotedIntegerType(LHSTy); } *CompLHSTy = LHSTy; @@ -12255,7 +12255,7 @@ // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we // promote the boolean type, and all other promotable integer types, to // avoid this. - if (IntType->isPromotableIntegerType()) + if (S.Context.isPromotableIntegerType(IntType)) IntType = S.Context.getPromotedIntegerType(IntType); LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast); @@ -15513,7 +15513,7 @@ if (T.isNull() || T->isDependentType()) return false; - if (!T->isPromotableIntegerType()) + if (!Ctx.isPromotableIntegerType(T)) return true; return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); @@ -16603,7 +16603,7 @@ // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; - if (TInfo->getType()->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(TInfo->getType())) { PromoteType = Context.getPromotedIntegerType(TInfo->getType()); // [cstdarg.syn]p1 defers the C++ behavior to what the C standard says, // and C2x 7.16.1.1p2 says, in part: diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2934,7 +2934,7 @@ // Compute the type of the integer literals. QualType PromotedCharTy = CharTy; - if (CharTy->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(CharTy)) PromotedCharTy = Context.getPromotedIntegerType(CharTy); unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2078,9 +2078,9 @@ // int can represent all the values of the source type; otherwise, // the source rvalue can be converted to an rvalue of type unsigned // int (C++ 4.5p1). - if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() && + if (Context.isPromotableIntegerType(FromType) && !FromType->isBooleanType() && !FromType->isEnumeralType()) { - if (// We can promote any signed, promotable integer type to an int + if ( // We can promote any signed, promotable integer type to an int (FromType->isSignedIntegerType() || // We can promote any unsigned integer type whose size is // less than int to an int. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5425,7 +5425,7 @@ D.setInvalidType(); } } else if (!FTI.hasPrototype) { - if (ParamTy->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(ParamTy)) { ParamTy = Context.getPromotedIntegerType(ParamTy); Param->setKNRPromoted(true); } else if (const BuiltinType* BTy = ParamTy->getAs()) { diff --git a/clang/test/CodeGenHLSL/builtins/abs.hlsl b/clang/test/CodeGenHLSL/builtins/abs.hlsl --- a/clang/test/CodeGenHLSL/builtins/abs.hlsl +++ b/clang/test/CodeGenHLSL/builtins/abs.hlsl @@ -7,8 +7,7 @@ // CHECK: define noundef signext i16 @ -// FIXME: int16_t is promoted to i32 now. Change to abs.i16 once it is fixed. -// CHECK: call i32 @llvm.abs.i32( +// CHECK: call i16 @llvm.abs.i16( int16_t test_abs_int16_t ( int16_t p0 ) { return abs ( p0 ); } diff --git a/clang/test/CodeGenHLSL/no_int_promotion.hlsl b/clang/test/CodeGenHLSL/no_int_promotion.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/no_int_promotion.hlsl @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -D__HLSL_ENABLE_16_BIT \ +// RUN: -emit-llvm -disable-llvm-passes -O3 -o - | FileCheck %s + +// FIXME: add test for char/int8_t/uint8_t when these types are supported in HLSL. +// See https://github.com/llvm/llvm-project/issues/58453. + +// Make sure generate i16 add. +// CHECK: add nsw i16 % +int16_t add(int16_t a, int16_t b) { + return a + b; +} +// CHECK: define noundef <2 x i16> @ +// CHECK: add <2 x i16> +int16_t2 add(int16_t2 a, int16_t2 b) { + return a + b; +} +// CHECK: define noundef <3 x i16> @ +// CHECK: add <3 x i16> +int16_t3 add(int16_t3 a, int16_t3 b) { + return a + b; +} +// CHECK: define noundef <4 x i16> @ +// CHECK: add <4 x i16> +int16_t4 add(int16_t4 a, int16_t4 b) { + return a + b; +} +// CHECK: define noundef zeroext i16 @ +// CHECK: add i16 % +uint16_t add(uint16_t a, uint16_t b) { + return a + b; +} +// CHECK: define noundef <2 x i16> @ +// CHECK: add <2 x i16> +uint16_t2 add(uint16_t2 a, uint16_t2 b) { + return a + b; +} +// CHECK: define noundef <3 x i16> @ +// CHECK: add <3 x i16> +uint16_t3 add(uint16_t3 a, uint16_t3 b) { + return a + b; +} +// CHECK: define noundef <4 x i16> @ +// CHECK: add <4 x i16> +uint16_t4 add(uint16_t4 a, uint16_t4 b) { + return a + b; +} diff --git a/clang/test/SemaHLSL/BitInt128.hlsl b/clang/test/SemaHLSL/BitInt128.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/SemaHLSL/BitInt128.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s -verify + +// expected-error@+1 {{_BitInt is not supported on this target}} +_BitInt(128) i128; + +// expected-error@+1 {{_BitInt is not supported on this target}} +unsigned _BitInt(128) u128;