Merge remote-tracking branch 'origin/hlsl-2021' into merge-hlsl2021-master

This commit is contained in:
Greg Roth 2021-09-21 13:01:07 -07:00
Родитель a6cf6a06b6 f1405e3542
Коммит a4dfa1c40c
106 изменённых файлов: 4191 добавлений и 436 удалений

Просмотреть файл

@ -123,6 +123,7 @@ import hctdb_instrhelp
IOP_abs,
IOP_acos,
IOP_all,
IOP_and,
IOP_any,
IOP_asdouble,
IOP_asfloat,
@ -185,6 +186,7 @@ import hctdb_instrhelp
IOP_msad4,
IOP_mul,
IOP_normalize,
IOP_or,
IOP_pack_clamp_s8,
IOP_pack_clamp_u8,
IOP_pack_s8,
@ -199,6 +201,7 @@ import hctdb_instrhelp
IOP_round,
IOP_rsqrt,
IOP_saturate,
IOP_select,
IOP_sign,
IOP_sin,
IOP_sincos,

Просмотреть файл

@ -199,6 +199,12 @@ public:
unsigned ScanLimit = 0; // OPT_memdep_block_scan_limit
bool ForceZeroStoreLifetimes = false; // OPT_force_zero_store_lifetimes
bool EnableLifetimeMarkers = false; // OPT_enable_lifetime_markers
bool EnableTemplates = false; // OPT_enable_templates
bool EnableOperatorOverloading = false; // OPT_enable_operator_overloading
bool StrictUDTCasting = false; // OPT_strict_udt_casting
// Experimental option to enable short-circuiting operators
bool EnableShortCircuit = false; // OPT_enable_short_circuit
// Optimization pass enables, disables and selects
std::map<std::string, bool> DxcOptimizationToggles; // OPT_opt_enable & OPT_opt_disable

Просмотреть файл

@ -288,6 +288,12 @@ def enable_lifetime_markers : Flag<["-", "/"], "enable-lifetime-markers">, Group
HelpText<"Enable generation of lifetime markers">;
def disable_lifetime_markers : Flag<["-", "/"], "disable-lifetime-markers">, Group<hlslcomp_Group>, Flags<[CoreOption, HelpHidden]>,
HelpText<"Disable generation of lifetime markers where they would be otherwise (6.6+)">;
def enable_templates: Flag<["-", "/"], "enable-templates">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
HelpText<"Enable template support for HLSL.">;
def enable_operator_overloading: Flag<["-", "/"], "enable-operator-overloading">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
HelpText<"Enable operator overloading support for HLSL.">;
def strict_udt_casting: Flag<["-", "/"], "strict-udt-casting">, Group<hlslcomp_Group>, Flags<[CoreOption, HelpHidden]>,
HelpText<"Require explicit casts between different structure types with compatible layouts.">;
def enable_payload_qualifiers : Flag<["-", "/"], "enable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
HelpText<"Enables support for payload access qualifiers for raytracing payloads in SM 6.6.">;
def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
@ -452,6 +458,9 @@ def Qstrip_reflect_from_dxil : Flag<["-", "/"], "Qstrip_reflect_from_dxil">,
Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
HelpText<"Strip reflection data from shader bytecode (must be used with /Fo <file>)">;
def enable_short_circuit : Flag<["-", "/"], "enable-short-circuit">, Flags<[CoreOption, HelpHidden]>, Group<hlslcomp_Group>,
HelpText<"Operators '&&', '||', and '?:' will short circuit, only accepting scalar inputs. Use and(), or(), and select() intrinsics in place of non-short-circuiting vector operators.">;
/*
def shtemplate : JoinedOrSeparate<["-", "/"], "shtemplate">, MetaVarName<"<file>">, Group<hlslcomp_Group>,
HelpText<"Template shader file for merging/matching resources">;

Просмотреть файл

@ -475,6 +475,19 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.EnableFXCCompatMode = true;
}
// If the HLSL version is 2021, allow the operator overloading by default.
// If the HLSL version is 2016 or 2018, allow the operator overloading only
// when -enable-operator-overloading option is enabled.
// If the HLSL version is 2015, do not allow the operator overloading.
opts.EnableOperatorOverloading =
opts.HLSLVersion >= 2021 ||
Args.hasFlag(OPT_enable_operator_overloading, OPT_INVALID, false);
if (opts.HLSLVersion <= 2015 && opts.EnableOperatorOverloading) {
errors << "/enable-operator-overloading is not supported with HLSL Version "
<< opts.HLSLVersion;
return 1;
}
// AssemblyCodeHex not supported (Fx)
// OutputLibrary not supported (Fl)
opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
@ -482,6 +495,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.ImportBindingTable = Args.getLastArgValue(OPT_import_binding_table);
opts.ExtractPrivateFile = Args.getLastArgValue(OPT_getprivate);
opts.Enable16BitTypes = Args.hasFlag(OPT_enable_16bit_types, OPT_INVALID, false);
opts.EnableTemplates = Args.hasFlag(OPT_enable_templates, OPT_INVALID, false);
opts.EnableOperatorOverloading =
Args.hasFlag(OPT_enable_operator_overloading, OPT_INVALID, false);
opts.StrictUDTCasting = Args.hasFlag(OPT_strict_udt_casting, OPT_INVALID, false);
opts.OutputObject = Args.getLastArgValue(OPT_Fo);
opts.OutputHeader = Args.getLastArgValue(OPT_Fh);
opts.OutputWarningsFile = Args.getLastArgValue(OPT_Fe);
@ -695,6 +712,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
!Args.hasFlag(OPT_disable_lifetime_markers, OPT_INVALID, false);
opts.EnablePayloadQualifiers = Args.hasFlag(OPT_enable_payload_qualifiers, OPT_INVALID,
DXIL::CompareVersions(Major, Minor, 6, 7) >= 0);
// Experimental option to enable short-circuiting operators
opts.EnableShortCircuit = Args.hasFlag(OPT_enable_short_circuit, OPT_INVALID, false);
if (DXIL::CompareVersions(Major, Minor, 6, 8) < 0) {
opts.EnablePayloadQualifiers &= !Args.hasFlag(OPT_disable_payload_qualifiers, OPT_INVALID, false);
}

Просмотреть файл

@ -5338,6 +5338,72 @@ Value *TranslateGetHandleFromHeap(CallInst *CI, IntrinsicOp IOP,
}
}
// Translate and/or/select intrinsics
namespace {
Value *TranslateAnd(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
Value *x = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc0Idx);
Value *y = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
Type *Ty = CI->getType();
Type *EltTy = Ty->getScalarType();
IRBuilder<> Builder(CI);
if (Ty != EltTy) {
Value *Result = UndefValue::get(Ty);
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
Value *EltX = Builder.CreateExtractElement(x, i);
Value *EltY = Builder.CreateExtractElement(y, i);
Value *tmp = Builder.CreateAnd(EltX, EltY);
Result = Builder.CreateInsertElement(Result, tmp, i);
}
return Result;
}
return Builder.CreateAnd(x, y);
}
Value *TranslateOr(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
Value *x = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc0Idx);
Value *y = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
Type *Ty = CI->getType();
Type *EltTy = Ty->getScalarType();
IRBuilder<> Builder(CI);
if (Ty != EltTy) {
Value *Result = UndefValue::get(Ty);
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
Value *EltX = Builder.CreateExtractElement(x, i);
Value *EltY = Builder.CreateExtractElement(y, i);
Value *tmp = Builder.CreateOr(EltX, EltY);
Result = Builder.CreateInsertElement(Result, tmp, i);
}
return Result;
}
return Builder.CreateOr(x, y);
}
Value *TranslateSelect(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
Value *cond = CI->getArgOperand(HLOperandIndex::kTrinaryOpSrc0Idx);
Value *t = CI->getArgOperand(HLOperandIndex::kTrinaryOpSrc1Idx);
Value *f = CI->getArgOperand(HLOperandIndex::kTrinaryOpSrc2Idx);
Type *Ty = CI->getType();
Type *EltTy = Ty->getScalarType();
IRBuilder<> Builder(CI);
if (Ty != EltTy) {
Value *Result = UndefValue::get(Ty);
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
Value *EltCond = Builder.CreateExtractElement(cond, i);
Value *EltTrue = Builder.CreateExtractElement(t, i);
Value *EltFalse = Builder.CreateExtractElement(f, i);
Value *tmp = Builder.CreateSelect(EltCond, EltTrue, EltFalse);
Result = Builder.CreateInsertElement(Result, tmp, i);
}
return Result;
}
return Builder.CreateSelect(cond, t, f);
}
}
// Lower table.
namespace {
@ -5475,6 +5541,7 @@ IntrinsicLower gLowerTable[] = {
{IntrinsicOp::IOP_abs, TranslateAbs, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_acos, TrivialUnaryOperation, DXIL::OpCode::Acos},
{IntrinsicOp::IOP_all, TranslateAll, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_and, TranslateAnd, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_any, TranslateAny, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_asdouble, TranslateAsDouble, DXIL::OpCode::MakeDouble},
{IntrinsicOp::IOP_asfloat, TranslateBitcast, DXIL::OpCode::NumOpCodes},
@ -5537,6 +5604,7 @@ IntrinsicLower gLowerTable[] = {
{IntrinsicOp::IOP_msad4, TranslateMSad4, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_mul, TranslateMul, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_normalize, TranslateNormalize, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_or, TranslateOr, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_pack_clamp_s8, TranslatePack, DXIL::OpCode::Pack4x8 },
{IntrinsicOp::IOP_pack_clamp_u8, TranslatePack, DXIL::OpCode::Pack4x8 },
{IntrinsicOp::IOP_pack_s8, TranslatePack, DXIL::OpCode::Pack4x8 },
@ -5551,6 +5619,7 @@ IntrinsicLower gLowerTable[] = {
{IntrinsicOp::IOP_round, TrivialUnaryOperation, DXIL::OpCode::Round_ne},
{IntrinsicOp::IOP_rsqrt, TrivialUnaryOperation, DXIL::OpCode::Rsqrt},
{IntrinsicOp::IOP_saturate, TrivialUnaryOperation, DXIL::OpCode::Saturate},
{IntrinsicOp::IOP_select, TranslateSelect, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_sign, TranslateSign, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_sin, TrivialUnaryOperation, DXIL::OpCode::Sin},
{IntrinsicOp::IOP_sincos, EmptyLower, DXIL::OpCode::NumOpCodes},

Просмотреть файл

@ -66,6 +66,9 @@ def warn_method_param_declaration : Warning<"redeclaration of method parameter %
def err_invalid_storage_class_in_func_decl : Error<
"invalid storage class specifier in function declarator">;
def err_expected_namespace_name : Error<"expected namespace name">;
// HLSL Change Starts
def err_hlsl_variadic_templates : Error<"variadic templates are not supported in HLSL">;
// HLSL Change Ends
def ext_variadic_templates : ExtWarn<
"variadic templates are a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_variadic_templates :

Просмотреть файл

@ -192,4 +192,8 @@ def warn_target_unsupported_nan2008 : Warning<
def warn_target_unsupported_nanlegacy : Warning<
"ignoring '-mnan=legacy' option because the '%0' architecture does not support it">,
InGroup<UnsupportedNan>;
// HLSL Change Starts
def err_hlsl_invalid_drv_for_operator_overloading : Error<"/enable-operator-overloading is not supported with HLSL Version '%0'">;
// HLSL Change Ends
}

Просмотреть файл

@ -797,4 +797,5 @@ def HLSLPayloadAccessQualifer: DiagGroup<"payload-access-qualifier", [
HLSLPayloadAccessQualiferPerf,
HLSLPayloadAccessQualiferCall
]>;
def HLSLSemanticIdentifierCollision : DiagGroup<"semantic-identifier-collision">;
// HLSL Change Ends

Просмотреть файл

@ -1022,6 +1022,9 @@ def warn_hlsl_effect_state_block : Warning <
def warn_hlsl_effect_technique : Warning <
"effect technique ignored - effect syntax is deprecated">,
InGroup< HLSLEffectsSyntax >;
def warn_hlsl_semantic_identifier_collision : Warning <
"'%0' interpreted as semantic; previous definition(s) ignored">,
InGroup< HLSLSemanticIdentifierCollision >;
def err_hlsl_enum : Error<
"enum is unsupported in HLSL before 2017">;

Просмотреть файл

@ -7481,6 +7481,8 @@ def err_hlsl_matrix_member_too_many_positions: Error<
"more than four positions are referenced in '%0'">;
def err_hlsl_matrix_member_zero_in_one_based: Error<
"the digit '0' is used in '%0', but the syntax is for one-based rows and columns">;
def err_hlsl_overloading_new_delete_operator: Error<
"overloading %0 is not allowed">;
def err_hlsl_vector_member_bad_format: Error<
"invalid format for vector swizzle '%0'">;
def err_hlsl_vector_member_empty: Error<
@ -7746,6 +7748,10 @@ def err_hlsl_load_from_mesh_out_arrays: Error<
"output arrays of a mesh shader can not be read from">;
def err_hlsl_out_indices_array_incorrect_access: Error<
"a vector in out indices array must be accessed as a whole">;
def err_hlsl_logical_binop_scalar : Error<
"operands for short-circuiting logical binary operator must be scalar">;
def err_hlsl_ternary_scalar : Error<
"condition for short-circuiting ternary operator must be scalar">;
// HLSL Change Ends
// SPIRV Change Starts

Просмотреть файл

@ -149,16 +149,20 @@ public:
#endif
// HLSL Change Starts
unsigned HLSLVersion;
unsigned HLSLVersion = 2018;
std::string HLSLEntryFunction;
std::string HLSLProfile;
unsigned RootSigMajor;
unsigned RootSigMinor;
bool IsHLSLLibrary;
bool UseMinPrecision; // use min precision, not native precision.
bool EnableDX9CompatMode;
bool EnableFXCCompatMode;
bool EnablePayloadAccessQualifiers;
unsigned RootSigMajor = 1;
unsigned RootSigMinor = 1;
bool IsHLSLLibrary = false;
bool UseMinPrecision = true; // use min precision, not native precision.
bool EnableDX9CompatMode = false;
bool EnableFXCCompatMode = false;
bool EnableTemplates = false;
bool EnableOperatorOverloading = false;
bool StrictUDTCasting = false;
bool EnablePayloadAccessQualifiers = false;
bool EnableShortCircuit = false;
// HLSL Change Ends
bool SPIRV = false; // SPIRV Change

Просмотреть файл

@ -680,6 +680,12 @@ def hlsl_version : Separate<["-", "/"], "HV">, Group<f_Group>, Flags<[DriverOpti
HelpText<"HLSL version (2015, 2016, 2017)">; // HLSL Change - mimic the HLSLOptions.td flag
def enable_16bit_types: Flag<["-", "/"], "enable-16bit-types">, Flags<[CoreOption, DriverOption, HelpHidden]>,
HelpText<"Enable 16bit types and disable min precision types.">; // HLSL Change - mimic the HLSLOptions.td flag
def enable_templates: Flag<["-", "/"], "enable-templates">, Flags<[CoreOption, DriverOption, HelpHidden]>,
HelpText<"Enable template support for HLSL.">; // HLSL Change
def enable_operator_overloading: Flag<["-", "/"], "enable-operator-overloading">, Flags<[CoreOption, DriverOption, HelpHidden]>,
HelpText<"Enable operator overloading support for HLSL.">; // HLSL Change
def strict_udt_casting: Flag<["-", "/"], "strict-udt-casting">, Flags<[CoreOption, DriverOption, HelpHidden]>,
HelpText<"Require explicit casts between different structure types with compatible layouts.">;
def fms_compatibility_version
: Joined<["-"], "fms-compatibility-version=">,
Group<f_Group>,

Просмотреть файл

@ -18,6 +18,13 @@
namespace clang {
namespace spirv {
/// Returns a string name for the function if |fn| is not an overloaded
/// operator. Otherwise, returns the name of the operator. If
/// |addClassNameWithOperator| is true, adds the name of RecordType that
/// defines the overloaded operator in front of the operator name.
std::string getFunctionOrOperatorName(const FunctionDecl *fn,
bool addClassNameWithOperator);
/// Returns a string name for the given type.
std::string getAstTypeName(QualType type);
@ -114,6 +121,10 @@ bool isConstantTextureBuffer(QualType);
/// * SubpassInput(MS)
bool isResourceType(QualType);
/// \brief Returns true if the given type is a user-defined struct or class
/// type (not HLSL built-in type).
bool isUserDefinedRecordType(const ASTContext &, QualType);
/// Returns true if the given type is or contains a 16-bit type.
/// The caller must also specify whether 16-bit types have been enabled via
/// command line options.
@ -240,6 +251,12 @@ bool isRWTexture(QualType);
/// \brief Returns true if the given type is an HLSL sampler type.
bool isSampler(QualType);
/// \brief Returns true if the given type is InputPatch.
bool isInputPatch(QualType type);
/// \brief Returns true if the given type is OutputPatch.
bool isOutputPatch(QualType type);
/// \brief Returns true if the given type is SubpassInput.
bool isSubpassInput(QualType);

Просмотреть файл

@ -5507,7 +5507,8 @@ public:
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
bool &MemberOfUnknownSpecialization);
bool &MemberOfUnknownSpecialization,
bool NextIsLess = false); // HLSL Change - additional special case flag
TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
@ -5516,7 +5517,8 @@ public:
ParsedType ObjectType,
bool EnteringContext,
TemplateTy &Template,
bool &MemberOfUnknownSpecialization);
bool &MemberOfUnknownSpecialization,
bool NextIsLess = false); // HLSL Change - additional special case flag
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,

Просмотреть файл

@ -465,9 +465,6 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
llvm_unreachable("No ObjC or OpenCL support");
case BuiltinType::LitInt:
case BuiltinType::LitFloat:
llvm_unreachable("Unsupported HLSL types");
#endif // HLSL Change - no ObjC or OpenCL support
case BuiltinType::UChar:
@ -503,6 +500,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Long:
case BuiltinType::WChar_S:
case BuiltinType::LongLong:
case BuiltinType::LitInt:
Encoding = llvm::dwarf::DW_ATE_signed;
break;
case BuiltinType::Bool:
@ -517,6 +515,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Float:
case BuiltinType::LongDouble:
case BuiltinType::Double:
case BuiltinType::LitFloat:
Encoding = llvm::dwarf::DW_ATE_float;
break;
}

Просмотреть файл

@ -3075,7 +3075,6 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
llvm::Value *Addr = base.getAddress();
unsigned Idx = RL.getLLVMFieldNo(field);
if (Idx != 0)
// For structs, we GEP to the field that the record layout suggests.
Addr = Builder.CreateStructGEP(nullptr, Addr, Idx, field->getName());
// Get the access type.

Просмотреть файл

@ -3420,8 +3420,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// 0 && RHS: If it is safe, just elide the RHS, and return 0/false.
if (!CGF.ContainsLabel(E->getRHS())) {
// HLSL Change Begins.
if (CGF.getLangOpts().HLSL) {
// HLSL does not short circuit.
if (CGF.getLangOpts().HLSL && !CGF.getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
Visit(E->getRHS());
}
// HLSL Change Ends.
@ -3430,8 +3430,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
// HLSL Change Begins.
if (CGF.getLangOpts().HLSL) {
// HLSL does not short circuit.
if (CGF.getLangOpts().HLSL && !CGF.getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
if (ResTy->isVectorTy()) {
@ -3525,8 +3525,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// 1 || RHS: If it is safe, just elide the RHS, and return 1/true.
if (!CGF.ContainsLabel(E->getRHS())) {
// HLSL Change Begins.
if (CGF.getLangOpts().HLSL) {
// HLSL does not short circuit.
if (CGF.getLangOpts().HLSL && !CGF.getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
Visit(E->getRHS());
}
// HLSL Change Ends.
@ -3535,8 +3535,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
}
// HLSL Change Begins.
if (CGF.getLangOpts().HLSL) {
// HLSL does not short circuit.
if (CGF.getLangOpts().HLSL && !CGF.getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
if (ResTy->isVectorTy()) {
@ -3700,8 +3700,9 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return tmp5;
}
// HLSL Change Starts
if (CGF.getLangOpts().HLSL &&
(hlsl::IsHLSLVecType(E->getType()) || E->getType()->isArithmeticType())) {
if (CGF.getLangOpts().HLSL && !CGF.getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
if (hlsl::IsHLSLVecType(E->getType()) || E->getType()->isArithmeticType()) {
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
@ -3720,13 +3721,14 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return Builder.CreateSelect(CondV, LHS, RHS);
}
}
if (CGF.getLangOpts().HLSL && hlsl::IsHLSLMatType(E->getType())) {
if (hlsl::IsHLSLMatType(E->getType())) {
llvm::Value *Cond = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
return CGF.CGM.getHLSLRuntime().EmitHLSLMatrixOperationCall(
CGF, E, LHS->getType(), {Cond, LHS, RHS});
}
}
// HLSL Change Ends
// If this is a really simple expression (like x ? 4 : 5), emit this as a

Просмотреть файл

@ -23,6 +23,7 @@
#include "dxc/DXIL/DxilTypeSystem.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/HlslTypes.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Lex/HLSLMacroExpander.h"
#include "clang/Sema/SemaDiagnostic.h"
@ -991,11 +992,68 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
unsigned CBufferSize = CBufferOffset;
for (auto fieldDecl : RD->fields()) {
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end();
Field != FieldEnd;) {
if (Field->isBitField()) {
// TODO(?): Consider refactoring, as this branch duplicates much
// of the logic of CGRecordLowering::accumulateBitFields().
DXASSERT(CGM.getLangOpts().HLSLVersion > 2015, "We should have already ensured we have no bitfields.");
CodeGenTypes &Types = CGM.getTypes();
ASTContext &Context = Types.getContext();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const llvm::DataLayout &DataLayout = Types.getDataLayout();
RecordDecl::field_iterator End = Field;
for (++End; End != FieldEnd && End->isBitField(); ++End);
RecordDecl::field_iterator Run = End;
uint64_t StartBitOffset, Tail = 0;
for (; Field != End; ++Field) {
uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex());
// Zero-width bitfields end runs.
if (Field->getBitWidthValue(Context) == 0) {
Run = End;
continue;
}
llvm::Type *Type = Types.ConvertTypeForMem(Field->getType());
// If we don't have a run yet, or don't live within the previous run's
// allocated storage then we allocate some storage and start a new run.
if (Run == End || BitOffset >= Tail) {
Run = Field;
StartBitOffset = BitOffset;
Tail = StartBitOffset + DataLayout.getTypeAllocSizeInBits(Type);
QualType fieldTy = Field->getType();
// Align offset.
CBufferOffset = AlignBaseOffset(fieldTy, CBufferOffset, bDefaultRowMajor, CGM, dataLayout);
DxilFieldAnnotation &fieldAnnotation =
annotation->GetFieldAnnotation(fieldIdx++);
ConstructFieldAttributedAnnotation(fieldAnnotation, fieldTy,
bDefaultRowMajor);
fieldAnnotation.SetCBufferOffset(CBufferOffset);
unsigned arrayEltSize = 0;
// Process field to make sure the size of field is ready.
unsigned size = AddTypeAnnotation(fieldTy, dxilTypeSys,
arrayEltSize);
// Update offset.
CBufferOffset += size;
}
}
CBufferSize = CBufferOffset;
continue; // Field has already been advanced past bitfields
}
FieldDecl *fieldDecl = *Field;
std::string fieldSemName = "";
QualType fieldTy = fieldDecl->getType();
DXASSERT(!fieldDecl->isBitField(), "We should have already ensured we have no bitfields.");
// Align offset.
CBufferOffset = AlignBaseOffset(fieldTy, CBufferOffset, bDefaultRowMajor, CGM, dataLayout);
DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(fieldIdx++);
ConstructFieldAttributedAnnotation(fieldAnnotation, fieldTy, bDefaultRowMajor);
@ -1081,6 +1139,8 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
// Update offset.
CBufferSize = std::max(CBufferSize, CBufferOffset + size);
CBufferOffset = CBufferSize;
++Field;
}
annotation->SetCBufferSize(CBufferSize);

Просмотреть файл

@ -1088,8 +1088,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
}
// HLSL Change Begins.
if (getLangOpts().HLSL) {
// HLSL don't short circuit.
if (getLangOpts().HLSL && !getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
// Emit the code with the fully general case.
llvm::Value *CondV;
{
@ -1148,8 +1148,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
}
// HLSL Change Begins.
if (getLangOpts().HLSL) {
// HLSL don't short circuit.
if (getLangOpts().HLSL && !getLangOpts().EnableShortCircuit) {
// HLSL does not short circuit by default.
// Emit the code with the fully general case.
llvm::Value *CondV;
{

Просмотреть файл

@ -1747,6 +1747,21 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// Enable low precision for HLSL 2018
// TODO: should we tie low precision to HLSL2018 only?
Opts.UseMinPrecision = !Args.hasArg(options::OPT_enable_16bit_types);
// Enable template support for HLSL
Opts.EnableTemplates = Args.hasArg(options::OPT_enable_templates);
// Enable operator overloading support for HLSL
// If the HLSL version is 2021, allow the operator overloading by default.
// If the HLSL version is 2016 or 2018, allow the operator overloading only
// when -enable-operator-overloading option is enabled.
// If the HLSL version is 2015, do not allow the operator overloading.
Opts.EnableOperatorOverloading =
Opts.HLSLVersion >= 2021 ||
Args.hasArg(options::OPT_enable_operator_overloading);
Opts.StrictUDTCasting = Args.hasArg(options::OPT_strict_udt_casting);
if (Opts.HLSLVersion <= 2015 && Opts.EnableOperatorOverloading) {
Diags.Report(diag::err_hlsl_invalid_drv_for_operator_overloading) << ver;
}
#endif // #ifdef MS_SUPPORT_VARIABLE_LANGOPTS
}

Просмотреть файл

@ -29,6 +29,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "dxc/Support/Global.h" // HLSL Change
#include "clang/Sema/SemaHLSL.h" // HLSL Change
#include "clang/AST/UnresolvedSet.h" // HLSL Change
#include "dxc/DXIL/DxilShaderModel.h" // HLSL Change
#include "dxc/DXIL/DxilConstants.h" // HLSL Change
@ -619,6 +620,22 @@ bool Parser::MaybeParseHLSLAttributes(std::vector<hlsl::UnusualAnnotation *> &ta
if (semanticName.equals("VFACE")) {
Diag(Tok.getLocation(), diag::warn_unsupported_target_attribute)
<< semanticName;
} else {
LookupResult R(Actions, Tok.getIdentifierInfo(), Tok.getLocation(),
Sema::LookupOrdinaryName);
if (Actions.LookupName(R, getCurScope())) {
for (UnresolvedSetIterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->getKind() == Decl::Kind::Var) {
VarDecl *VD = static_cast<VarDecl *>(D);
if (VD->getType()->isIntegralOrEnumerationType()) {
Diag(Tok.getLocation(), diag::warn_hlsl_semantic_identifier_collision)
<< semanticName;
break;
}
}
}
}
}
hlsl::SemanticDecl *pUA = new (context) hlsl::SemanticDecl(semanticName);
pUA->Loc = Tok.getLocation();
@ -1997,7 +2014,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
switch (Tok.getKind()) {
case tok::kw_template:
// HLSL Change Starts
if (getLangOpts().HLSL) {
if (getLangOpts().HLSL && !getLangOpts().EnableTemplates) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
SkipMalformedDecl();
return DeclGroupPtrTy();
@ -4162,7 +4179,7 @@ HLSLReservedKeyword:
// C++ typename-specifier:
case tok::kw_typename:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
if (getLangOpts().HLSL && !getLangOpts().EnableTemplates) { goto HLSLReservedKeyword; } // HLSL Change - reserved for HLSL
if (TryAnnotateTypeOrScopeToken()) {
DS.SetTypeSpecError();
goto DoneWithDeclSpec;

Просмотреть файл

@ -2347,13 +2347,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_template)) {
assert(!TemplateInfo.TemplateParams &&
"Nested template improperly parsed?");
// HLSL Change Start - disallow template members
if (getLangOpts().HLSL) {
// HLSL Change Starts
if (getLangOpts().HLSL && !getLangOpts().EnableTemplates) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
SkipUntil(tok::r_brace, StopAtSemi);
return;
}
// HLSL Change End
// HLSL Change Ends
SourceLocation DeclEnd;
ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
AS, AccessAttrs);

Просмотреть файл

@ -1250,7 +1250,7 @@ HLSLReservedKeyword:
if (getLangOpts().HLSL && (
SavedKind == tok::kw_wchar_t || SavedKind == tok::kw_char || SavedKind == tok::kw_char16_t || SavedKind == tok::kw_char32_t ||
SavedKind == tok::kw_short || SavedKind == tok::kw_long || SavedKind == tok::kw___int64 || SavedKind == tok::kw___int128 ||
SavedKind == tok::kw_typename || SavedKind == tok::kw_typeof)) {
(SavedKind == tok::kw_typename && !getLangOpts().EnableTemplates) || SavedKind == tok::kw_typeof)) {
// the vector/image/sampler/event keywords aren't returned by the lexer for HLSL
goto HLSLReservedKeyword;
}
@ -1335,7 +1335,10 @@ HLSLReservedKeyword:
}
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
if (getLangOpts().HLSL && SavedKind == tok::kw_operator) goto HLSLReservedKeyword; // HLSL Change - 'operator' is reserved
if (getLangOpts().HLSL && !getLangOpts().EnableOperatorOverloading &&
SavedKind == tok::kw_operator) {
goto HLSLReservedKeyword; // HLSL Change - 'operator' is reserved
}
Res = ParseCXXIdExpression(isAddressOfOperand);
break;
@ -2775,8 +2778,19 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
} else
Expr = ParseAssignmentExpression();
if (Tok.is(tok::ellipsis))
if (Tok.is(tok::ellipsis)) {
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_variadic_templates);
SkipUntil(tok::r_paren, StopBeforeMatch);
Actions.CorrectDelayedTyposInExpr(Expr);
Expr = ExprError();
SawError = true;
break;
}
// HLSL Change Ends
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
}
if (Expr.isInvalid()) {
SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch);
SawError = true;

Просмотреть файл

@ -82,7 +82,6 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
bool EnteringContext,
IdentifierInfo &II, CXXScopeSpec &SS) {
assert(!getLangOpts().HLSL && "not supported in HLSL - unreachable"); // HLSL Change
if (!Next.is(tok::l_square) || Next.getLength() != 2)
return;
@ -309,7 +308,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// 'identifier <' after it.
if (Tok.is(tok::kw_template)) {
// HLSL Change Starts - template is reserved
if (getLangOpts().HLSL) {
if (getLangOpts().HLSL && !getLangOpts().EnableTemplates) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
ConsumeToken();
return true;
@ -332,7 +331,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
// HLSL Change Starts
if (getLangOpts().HLSL) {
if (getLangOpts().HLSL && !getLangOpts().EnableOperatorOverloading) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
TPA.Commit();
return true;
@ -554,7 +553,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ObjectType,
EnteringContext,
Template,
MemberOfUnknownSpecialization)) {
MemberOfUnknownSpecialization,
nextIsLess)) { // HLSL Change
// We have found a template name, so annotate this token
// with a template-id annotation. We do not permit the
// template-id to be translated into a type annotation,
@ -570,14 +570,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
continue;
}
// HLSL Change: templates aren't really supported in HLSL, so avoid
// handling other cases and emitting incorrect diagnostics if
// the template lookup fails.
// HLSL Change: avoid handling other cases and emitting incorrect
// diagnostics if the template lookup fails.
if (!nextIsLess && getLangOpts().HLSL) {
break;
}
if (!getLangOpts().HLSL && // HLSL Change - no template fixup available
if (getLangOpts().EnableTemplates && // HLSL Change - template fixup only available when templates enabled
MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
(IsTypename || IsTemplateArgumentList(1))) {
// We have something like t::getAs<T>, where getAs is a
@ -2208,7 +2207,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result) {
assert(!getLangOpts().HLSL && "not supported in HLSL - unreachable"); // HLSL Change
assert((!getLangOpts().HLSL || getLangOpts().EnableOperatorOverloading) &&
"not supported in HLSL - unreachable"); // HLSL Change
assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
// Consume the 'operator' keyword.
@ -2538,7 +2538,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// conversion-function-id
if (Tok.is(tok::kw_operator)) {
// HLSL Change Starts
if (getLangOpts().HLSL) {
if (getLangOpts().HLSL && !getLangOpts().EnableOperatorOverloading) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
ConsumeToken();
return true;

Просмотреть файл

@ -29,7 +29,6 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
@ -63,7 +62,6 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
"Token does not start a template declaration.");
@ -177,7 +175,6 @@ Parser::ParseSingleDeclarationAfterTemplate(
SourceLocation &DeclEnd,
AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required");
@ -340,7 +337,6 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
SmallVectorImpl<Decl*> &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
// Get the template parameter list.
if (!TryConsumeToken(tok::less, LAngleLoc)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
@ -379,7 +375,6 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
bool
Parser::ParseTemplateParameterList(unsigned Depth,
SmallVectorImpl<Decl*> &TemplateParams) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
while (1) {
if (Decl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
@ -413,7 +408,6 @@ Parser::ParseTemplateParameterList(unsigned Depth,
/// \brief Determine whether the parser is at the start of a template
/// type parameter.
bool Parser::isStartOfTemplateTypeParameter() {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
if (Tok.is(tok::kw_class)) {
// "class" may be the start of an elaborated-type-specifier or a
// type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@ -490,7 +484,6 @@ bool Parser::isStartOfTemplateTypeParameter() {
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
/// = id-expression
Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
@ -513,7 +506,6 @@ Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
/// 'typename' ...[opt][C++0x] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) &&
"A type-parameter starts with 'class' or 'typename'");
@ -524,6 +516,12 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
// Grab the ellipsis (if given).
SourceLocation EllipsisLoc;
if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(EllipsisLoc, diag::err_hlsl_variadic_templates);
return nullptr;
}
// HLSL Change Ends
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
@ -577,7 +575,6 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
/// 'typename' [C++1z]
Decl *
Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
// Handle the template <...> part.
@ -622,11 +619,16 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Parse the ellipsis, if given.
SourceLocation EllipsisLoc;
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
// HLSL Change Starts
if (getLangOpts().HLSL)
Diag(EllipsisLoc, diag::err_hlsl_variadic_templates);
else
// HLSL Change Ends
Diag(EllipsisLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
// Get the identifier, if given.
SourceLocation NameLoc;
@ -684,7 +686,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
/// parameter-declaration
Decl *
Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
// Parse the declaration-specifiers (i.e., the type).
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
@ -1359,7 +1360,6 @@ void Parser::LateTemplateParserCallback(void *P, LateParsedTemplate &LPT) {
/// \brief Late parse a C++ function template in Microsoft mode.
void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
if (!LPT.D)
return;
@ -1450,7 +1450,6 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
/// \brief Lex a delayed template function for late parsing.
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
tok::TokenKind kind = Tok.getKind();
if (!ConsumeAndStoreFunctionPrologue(Toks)) {
// Consume everything up to (and including) the matching right brace.

Просмотреть файл

@ -1748,7 +1748,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
/*hasTemplateKeyword=*/false, TemplateName,
/*ObjectType=*/ ParsedType(),
EnteringContext,
Template, MemberOfUnknownSpecialization)) {
Template, MemberOfUnknownSpecialization,
/*NextIsLess*/ true)) { // HLSL Change - additional flag
// Consume the identifier.
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),

Просмотреть файл

@ -28,6 +28,32 @@ clang::DiagnosticBuilder emitError(const clang::ASTContext &astContext,
namespace clang {
namespace spirv {
std::string getFunctionOrOperatorName(const FunctionDecl *fn,
bool addClassNameWithOperator) {
auto operatorKind = fn->getOverloadedOperator();
if (operatorKind == OO_None)
return fn->getNameAsString();
if (const auto *cxxMethodDecl = dyn_cast<CXXMethodDecl>(fn)) {
std::string prefix =
addClassNameWithOperator
? cxxMethodDecl->getParent()->getNameAsString() + "."
: "";
switch (operatorKind) {
#ifdef OVERLOADED_OPERATOR
#undef OVERLOADED_OPERATOR
#endif
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
case OO_##Name: \
return prefix + "operator." #Name;
#include "clang/Basic/OperatorKinds.def"
default:
break;
}
}
llvm_unreachable("unknown overloaded operator type");
}
std::string getAstTypeName(QualType type) {
{
QualType ty = {};
@ -251,6 +277,20 @@ bool isMxNMatrix(QualType type, QualType *elemType, uint32_t *numRows,
return false;
}
bool isInputPatch(QualType type) {
if (const auto *rt = type->getAs<RecordType>())
return rt->getDecl()->getName() == "InputPatch";
return false;
}
bool isOutputPatch(QualType type) {
if (const auto *rt = type->getAs<RecordType>())
return rt->getDecl()->getName() == "OutputPatch";
return false;
}
bool isSubpassInput(QualType type) {
if (const auto *rt = type->getAs<RecordType>())
return rt->getDecl()->getName() == "SubpassInput";
@ -308,12 +348,26 @@ bool isResourceType(QualType type) {
type = type->getAsArrayTypeUnsafe()->getElementType();
}
if (isSubpassInput(type) || isSubpassInputMS(type))
if (isSubpassInput(type) || isSubpassInputMS(type) || isInputPatch(type) ||
isOutputPatch(type))
return true;
return hlsl::IsHLSLResourceType(type);
}
bool isUserDefinedRecordType(const ASTContext &astContext, QualType type) {
if (const auto *rt = type->getAs<RecordType>()) {
if (rt->getDecl()->getName() == "mips_slice_type" ||
rt->getDecl()->getName() == "sample_slice_type") {
return false;
}
}
return type->getAs<RecordType>() != nullptr && !isResourceType(type) &&
!isMatrixOrArrayOfMatrix(astContext, type) &&
!isScalarOrVectorType(type, nullptr, nullptr) &&
!isArrayType(type, nullptr, nullptr);
}
bool isOrContains16BitType(QualType type, bool enable16BitTypesOption) {
// Primitive types
{

Просмотреть файл

@ -1403,9 +1403,9 @@ SpirvFunction *DeclResultIdMapper::getOrRegisterFn(const FunctionDecl *fn) {
// definition is seen, the parameter types will be set properly and take into
// account whether the function is a member function of a class/struct (in
// which case a 'this' parameter is added at the beginnig).
SpirvFunction *spirvFunction =
spvBuilder.createSpirvFunction(fn->getReturnType(), fn->getLocation(),
fn->getName(), isPrecise, isNoInline);
SpirvFunction *spirvFunction = spvBuilder.createSpirvFunction(
fn->getReturnType(), fn->getLocation(),
getFunctionOrOperatorName(fn, true), isPrecise, isNoInline);
if (fn->getAttr<HLSLExportAttr>()) {
spvBuilder.decorateLinkage(nullptr, spirvFunction, fn->getName(),

Просмотреть файл

@ -437,7 +437,8 @@ std::string getFnName(const FunctionDecl *fn) {
if (const auto *memberFn = dyn_cast<CXXMethodDecl>(fn))
if (const auto *st = dyn_cast<CXXRecordDecl>(memberFn->getDeclContext()))
classOrStructName = st->getName().str() + ".";
return getNamespacePrefix(fn) + classOrStructName + fn->getName().str();
return getNamespacePrefix(fn) + classOrStructName +
getFunctionOrOperatorName(fn, false);
}
bool isMemoryObjectDeclaration(SpirvInstruction *inst) {
@ -822,6 +823,12 @@ void SpirvEmitter::doDecl(const Decl *decl) {
doRecordDecl(recordDecl);
} else if (const auto *enumDecl = dyn_cast<EnumDecl>(decl)) {
doEnumDecl(enumDecl);
} else if (const auto *classTemplateDecl =
dyn_cast<ClassTemplateDecl>(decl)) {
doClassTemplateDecl(classTemplateDecl);
} else if (const auto *functionTemplateDecl =
dyn_cast<FunctionTemplateDecl>(decl)) {
// nothing to do.
} else {
emitError("decl type %0 unimplemented", decl->getLocation())
<< decl->getDeclKindName();
@ -1460,6 +1467,17 @@ void SpirvEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) {
}
}
void SpirvEmitter::doClassTemplateDecl(
const ClassTemplateDecl *classTemplateDecl) {
for (auto classTemplateSpecializationDeclItr :
classTemplateDecl->specializations()) {
if (const CXXRecordDecl *recordDecl =
dyn_cast<CXXRecordDecl>(&*classTemplateSpecializationDeclItr)) {
doRecordDecl(recordDecl);
}
}
}
void SpirvEmitter::doRecordDecl(const RecordDecl *recordDecl) {
// Ignore implict records
// Somehow we'll have implicit records with:
@ -2282,8 +2300,18 @@ SpirvInstruction *SpirvEmitter::doBinaryOperator(const BinaryOperator *expr) {
}
SpirvInstruction *SpirvEmitter::doCallExpr(const CallExpr *callExpr) {
if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(callExpr))
if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(callExpr)) {
if (const auto *cxxMethodDecl =
dyn_cast<CXXMethodDecl>(operatorCall->getCalleeDecl())) {
QualType parentType =
QualType(cxxMethodDecl->getParent()->getTypeForDecl(), 0);
if (isUserDefinedRecordType(astContext, parentType)) {
// If the parent is a user-defined record type
return processCall(callExpr);
}
}
return doCXXOperatorCallExpr(operatorCall);
}
if (const auto *memberCall = dyn_cast<CXXMemberCallExpr>(callExpr))
return doCXXMemberCallExpr(memberCall);
@ -2355,8 +2383,10 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
const auto numParams = callee->getNumParams();
bool isNonStaticMemberCall = false;
bool isOperatorOverloading = false;
QualType objectType = {}; // Type of the object (if exists)
SpirvInstruction *objInstr = nullptr; // EvalInfo for the object (if exists)
const Expr *object;
llvm::SmallVector<SpirvInstruction *, 4> vars; // Variables for function call
llvm::SmallVector<bool, 4> isTempVar; // Temporary variable or not
@ -2369,7 +2399,7 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
if (isNonStaticMemberCall) {
// For non-static member calls, evaluate the object and pass it as the
// first argument.
const auto *object = memberCall->getImplicitObjectArgument();
object = memberCall->getImplicitObjectArgument();
object = object->IgnoreParenNoopCasts(astContext);
// Update counter variable associated with the implicit object
@ -2381,7 +2411,20 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
objInstr = accessToBaseInstr;
objectType = accessToBaseInstr->getAstResultType();
}
}
} else if (const auto *operatorCallExpr =
dyn_cast<CXXOperatorCallExpr>(callExpr)) {
isOperatorOverloading = true;
isNonStaticMemberCall = true;
// For overloaded operator calls, the first argument is considered as the
// object.
object = operatorCallExpr->getArg(0);
object = object->IgnoreParenNoopCasts(astContext);
objectType = object->getType();
objInstr = doExpr(object);
}
if (objInstr != nullptr) {
// If not already a variable, we need to create a temporary variable and
// pass the object pointer to the function. Example:
// getObject().objectMethod();
@ -2408,14 +2451,17 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
vars.push_back(args.back());
isTempVar.push_back(false);
}
}
// Evaluate parameters
for (uint32_t i = 0; i < numParams; ++i) {
// Arguments for the overloaded operator includes the object itself. The
// actual argument starts from the second one.
const uint32_t argIndex = i + isOperatorOverloading;
// We want the argument variable here so that we can write back to it
// later. We will do the OpLoad of this argument manually. So ingore
// the LValueToRValue implicit cast here.
auto *arg = callExpr->getArg(i)->IgnoreParenLValueCasts();
auto *arg = callExpr->getArg(argIndex)->IgnoreParenLValueCasts();
const auto *param = callee->getParamDecl(i);
const auto paramType = param->getType();
@ -2529,7 +2575,11 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
// the resource.
if (isTempVar[index] && canActAsOutParmVar(param) &&
!isResourceType(paramType)) {
const auto *arg = callExpr->getArg(i);
// Arguments for the overloaded operator includes the object itself. The
// actual argument starts from the second one.
const uint32_t argIndex = i + isOperatorOverloading;
const auto *arg = callExpr->getArg(argIndex);
SpirvInstruction *value =
spvBuilder.createLoad(paramType, vars[index], arg->getLocStart());
@ -4032,7 +4082,7 @@ SpirvEmitter::getOrCreateDeclForMethodObject(const CXXMethodDecl *method) {
if (found != thisDecls.end())
return found->second;
const std::string name = method->getName().str() + ".this";
const std::string name = getFunctionOrOperatorName(method, true) + ".this";
// Create a new identifier to convey the name
auto &identifier = astContext.Idents.get(name);
@ -4485,7 +4535,7 @@ SpirvEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
case IntrinsicOp::MOP_GatherCmpAlpha:
emitError("no equivalent for %0 intrinsic method in Vulkan",
expr->getCallee()->getExprLoc())
<< expr->getMethodDecl()->getName();
<< getFunctionOrOperatorName(expr->getMethodDecl(), true);
return nullptr;
case IntrinsicOp::MOP_TraceRayInline:
return processTraceRayInline(expr);
@ -4532,7 +4582,7 @@ SpirvEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
default:
emitError("intrinsic '%0' method unimplemented",
expr->getCallee()->getExprLoc())
<< expr->getDirectCallee()->getName();
<< getFunctionOrOperatorName(expr->getDirectCallee(), true);
return nullptr;
}
@ -6979,7 +7029,20 @@ const Expr *SpirvEmitter::collectArrayStructIndices(
// The index into an array must be an integer number.
const auto *idxExpr = indexing->getIdx();
const auto idxExprType = idxExpr->getType();
SpirvInstruction *thisIndex = doExpr(idxExpr);
if (idxExpr->isLValue()) {
// If the given HLSL code is correct, this case will not happen, because
// the correct HLSL code will not use LValue for the index of an array.
emitError("Index of ArraySubscriptExpr must be rvalue",
idxExpr->getExprLoc());
return nullptr;
}
// Since `doExpr(idxExpr)` can generate LValue SPIR-V instruction for
// RValue `idxExpr` (see
// https://github.com/microsoft/DirectXShaderCompiler/issues/3620),
// we have to use `loadIfGLValue(idxExpr)` instead of `doExpr(idxExpr)`.
SpirvInstruction *thisIndex = loadIfGLValue(idxExpr);
if (!idxExprType->isIntegerType() || idxExprType->isBooleanType()) {
thisIndex = castToInt(thisIndex, idxExprType, astContext.UnsignedIntTy,
idxExpr->getExprLoc());
@ -7428,7 +7491,7 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
case hlsl::IntrinsicOp::IOP_texCUBElod:
case hlsl::IntrinsicOp::IOP_texCUBEproj: {
emitError("deprecated %0 intrinsic function will not be supported", srcLoc)
<< callee->getName();
<< getFunctionOrOperatorName(callee, true);
return nullptr;
}
case hlsl::IntrinsicOp::IOP_dot:
@ -7631,7 +7694,7 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
case hlsl::IntrinsicOp::IOP_GetRenderTargetSampleCount:
case hlsl::IntrinsicOp::IOP_GetRenderTargetSamplePosition: {
emitError("no equivalent for %0 intrinsic function in Vulkan", srcLoc)
<< callee->getName();
<< getFunctionOrOperatorName(callee, true);
return 0;
}
case hlsl::IntrinsicOp::IOP_transpose: {
@ -7811,7 +7874,7 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
INTRINSIC_OP_CASE(trunc, Trunc, true);
default:
emitError("%0 intrinsic function unimplemented", srcLoc)
<< callee->getName();
<< getFunctionOrOperatorName(callee, true);
return 0;
}
@ -9654,7 +9717,7 @@ SpirvEmitter::processIntrinsicAsType(const CallExpr *callExpr) {
}
default:
emitError("unrecognized signature for %0 intrinsic function", loc)
<< callExpr->getDirectCallee()->getName();
<< getFunctionOrOperatorName(callExpr->getDirectCallee(), true);
return nullptr;
}
}
@ -12358,7 +12421,7 @@ SpirvEmitter::processRayQueryIntrinsics(const CXXMemberCallExpr *expr,
default:
emitError("intrinsic '%0' method unimplemented",
expr->getCallee()->getExprLoc())
<< expr->getDirectCallee()->getName();
<< getFunctionOrOperatorName(expr->getDirectCallee(), true);
return nullptr;
}

Просмотреть файл

@ -94,6 +94,7 @@ private:
void doFunctionDecl(const FunctionDecl *decl);
void doVarDecl(const VarDecl *decl);
void doRecordDecl(const RecordDecl *decl);
void doClassTemplateDecl(const ClassTemplateDecl *classTemplateDecl);
void doEnumDecl(const EnumDecl *decl);
void doHLSLBufferDecl(const HLSLBufferDecl *decl);
void doImplicitDecl(const Decl *decl);

Просмотреть файл

@ -8562,8 +8562,13 @@ void Sema::CheckArrayAccess(const Expr *expr) {
// HLSL Change Starts : Access checking for HLSL vector and matrix array subscript
case Stmt::CXXOperatorCallExprClass : {
if (getLangOpts().HLSL) {
const CXXOperatorCallExpr *OperatorCallExpr =
cast<CXXOperatorCallExpr>(expr);
if (OperatorCallExpr->getOperator() ==
OverloadedOperatorKind::OO_Subscript) {
CheckHLSLArrayAccess(expr);
}
}
return;
}
// HLSL Change Ends

Просмотреть файл

@ -602,7 +602,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
return;
}
if (getLangOpts().CPlusPlus) {
if (getLangOpts().CPlusPlus && !getLangOpts().HLSL) { // HLSL Change
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
Name.setIdentifier(II, IILoc);

Просмотреть файл

@ -11638,6 +11638,17 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
OverloadedOperatorKind Op = FnDecl->getOverloadedOperator();
// HLSL Change Starts
if (LangOpts.HLSL) {
if (Op == OO_Delete || Op == OO_Array_Delete || Op == OO_New ||
Op == OO_Array_New) {
return Diag(FnDecl->getLocation(),
diag::err_hlsl_overloading_new_delete_operator)
<< FnDecl->getDeclName();
}
}
// HLSL Change Ends
// C++ [over.oper]p5:
// The allocation and deallocation functions, operator new,
// operator new[], operator delete and operator delete[], are

Просмотреть файл

@ -1552,6 +1552,49 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
}
// HLSL Change Starts
static bool IsUserDefinedRecordType(QualType type) {
if (const auto *rt = type->getAs<RecordType>()) {
// HLSL specific types
if (hlsl::IsHLSLResourceType(type) || hlsl::IsHLSLVecMatType(type) ||
isa<ExtVectorType>(type.getTypePtr()) || type->isBuiltinType() ||
type->isArrayType()) {
return false;
}
// SubpassInput or SubpassInputMS type
if (rt->getDecl()->getName() == "SubpassInput" ||
rt->getDecl()->getName() == "SubpassInputMS") {
return false;
}
return true;
}
return false;
}
static bool DoesTypeDefineOverloadedOperator(QualType type) {
if (const RecordType *recordType = type->getAs<RecordType>()) {
if (const CXXRecordDecl *cxxRecordDecl =
dyn_cast<CXXRecordDecl>(recordType->getDecl())) {
bool found_overloaded_operator = false;
for (const auto *method : cxxRecordDecl->methods()) {
if (method->getOverloadedOperator() != OO_None)
found_overloaded_operator = true;
}
return found_overloaded_operator;
}
}
return false;
}
static bool IsUserDefinedRecordTypeWithOverloadedOperator(QualType type) {
if (!IsUserDefinedRecordType(type))
return false;
return DoesTypeDefineOverloadedOperator(type);
}
// HLSL Change Ends
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
@ -10846,10 +10889,18 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
RHSExpr = resolvedRHS.get();
}
// HLSL Change: bypass binary operator overload work, which isn't supported in any case;
// otherwise more extensive changes need to be done to add HLSL-specific behavior to
// be considered when building overload candidate sets
if (getLangOpts().CPlusPlus && !getLangOpts().HLSL) {
// HLSL Change: The condition of this if-statement must be false for the
// binary operator overloading for HLSL-specific resource types because they
// must be handled by the following CreateBuiltinBinOp(). If it is a
// user-defined type with operator overloading methods, we know it is not a
// binary operator overloading for a HLSL-specific resource type. This
// if-statement condition does not perfectly checks all the cases, but it
// simply checks whether it is a user-defined type with operator overloading
// methods or not.
if (getLangOpts().CPlusPlus &&
(!getLangOpts().HLSL || getLangOpts().EnableOperatorOverloading) &&
IsUserDefinedRecordTypeWithOverloadedOperator(LHSExpr->getType()) &&
IsUserDefinedRecordType(RHSExpr->getType())) {
// If either expression is type-dependent, always build an
// overloaded op.
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())

Просмотреть файл

@ -78,7 +78,7 @@ enum ArBasicKind {
AR_BASIC_NONE,
AR_BASIC_UNKNOWN,
AR_BASIC_NOCAST,
AR_BASIC_DEPENDENT,
//
// The following pseudo-entries represent higher-level
// object types that are treated as units.
@ -378,6 +378,7 @@ const UINT g_uBasicKindProps[] =
0, // AR_BASIC_NONE
BPROP_OTHER, // AR_BASIC_UNKNOWN
BPROP_OTHER, // AR_BASIC_NOCAST
0, // AR_BASIC_DEPENDENT
//
// The following pseudo-entries represent higher-level
@ -589,6 +590,7 @@ enum ArTypeObjectKind {
AR_TOBJ_INNER_OBJ, // Represents a built-in inner object, such as an
// indexer object used to implement .mips[1].
AR_TOBJ_STRING, // Represents a string
AR_TOBJ_DEPENDENT, // Dependent type for template.
};
enum TYPE_CONVERSION_FLAGS
@ -1627,6 +1629,7 @@ const char* g_ArBasicTypeNames[] =
"<none>",
"<unknown>",
"<nocast>",
"<dependent>",
"<pointer>",
"enum class",
@ -3910,7 +3913,7 @@ public:
/// <summary>
/// Determines whether the specify record type is a matrix, another HLSL object, or a user-defined structure.
/// </sumary>
/// </summary>
ArTypeObjectKind ClassifyRecordType(const RecordType* type)
{
DXASSERT_NOMSG(type != nullptr);
@ -3923,7 +3926,8 @@ public:
return AR_TOBJ_MATRIX;
else if (decl == m_vectorTemplateDecl)
return AR_TOBJ_VECTOR;
DXASSERT(decl->isImplicit(), "otherwise object template decl is not set to implicit");
else if (!decl->isImplicit())
return AR_TOBJ_COMPOUND;
return AR_TOBJ_OBJECT;
}
@ -3991,6 +3995,9 @@ public:
if (type->isPointerType()) {
return hlsl::IsPointerStringType(type) ? AR_TOBJ_STRING : AR_TOBJ_POINTER;
}
if (type->isDependentType()) {
return AR_TOBJ_DEPENDENT;
}
if (type->isStructureOrClassType()) {
const RecordType* recordType = type->getAs<RecordType>();
return ClassifyRecordType(recordType);
@ -4124,6 +4131,7 @@ public:
case BuiltinType::LitInt: return AR_BASIC_LITERAL_INT;
case BuiltinType::Int8_4Packed: return AR_BASIC_INT8_4PACKED;
case BuiltinType::UInt8_4Packed: return AR_BASIC_UINT8_4PACKED;
case BuiltinType::Dependent: return AR_BASIC_DEPENDENT;
default:
// Only builtin types that have basickind equivalents.
break;
@ -4513,6 +4521,17 @@ public:
pIntrinsic->uNumArgs <= g_MaxIntrinsicParamCount + 1,
"otherwise g_MaxIntrinsicParamCount needs to be updated for wider signatures");
// Some intrinsics only optionally exist in later language versions.
// To prevent collisions with existing functions or templates, exclude
// intrinsics when they aren't enabled.
if (IsBuiltinTable(tableName) && !m_sema->getLangOpts().EnableShortCircuit) {
if (pIntrinsic->Op == (UINT)IntrinsicOp::IOP_and ||
pIntrinsic->Op == (UINT)IntrinsicOp::IOP_or ||
pIntrinsic->Op == (UINT)IntrinsicOp::IOP_select) {
continue;
}
}
std::vector<QualType> functionArgTypes;
size_t badArgIdx;
bool argsMatch = MatchArguments(pIntrinsic, QualType(), QualType(), Args, &functionArgTypes, badArgIdx);
@ -5099,7 +5118,7 @@ public:
IntrinsicOp intrinOp = static_cast<IntrinsicOp>(intrinsic->Op);
if (intrinOp == IntrinsicOp::MOP_SampleBias) {
if (IsBuiltinTable(tableName) && intrinOp == IntrinsicOp::MOP_SampleBias) {
// Remove this when update intrinsic table not affect other things.
// Change vector<float,1> into float for bias.
const unsigned biasOperandID = 3; // return type, sampler, coord, bias.
@ -8623,6 +8642,7 @@ bool HLSLExternalSource::CanConvert(
&& sourceExpr->getStmtClass() != Expr::StringLiteralClass;
bool targetRef = target->isReferenceType();
bool TargetIsAnonymous = false;
// Initialize the output standard sequence if available.
if (standard != nullptr) {
@ -8712,6 +8732,9 @@ bool HLSLExternalSource::CanConvert(
Second = ICK_HLSL_Derived_To_Base;
goto lSuccess;
}
// There is no way to cast to anonymous structures. So we allow legacy
// HLSL implicit casts to matching anonymous structure types.
TargetIsAnonymous = !targetRD->hasNameForLinkage();
}
}
@ -8740,6 +8763,14 @@ bool HLSLExternalSource::CanConvert(
break;
}
}
} else if (m_sema->getLangOpts().StrictUDTCasting &&
(SourceInfo.ShapeKind == AR_TOBJ_COMPOUND ||
TargetInfo.ShapeKind == AR_TOBJ_COMPOUND) &&
!TargetIsAnonymous) {
// Not explicit, either are struct/class, not derived-to-base,
// target is named (so explicit cast is possible),
// and using strict UDT rules: disallow this implicit cast.
return false;
}
FlattenedTypeIterator::ComparisonResult result =
@ -8873,6 +8904,11 @@ bool HLSLExternalSource::ValidateTypeRequirements(
bool requiresIntegrals,
bool requiresNumerics)
{
if (objectKind == AR_TOBJ_DEPENDENT)
return true;
if (elementKind == AR_BASIC_DEPENDENT)
return true;
if (requiresIntegrals || requiresNumerics)
{
if (!IsObjectKindPrimitiveAggregate(objectKind))
@ -8974,6 +9010,17 @@ void HLSLExternalSource::CheckBinOpForHLSL(
return;
}
// If there is a dependent type we will use that as the result type
if (LHS.get()->getType()->isDependentType() || RHS.get()->getType()->isDependentType()) {
if (LHS.get()->getType()->isDependentType())
ResultTy = LHS.get()->getType();
else
ResultTy = RHS.get()->getType();
if (BinaryOperatorKindIsCompoundAssignment(Opc))
CompResultTy = ResultTy;
return;
}
// TODO: re-review the Check** in Clang and add equivalent diagnostics if/as needed, possibly after conversions
// Handle Assign and Comma operators and return
@ -9097,6 +9144,14 @@ void HLSLExternalSource::CheckBinOpForHLSL(
ArBasicKind resultElementKind = leftElementKind;
{
if (BinaryOperatorKindIsLogical(Opc)) {
if (m_sema->getLangOpts().EnableShortCircuit) {
// Only allow scalar types for logical operators &&, ||
if (leftObjectKind != ArTypeObjectKind::AR_TOBJ_BASIC ||
rightObjectKind != ArTypeObjectKind::AR_TOBJ_BASIC) {
m_sema->Diag(OpLoc, diag::err_hlsl_logical_binop_scalar);
return;
}
}
resultElementKind = AR_BASIC_BOOL;
} else if (!BinaryOperatorKindIsBitwiseShift(Opc) && leftElementKind != rightElementKind) {
if (!CombineBasicTypes(leftElementKind, rightElementKind, &resultElementKind)) {
@ -9151,8 +9206,11 @@ void HLSLExternalSource::CheckBinOpForHLSL(
StandardConversionSequence standard;
// Suppress type narrowing or truncation warnings for RHS on bitwise shift, since we only care about the LHS type.
bool bSuppressWarnings = BinaryOperatorKindIsBitwiseShift(Opc);
// Suppress errors on compound assignment, since we will vaildate the cast to the final type later.
// Suppress errors on compound assignment, since we will validate the cast to the final type later.
bool bSuppressErrors = isCompoundAssignment;
// Suppress errors if either operand has a dependent type.
if (RHS.get()->getType()->isDependentType() || ResultTy->isDependentType())
bSuppressErrors = true;
// If compound assignment, suppress errors until later, but report warning (vector truncation/type narrowing) here.
if (ValidateCast(SourceLocation(), RHS.get(), ResultTy, ExplicitConversionFalse, bSuppressWarnings, bSuppressErrors, &standard)) {
if (standard.First != ICK_Identity || !standard.isIdentityConversion())
@ -9355,6 +9413,15 @@ clang::QualType HLSLExternalSource::CheckVectorConditional(
QualType condType = GetStructuralForm(Cond.get()->getType());
QualType leftType = GetStructuralForm(LHS.get()->getType());
QualType rightType = GetStructuralForm(RHS.get()->getType());
// If any type is dependent, we will use that as the type to return.
if (leftType->isDependentType())
return leftType;
if (rightType->isDependentType())
return rightType;
if (condType->isDependentType())
return condType;
ArBasicKind condElementKind = GetTypeElementKind(condType);
ArBasicKind leftElementKind = GetTypeElementKind(leftType);
ArBasicKind rightElementKind = GetTypeElementKind(rightType);
@ -9364,6 +9431,14 @@ clang::QualType HLSLExternalSource::CheckVectorConditional(
QualType ResultTy = leftType;
if (m_sema->getLangOpts().EnableShortCircuit) {
// Only allow scalar.
if (condObjectKind == AR_TOBJ_VECTOR || condObjectKind == AR_TOBJ_MATRIX) {
m_sema->Diag(QuestionLoc, diag::err_hlsl_ternary_scalar);
return QualType();
}
}
bool condIsSimple = condObjectKind == AR_TOBJ_BASIC || condObjectKind == AR_TOBJ_VECTOR || condObjectKind == AR_TOBJ_MATRIX;
if (!condIsSimple) {
m_sema->Diag(QuestionLoc, diag::err_hlsl_conditional_cond_typecheck);
@ -9436,7 +9511,13 @@ clang::QualType HLSLExternalSource::CheckVectorConditional(
Cond.set(CreateLValueToRValueCast(Cond.get()));
// Convert condition component type to bool, using result component dimensions
QualType boolType = NewSimpleAggregateType(AR_TOBJ_INVALID, AR_BASIC_BOOL, 0, rowCount, colCount)->getCanonicalTypeInternal();
QualType boolType;
// If short-circuiting, condition must be scalar.
if (m_sema->getLangOpts().EnableShortCircuit)
boolType = NewSimpleAggregateType(AR_TOBJ_INVALID, AR_BASIC_BOOL, 0, 1, 1)->getCanonicalTypeInternal();
else
boolType = NewSimpleAggregateType(AR_TOBJ_INVALID, AR_BASIC_BOOL, 0, rowCount, colCount)->getCanonicalTypeInternal();
if (condElementKind != AR_BASIC_BOOL || condType != boolType) {
StandardConversionSequence standard;
if (ValidateCast(SourceLocation(), Cond.get(), boolType, ExplicitConversionFalse, SuppressWarningsFalse, SuppressErrorsFalse, &standard)) {
@ -9531,8 +9612,10 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
// Get information about the function we have.
CXXMethodDecl* functionMethod = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl());
DXASSERT(functionMethod != nullptr,
"otherwise this is standalone function rather than a method, which isn't supported in the HLSL object model");
if (!functionMethod) {
// standalone function.
return Sema::TemplateDeductionResult::TDK_Invalid;
}
CXXRecordDecl* functionParentRecord = functionMethod->getParent();
DXASSERT(functionParentRecord != nullptr, "otherwise function is orphaned");
QualType objectElement = GetFirstElementTypeFromDecl(functionParentRecord);
@ -9590,6 +9673,11 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
size_t intrinsicCount = 0;
const char* objectName = nullptr;
FindIntrinsicTable(FunctionTemplate->getDeclContext(), &objectName, &intrinsics, &intrinsicCount);
// user-defined template object.
if (objectName == nullptr && intrinsics == nullptr) {
return Sema::TemplateDeductionResult::TDK_Invalid;
}
DXASSERT(objectName != nullptr &&
(intrinsics != nullptr || m_intrinsicTables.size() > 0),
"otherwise FindIntrinsicTable failed to lookup a valid object, "
@ -9610,6 +9698,7 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
continue;
}
LPCSTR tableName = cursor.GetTableName();
// Currently only intrinsic we allow for explicit template arguments are
// for Load/Store for ByteAddressBuffer/RWByteAddressBuffer
@ -9620,8 +9709,12 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
bool IsBAB =
objectName == g_ArBasicTypeNames[AR_OBJECT_BYTEADDRESS_BUFFER] ||
objectName == g_ArBasicTypeNames[AR_OBJECT_RWBYTEADDRESS_BUFFER];
bool IsBABLoad = IsBAB && intrinsicOp == (UINT)IntrinsicOp::MOP_Load;
bool IsBABStore = IsBAB && intrinsicOp == (UINT)IntrinsicOp::MOP_Store;
bool IsBABLoad = false;
bool IsBABStore = false;
if (IsBuiltinTable(tableName) && IsBAB) {
IsBABLoad = intrinsicOp == (UINT)IntrinsicOp::MOP_Load;
IsBABStore = intrinsicOp == (UINT)IntrinsicOp::MOP_Store;
}
if (ExplicitTemplateArgs && ExplicitTemplateArgs->size() > 0) {
bool isLegalTemplate = false;
SourceLocation Loc = ExplicitTemplateArgs->getLAngleLoc();
@ -9656,11 +9749,11 @@ Sema::TemplateDeductionResult HLSLExternalSource::DeduceTemplateArgumentsForHLSL
32, /*signed*/ false);
}
}
Specialization = AddHLSLIntrinsicMethod(cursor.GetTableName(), cursor.GetLoweringStrategy(), *cursor, FunctionTemplate, Args, argTypes.data(), argTypes.size());
Specialization = AddHLSLIntrinsicMethod(tableName, cursor.GetLoweringStrategy(), *cursor, FunctionTemplate, Args, argTypes.data(), argTypes.size());
DXASSERT_NOMSG(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
FunctionTemplate->getCanonicalDecl());
if (!IsValidateObjectElement(*cursor, objectElement)) {
if (IsBuiltinTable(tableName) && !IsValidateObjectElement(*cursor, objectElement)) {
m_sema->Diag(Args[0]->getExprLoc(), diag::err_hlsl_invalid_resource_type_on_intrinsic) <<
nameIdentifier << g_ArBasicTypeNames[GetTypeElementKind(objectElement)];
}
@ -12737,7 +12830,7 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth,
// SPIRV change ends
// Disallow bitfields
if (BitWidth) {
if (BitWidth && getLangOpts().HLSLVersion <= 2015) {
Diag(BitWidth->getExprLoc(), diag::err_hlsl_bitfields);
result = false;
}
@ -13441,7 +13534,11 @@ void Sema::CheckHLSLArrayAccess(const Expr *expr) {
// we also have to check the first subscript oprator by recursively calling
// this funciton for the first CXXOperatorCallExpr
if (isa<CXXOperatorCallExpr>(OperatorCallExpr->getArg(0))) {
CheckHLSLArrayAccess(cast<CXXOperatorCallExpr>(OperatorCallExpr->getArg(0)));
const CXXOperatorCallExpr *object =
cast<CXXOperatorCallExpr>(OperatorCallExpr->getArg(0));
if (object->getOperator() == OverloadedOperatorKind::OO_Subscript) {
CheckHLSLArrayAccess(object);
}
}
if (intIndex < 0 || (uint32_t)intIndex >= vectorSize) {
Diag(RHS->getExprLoc(),

Просмотреть файл

@ -292,6 +292,30 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus,
isForRedeclaration());
// HLSL Change Starts - do not handle new and delete
//
// Without this if-statement, the following HLSL example will just meet the
// llvm_unreachable(..) in Sema::DeclareGlobalAllocationFunction(..) method:
//
// struct S
// {
// float foo;
// void * operator new(int size) {
// return (void *)0;
// }
// void operator delete(void *ptr) {
// (void) ptr;
// }
// };
//
// The llvm_unreachable(..) just prints the following message without
// reporting the exact HLSL code line that causes the failure:
//
// no support for new and delete in HLSL
// UNREACHABLE executed at ../../tools/clang/lib/Sema/SemaExprCXX.cpp:2163!
// Aborted
if (!getSema().getLangOpts().HLSL ||
!getSema().getLangOpts().EnableOperatorOverloading) {
// If we're looking for one of the allocation or deallocation
// operators, make sure that the implicitly-declared new and delete
// operators can be found.
@ -306,6 +330,8 @@ void LookupResult::configure() {
default:
break;
}
}
// HLSL Change Ends
// Compiler builtins are always visible, regardless of where they end
// up being declared.

Просмотреть файл

@ -11493,6 +11493,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_Comma)
break;
// HLSL Change Starts
if (getLangOpts().HLSL)
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// HLSL Change Ends
// For class as left operand for assignment or compound assigment
// operator do not fall through to handling in built-in, but report that
// no overloaded assignment operator found
@ -11528,6 +11533,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
case OR_Ambiguous:
// HLSL Change Starts
if (getLangOpts().HLSL)
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// HLSL Change Ends
Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getType() << Args[1]->getType()

Просмотреть файл

@ -140,7 +140,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
ParsedType ObjectTypePtr,
bool EnteringContext,
TemplateTy &TemplateResult,
bool &MemberOfUnknownSpecialization) {
bool &MemberOfUnknownSpecialization,
bool NextIsLess) { // HLSL CHange
assert(getLangOpts().CPlusPlus && "No template names in C!");
DeclarationName TName;
@ -168,7 +169,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName);
LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
MemberOfUnknownSpecialization);
MemberOfUnknownSpecialization,
NextIsLess); // HLSL Change
if (R.empty()) return TNK_Non_template;
if (R.isAmbiguous()) {
// Suppress diagnostics; we'll redo this lookup later.
@ -248,7 +250,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
bool EnteringContext,
bool &MemberOfUnknownSpecialization) {
bool &MemberOfUnknownSpecialization,
bool NextIsLess) { // HLSL Change
// Determine where to perform name lookup
MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = nullptr;
@ -319,9 +322,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
// HLSL Change: do not try to save template name lookups with auto-correct,
// otherwise identifiers like variable-names might match and fail;
// ideally we would still do this if 'nextIsLess' was known to be true,
// but this is a more localized change.
if (Found.empty() && !isDependent && !getLangOpts().HLSL) {
// however we still do this if 'NextIsLess' is known to be true.
if (Found.empty() && !isDependent && (!getLangOpts().HLSL || NextIsLess)) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
@ -3056,15 +3058,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
case TemplateArgument::Template: {
// We have a template type parameter but the template argument
// is a template without any arguments.
// HLSL Change Starts
// We suppress some errors when templates are enabled in order to preserve
// backwards compatibility.
SourceRange SR = AL.getSourceRange();
TemplateName Name = Arg.getAsTemplate();
TemplateDecl *Decl = Name.getAsTemplateDecl();
if (Decl && !Decl->getLocation().isValid() && getLangOpts().EnableTemplates)
break;
Diag(SR.getBegin(), diag::err_template_missing_args)
<< Name << SR;
if (TemplateDecl *Decl = Name.getAsTemplateDecl()) {
if (Decl->getLocation().isValid()) { // HLSL Change - ellide location notes for built-ins
if (Decl && Decl->getLocation().isValid()) { // HLSL Change - ellide location notes for built-ins
Diag(Decl->getLocation(), diag::note_template_decl_here);
}
}
// HLSL Change Ends
return true;
}

Просмотреть файл

@ -3142,12 +3142,12 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
// - If A is an array type, the pointer type produced by the
// array-to-pointer standard conversion (4.2) is used in place of
// A for type deduction; otherwise,
if (ArgType->isArrayType())
ArgType = S.Context.getArrayDecayedType(ArgType);
//if (ArgType->isArrayType()) // HLSL Change
// ArgType = S.Context.getArrayDecayedType(ArgType);
// - If A is a function type, the pointer type produced by the
// function-to-pointer standard conversion (4.3) is used in place
// of A for type deduction; otherwise,
else if (ArgType->isFunctionType())
if (ArgType->isFunctionType())
ArgType = S.Context.getPointerType(ArgType);
else {
// - If A is a cv-qualified type, the top level cv-qualifiers of A's

Просмотреть файл

@ -545,6 +545,11 @@ bool Sema::CheckParameterPacksForExpansion(
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
if (getLangOpts().HLSL) {
Diag(EllipsisLoc, diag::err_hlsl_variadic_templates);
return true;
}
for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
end = Unexpanded.end();
i != end; ++i) {

Просмотреть файл

@ -4254,6 +4254,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Note: core issue 778 clarifies that, if there are any unexpanded
// parameter packs in the type of the non-type template parameter, then
// it expands those parameter packs.
// HLSL Change Starts
if (LangOpts.HLSL) {
S.Diag(D.getEllipsisLoc(), diag::err_hlsl_variadic_templates);
break;
}
// HLSL Change Ends
if (T->containsUnexpandedParameterPack())
T = Context.getPackExpansionType(T, None);
else

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,59 @@
// RUN: %dxc /T ps_6_0 %s -enable-short-circuit /Zi | FileCheck %s
// RUN: %dxc /T ps_6_0 %s | FileCheck %s -check-prefix=NO_SHORT_CIRCUIT
// Load the two uav handles
// CHECK-DAG: %[[uav_foo:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 128, i1 false)
// CHECK-DAG: %[[uav_bar:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 1, i32 256, i1 false)
// First side effect
// CHECK-DAG: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_foo]]
// LHS: sin(...) != 0
// CHECK-DAG: %[[sin:.+]] = call float @dx.op.unary.f32(i32 13
// CHECK: %[[foo_cmp:.+]] = fcmp fast une float %[[sin]]
// CHECK: br i1 %[[foo_cmp]], label %[[true_label:.+]], label %[[false_label:.+]],
// For AND, if first operand is TRUE, goes to evaluate the second operand
// CHECK: [[true_label]]:
// Second side effect
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_bar]]
// RHS: cos(...) != 0
// CHECK-DAG: %[[cos:.+]] = call float @dx.op.unary.f32(i32 12
// CHECK: %[[bar_cmp:.+]] = fcmp fast une float %[[cos]]
// CHECK: br i1 %[[bar_cmp]]
// CHECK-SAME: %[[false_label]]
// Just check there's no branches.
// NO_SHORT_CIRCUIT-NOT: br i1 %{{.+}}
// NO_SHORT_CIRCUIT-NOT: br label %{{.+}}
RWBuffer<float> buf_foo : register(u128);
RWBuffer<float> buf_bar : register(u256);
cbuffer cb : register(b0) {
uint write_idx0;
uint write_idx1;
float foo_val;
float bar_val;
bool a, b;
}
bool foo() {
buf_foo[write_idx0] = foo_val;
return sin(foo_val) != 0;
}
bool bar() {
buf_bar[write_idx1] = bar_val;
return cos(bar_val) != 0;
}
[RootSignature("DescriptorTable(SRV(t0,numDescriptors=32)),DescriptorTable(CBV(b0,numDescriptors=32)),DescriptorTable(UAV(u0,numDescriptors=1000))")]
float main() : SV_Target {
float ret = 0;
if (foo() && bar()) {
ret = 1;
}
return ret;
}

Просмотреть файл

@ -0,0 +1,60 @@
// RUN: %dxc /T ps_6_0 %s -enable-short-circuit /Zi | FileCheck %s
// RUN: %dxc /T ps_6_0 %s | FileCheck %s -check-prefix=NO_SHORT_CIRCUIT
// Load the two uav handles
// CHECK-DAG: %[[uav_foo:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 128, i1 false)
// CHECK-DAG: %[[uav_bar:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 1, i32 256, i1 false)
// First side effect
// CHECK-DAG: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_foo]]
// LHS: sin(...) != 0
// CHECK-DAG: %[[sin:.+]] = call float @dx.op.unary.f32(i32 13
// CHECK: %[[foo_cmp:.+]] = fcmp fast une float %[[sin]]
// CHECK: br i1 %[[foo_cmp]], label %[[true_label:.+]], label %[[false_label:.+]],
// For OR, if first operand is FALSE, goes to evaluate the second operand
// CHECK: [[false_label]]:
// Second side effect
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_bar]]
// RHS: cos(...) != 0
// CHECK-DAG: %[[cos:.+]] = call float @dx.op.unary.f32(i32 12
// CHECK: %[[bar_cmp:.+]] = fcmp fast une float %[[cos]]
// CHECK: br i1 %[[bar_cmp]]
// CHECK-SAME: %[[true_label]]
// Just check there's no branches.
// NO_SHORT_CIRCUIT-NOT: br i1 %{{.+}}
// NO_SHORT_CIRCUIT-NOT: br label %{{.+}}
RWBuffer<float> buf_foo : register(u128);
RWBuffer<float> buf_bar : register(u256);
cbuffer cb : register(b0) {
uint write_idx0;
uint write_idx1;
float foo_val;
float bar_val;
bool a, b;
}
bool foo() {
buf_foo[write_idx0] = foo_val;
return sin(foo_val) != 0;
}
bool bar() {
buf_bar[write_idx1] = bar_val;
return cos(bar_val) != 0;
}
[RootSignature("DescriptorTable(SRV(t0,numDescriptors=32)),DescriptorTable(CBV(b0,numDescriptors=32)),DescriptorTable(UAV(u0,numDescriptors=1000))")]
float main() : SV_Target {
float ret = 0;
if (foo() || bar()) {
ret = 1;
}
return ret;
}

Просмотреть файл

@ -0,0 +1,59 @@
// RUN: %dxc /T ps_6_0 %s -enable-short-circuit /Zi | FileCheck %s
// RUN: %dxc /T ps_6_0 %s | FileCheck %s -check-prefix=NO_SHORT_CIRCUIT
// Load the two uav handles
// CHECK-DAG: %[[uav_foo:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 128, i1 false)
// CHECK-DAG: %[[uav_bar:.+]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 1, i32 256, i1 false)
// Cond:
// CHECK-DAG: %[[tan:.+]] = call float @dx.op.unary.f32(i32 14
// CHECK: %[[cond_cmp:.+]] = fcmp fast une float %[[tan]], 0.000000e+00
// The actual select
// CHECK: br i1 %[[cond_cmp]], label %[[true_label:.+]], label %[[false_label:.+]],
// CHECK: [[true_label]]:
// First side effect
// CHECK-DAG: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_foo]]
// CHECK-DAG: %[[sin:.+]] = call float @dx.op.unary.f32(i32 13
// CHECK: br label %[[final_block:.+]],
// CHECK: [[false_label]]:
// Second side effect
// CHECK-DAG: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %[[uav_bar]]
// CHECK-DAG: %[[cos:.+]] = call float @dx.op.unary.f32(i32 12
// CHECK: br label %[[final_block]],
// CHECK: [[final_block]]:
// CHECK: phi float [ %[[sin]], %[[true_label]] ], [ %[[cos]], %[[false_label]] ]
// Just check there's no branches.
// NO_SHORT_CIRCUIT-NOT: br i1 %{{.+}}
// NO_SHORT_CIRCUIT-NOT: br label %{{.+}}
RWBuffer<float> buf_foo : register(u128);
RWBuffer<float> buf_bar : register(u256);
cbuffer cb : register(b0) {
uint write_idx0;
uint write_idx1;
float foo_val;
float bar_val;
float cond;
bool a, b;
}
float foo() {
buf_foo[write_idx0] = foo_val;
return sin(foo_val);
}
float bar() {
buf_bar[write_idx1] = bar_val;
return cos(bar_val);
}
[RootSignature("DescriptorTable(SRV(t0,numDescriptors=32)),DescriptorTable(CBV(b0,numDescriptors=32)),DescriptorTable(UAV(u0,numDescriptors=1000))")]
float main() : SV_Target {
return tan(cond) != 0 ? foo() : bar();
}

Просмотреть файл

@ -0,0 +1,31 @@
// Run: %dxc -T ps_6_0 -E main -enable-operator-overloading
// CHECK: %a = OpVariable %_ptr_Function_Number Function
// CHECK: %b = OpVariable %_ptr_Function_Number Function
// CHECK: %param_var_x = OpVariable %_ptr_Function_Number Function
// CHECK: [[b:%\w+]] = OpLoad %Number %b
// CHECK: OpStore %param_var_x [[b]]
// CHECK: OpFunctionCall %void %Number_operator_Equal %a %param_var_x
// CHECK: %Number_operator_Equal = OpFunction %void None
// CHECK: %param_this = OpFunctionParameter %_ptr_Function_Number
// CHECK: %x = OpFunctionParameter %_ptr_Function_Number
// CHECK: [[p_x_n:%\w+]] = OpAccessChain %_ptr_Function_int %x %int_0
// CHECK: [[x_n:%\w+]] = OpLoad %int [[p_x_n]]
// CHECK: [[p_n:%\w+]] = OpAccessChain %_ptr_Function_int %param_this %int_0
// CHECK: OpStore [[p_n]] [[x_n]]
struct Number {
int n;
void operator=(Number x) {
n = x.n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
Number b = {pos.y};
a = b;
return a.n;
}

Просмотреть файл

@ -0,0 +1,21 @@
// Run: %dxc -T ps_6_0 -E main -enable-operator-overloading
// CHECK: %a = OpVariable %_ptr_Function_Number Function
// CHECK: [[call:%\w+]] = OpFunctionCall %int %Number_operator_Call %a
// CHECK: OpReturnValue [[call]]
// CHECK: %Number_operator_Call = OpFunction %int None
// CHECK: %param_this = OpFunctionParameter %_ptr_Function_Number
struct Number {
int n;
int operator()() {
return n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
return a();
}

Просмотреть файл

@ -0,0 +1,76 @@
// Run: %dxc -T ps_6_0 -E main -enable-operator-overloading
struct GLFloat3x2 {
float3x2 m;
};
struct GLFloat3x4 {
float3x4 m;
};
struct GLFloat3x3 {
float3x3 m;
float3x3 operator*(GLFloat3x3 x) {
return mul(m, x.m);
}
float3x2 operator*(GLFloat3x2 x) {
return mul(m, x.m);
}
float3x4 operator*(GLFloat3x4 x) {
return mul(m, x.m);
}
float3 operator[](int x) {
return m[x];
}
};
float3 main(float4 pos: SV_Position) : SV_Target {
GLFloat3x3 a = {pos.xyz, pos.xyz, pos.xyz,};
GLFloat3x3 b = {pos.xxx, pos.yyy, pos.zzz,};
GLFloat3x2 c = {pos.xy, pos.yz, pos.zx,};
GLFloat3x4 d = {pos, pos, pos,};
// CHECK: [[d:%\w+]] = OpLoad %GLFloat3x4 %d
// CHECK: OpStore %param_var_x [[d]]
// CHECK: OpFunctionCall %mat3v4float %GLFloat3x3_operator_Star %a %param_var_x
a * d;
// CHECK: [[c:%\w+]] = OpLoad %GLFloat3x2 %c
// CHECK: OpStore %param_var_x_0 [[c]]
// CHECK: OpFunctionCall %mat3v2float %GLFloat3x3_operator_Star_0 %b %param_var_x_0
b * c;
// CHECK: [[b:%\w+]] = OpLoad %GLFloat3x3 %b
// CHECK: OpStore %param_var_x_1 [[b]]
// CHECK: OpFunctionCall %mat3v3float %GLFloat3x3_operator_Star_1 %a %param_var_x_1
a * b;
// CHECK: OpStore %param_var_x_2 %int_1
// CHECK: OpFunctionCall %v3float %GLFloat3x3_operator_Subscript %a %param_var_x_2
return a[1];
}
// CHECK: OpFunction %mat3v4float None
// CHECK: [[this:%\w+]] = OpLoad %mat3v3float
// CHECK: [[x:%\w+]] = OpLoad %mat3v4float
// CHECK: OpMatrixTimesMatrix %mat3v4float [[x]] [[this]]
// CHECK: OpFunction %mat3v2float None
// CHECK: [[this:%\w+]] = OpLoad %mat3v3float
// CHECK: [[x:%\w+]] = OpLoad %mat3v2float
// CHECK: OpMatrixTimesMatrix %mat3v2float [[x]] [[this]]
// CHECK: OpFunction %mat3v3float None
// CHECK: [[this:%\w+]] = OpLoad %mat3v3float
// CHECK: [[x:%\w+]] = OpLoad %mat3v3float
// CHECK: OpMatrixTimesMatrix %mat3v3float [[x]] [[this]]
// CHECK: %GLFloat3x3_operator_Subscript = OpFunction %v3float None
// CHECK: [[x:%\w+]] = OpLoad %int
// CHECK: [[ux:%\w+]] = OpBitcast %uint [[x]]
// CHECK: [[this:%\w+]] = OpAccessChain %_ptr_Function_v3float {{%\w+}} %int_0 [[ux]]
// CHECK: OpLoad %v3float [[this]]

Просмотреть файл

@ -0,0 +1,27 @@
// Run: %dxc -T hs_6_0 -E main
struct INPUT
{
float4 Pos : SV_Position;
};
struct OUTPUT
{
float x[3] : SV_TessFactor;
};
[outputcontrolpoints(3)]
[patchconstantfunc("foo")]
INPUT main(InputPatch<INPUT, 3> Input,
uint PointID : SV_OutputControlPointID)
{
// CHECK: [[PointID:%\d+]] = OpLoad %uint %PointID
// CHECK: OpAccessChain %_ptr_Function_INPUT %Input [[PointID]]
return Input[PointID];
}
OUTPUT foo()
{
return (OUTPUT)0;
}

Просмотреть файл

@ -0,0 +1,27 @@
// Run: %dxc -T ps_6_0 -E main -enable-operator-overloading
// CHECK: %a = OpVariable %_ptr_Function_Number Function
// CHECK: %b = OpVariable %_ptr_Function_Number Function
// CHECK: %param_var_x = OpVariable %_ptr_Function_Number Function
// CHECK: [[b:%\w+]] = OpLoad %Number %b
// CHECK: OpStore %param_var_x [[b]]
// CHECK: [[call:%\w+]] = OpFunctionCall %int %Number_operator_Star %a %param_var_x
// CHECK: OpReturnValue [[call]]
// CHECK: %Number_operator_Star = OpFunction %int None
// CHECK: %param_this = OpFunctionParameter %_ptr_Function_Number
// CHECK: %x = OpFunctionParameter %_ptr_Function_Number
struct Number {
int n;
int operator*(Number x) {
return x.n * n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
Number b = {pos.y};
return a * b;
}

Просмотреть файл

@ -0,0 +1,47 @@
// Run: %dxc -T ps_6_0 -E main -enable-templates
template <typename T>
T square(T number) {
return number * number;
}
template <typename T>
T plusTwo(int n) {
return 2 + n;
}
template <typename T>
int triple(T x) {
return 3 * x;
}
void main() {
int x;
float y;
// CHECK: [[fn_param_int_ret_int:%\w+]] = OpTypeFunction %int %_ptr_Function_int
// CHECK: [[fn_param_float_ret_float:%\w+]] = OpTypeFunction %float %_ptr_Function_float
// CHECK: [[fn_param_double_ret_double:%\w+]] = OpTypeFunction %double %_ptr_Function_double
// CHECK: [[fn_param_int_ret_bool:%\w+]] = OpTypeFunction %bool %_ptr_Function_int
// CHECK: [[fn_param_double_ret_int:%\w+]] = OpTypeFunction %int %_ptr_Function_double
// CHECK: OpFunction %int None [[fn_param_int_ret_int]]
// CHECK: OpFunctionParameter %_ptr_Function_int
x = square<int>(x);
// CHECK: OpFunction %float None [[fn_param_float_ret_float]]
// CHECK: OpFunctionParameter %_ptr_Function_float
y = square<float>(y);
// CHECK: OpFunction %double None [[fn_param_double_ret_double]]
// CHECK: OpFunctionParameter %_ptr_Function_double
y = square<double>(x);
// CHECK: %plusTwo = OpFunction %bool None [[fn_param_int_ret_bool]]
// CHECK: %n = OpFunctionParameter %_ptr_Function_int
y = plusTwo<bool>(x);
// CHECK: %triple = OpFunction %int None [[fn_param_double_ret_int]]
// CHECK: OpFunctionParameter %_ptr_Function_double
y = triple<double>(x);
}

Просмотреть файл

@ -0,0 +1,51 @@
// Run: %dxc -T ps_6_0 -E main -enable-templates
// The SPIR-V backend correctly handles the template instance `Foo<int>`.
// The created template instance is ClassTemplateSpecializationDecl in AST.
template <typename T>
struct Foo {
static const T bar = 0;
T value;
void set(T value_) { value = value_; }
T get() { return value; }
};
void main() {
// CHECK: [[bar_int:%\w+]] = OpVariable %_ptr_Private_int Private
// CHECK: [[bar_float:%\w+]] = OpVariable %_ptr_Private_float Private
// CHECK: OpStore [[bar_int]] %int_0
// CHECK: OpStore [[bar_float]] %float_0
Foo<int>::bar;
// CHECK: %x = OpVariable %_ptr_Function_int Function
int x;
// CHECK: %y = OpVariable %_ptr_Function_Foo Function
Foo<float> y;
// CHECK: [[x:%\w+]] = OpLoad %int %x
// CHECK: [[float_x:%\w+]] = OpConvertSToF %float [[x]]
// CHECK: OpStore [[param_value_:%\w+]] [[float_x]]
// CHECK: OpFunctionCall %void %Foo_set %y [[param_value_]]
y.set(x);
// CHECK: [[y_get:%\w+]] = OpFunctionCall %float %Foo_get %y
// CHECK: [[y_get_int:%\w+]] = OpConvertFToS %int [[y_get]]
// CHECK: OpStore %x [[y_get_int]]
x = y.get();
}
// CHECK: %Foo_set = OpFunction
// CHECK-NEXT: %param_this = OpFunctionParameter %_ptr_Function_Foo
// CHECK-NEXT: %value_ = OpFunctionParameter %_ptr_Function_float
// CHECK: %Foo_get = OpFunction %float
// CHECK-NEXT: [[this:%\w+]] = OpFunctionParameter %_ptr_Function_Foo
// CHECK: [[ptr_value:%\w+]] = OpAccessChain %_ptr_Function_float [[this]] %int_0
// CHECK: [[value:%\w+]] = OpLoad %float [[ptr_value]]
// CHECK: OpReturnValue [[value]]

Просмотреть файл

@ -0,0 +1,46 @@
// Run: %dxc -T cs_6_0 -E main -enable-templates
// Tests that a rvalue is used for the index of ArraySubscriptExpr. The newly
// introduced template support generates a template instance of
// `BufferAccess::load(uint index)` that misses LValueToRValue cast for a
// MemberExpr. We prevent an array subscript from using lvalue.
[[vk::binding(0, 0)]] ByteAddressBuffer babuf[]: register(t0, space0);
[[vk::binding(0, 0)]] RWByteAddressBuffer rwbuf[]: register(u0, space0);
struct BufferAccess {
uint handle;
template<typename T>
T load(uint index) {
// CHECK: [[handle_ptr:%\d+]] = OpAccessChain %_ptr_Function_uint %param_this %int_0
// CHECK: [[handle:%\d+]] = OpLoad %uint [[handle_ptr]]
// CHECK: OpAccessChain %_ptr_Uniform_type_ByteAddressBuffer %babuf [[handle]]
return babuf[this.handle].Load<T>(index * sizeof(T));
}
template<typename T>
void store(uint index, T value) {
return rwbuf[this.handle].Store<T>(index * sizeof(T), value);
}
};
struct Data {
BufferAccess buf;
uint a0;
uint a1;
uint a2;
};
struct A {
uint x;
};
[[vk::push_constant]] ConstantBuffer<Data> cbuf;
[numthreads(1, 1, 1)]
void main(uint tid : SV_DispatchThreadId) {
A b = cbuf.buf.load<A>(0);
b.x = 12;
cbuf.buf.store<A>(0, b);
}

Просмотреть файл

@ -0,0 +1,43 @@
// RUN: %clang_cc1 -fsyntax-only -ffreestanding -verify %s
typedef int T : 1; /* expected-error {{expected unqualified-id}} expected-error {{expected ';' after top level declarator}} */
static int sb : 1; /* expected-error {{expected unqualified-id}} expected-error {{expected ';' after top level declarator}} */
struct R {
static uint bf : 8; /* expected-error {{static member 'bf' cannot be a bit-field}} */
uint pad : 0; /* expected-error {{named bit-field 'pad' has zero width}} */
};
struct S {
uint b : 33; /* expected-error {{size of bit-field 'b' (33 bits) exceeds size of its type (32 bits)}} */
bool c : 39; /* expected-error {{size of bit-field 'c' (39 bits) exceeds size of its type (32 bits)}} */
bool d : 3;
};
int a[sizeof(S) == 1 ? 1 : -1];
enum E {};
struct Z {};
typedef int Integer;
struct X {
enum E : 1;
Z : 1; /* expected-error {{anonymous bit-field has non-integral type 'Z'}} */
};
struct A {
uint bitX : 4;
uint bitY : 4;
uint var;
};
void main(A a : IN) {
int x;
x = sizeof(a.bitX); /* expected-error {{invalid application of 'sizeof' to bit-field}} */
x = sizeof((uint) a.bitX);
x = sizeof(a.var ? a.bitX : a.bitY); // clang: error: invalid application of 'sizeof' to bit-field
x = sizeof(a.var ? a.bitX : a.bitX); // clang: error: invalid application of 'sizeof' to bit-field
x = sizeof(a.bitX = 3); /* expected-warning {{expression with side effects has no effect in an unevaluated context}} */ // clang: error: invalid application of 'sizeof' to bit-field
x = sizeof(a.bitY += 3); /* expected-error {{invalid application of 'sizeof' to bit-field}} */
}

Просмотреть файл

@ -0,0 +1,349 @@
// RUN: %clang_cc1 -strict-udt-casting -Wno-unused-value -fsyntax-only -ffreestanding -verify -verify-ignore-unexpected=note %s
// Tests all implicit conversions and explicit casts between type shapes
// (scalars, vectors, matrices, arrays and structs).
// Explicit casts are assumed to be "stronger" than implicit conversions.
// > If an implicit conversion succeeds, we don't test the explicit cast
// > If an explicit cast fails, we don't test the implicit conversion
// This variation tests the -strict-udt-casting rule, which disables
// implicit casts between unrelated structure types (non-base casts),
// no matter how compatible they are element-wise.
typedef int A1[1];
typedef int A2[2];
typedef int A4[4];
typedef int A5[5];
struct S1 { int a; };
struct S2 { int a, b; };
struct S4 { int a, b, c, d; };
struct S5 { int a, b, c, d, e; };
typedef S2 TD_S2;
struct Like_S2 { int a, b; };
struct DerivedFrom_S2 : S2 {
int c;
};
// Clang generates a bunch of "notes" about overload candidates here, but we're not testing for these
void to_i(int i) {}
void to_v1(int1 v) {}
void to_v2(int2 v) {}
void to_v4(int4 v) {}
void to_m1x1(int1x1 m) {}
void to_m1x2(int1x2 m) {}
void to_m2x1(int2x1 m) {}
void to_m2x2(int2x2 m) {}
void to_m3x3(int3x3 m) {}
void to_a1(A1 a) {}
void to_a2(A2 a) {}
void to_a4(A4 a) {}
void to_a5(A5 a) {}
void to_s1(S1 s) {}
void to_s2(S2 s) {}
void to_s4(S4 s) {}
void to_s5(S5 s) {}
void main()
{
int i = 0;
int1 v1 = 0;
int2 v2 = 0;
int4 v4 = 0;
int1x1 m1x1 = 0;
int1x2 m1x2 = 0;
int2x1 m2x1 = 0;
int2x2 m2x2 = 0;
int1x3 m1x3 = 0;
int2x3 m2x3 = 0;
int3x1 m3x1 = 0;
int3x2 m3x2 = 0;
int3x3 m3x3 = 0;
A1 a1 = { 0 };
A2 a2 = { 0, 0 };
A4 a4 = { 0, 0, 0, 0 };
A5 a5 = { 0, 0, 0, 0, 0 };
S1 s1 = { 0 };
S2 s2 = { 0, 0 };
S4 s4 = { 0, 0, 0, 0 };
S5 s5 = { 0, 0, 0, 0, 0 };
TD_S2 td_s2 = { 0, 0 };
Like_S2 like_s2 = { 0, 0 };
DerivedFrom_S2 derivedfrom_s2 = { 0, 0, 0 };
// =========== Scalar/single-element ===========
to_i(v1);
to_i(m1x1);
to_i(a1); /* expected-error {{no matching function for call to 'to_i'}} fxc-error {{X3017: 'to_i': cannot convert from 'typedef int[1]' to 'int'}} */
(int)a1;
to_i(s1); /* expected-error {{no matching function for call to 'to_i'}} fxc-error {{X3017: 'to_i': cannot convert from 'struct S1' to 'int'}} */
(int)s1;
to_v1(i);
to_v1(m1x1);
to_v1(a1); /* expected-error {{no matching function for call to 'to_v1'}} fxc-error {{X3017: 'to_v1': cannot convert from 'typedef int[1]' to 'int1'}} */
(int1)a1;
to_v1(s1); /* expected-error {{no matching function for call to 'to_v1'}} fxc-error {{X3017: 'to_v1': cannot convert from 'struct S1' to 'int1'}} */
(int1)s1;
to_m1x1(i);
to_m1x1(v1);
to_m1x1(a1); /* expected-error {{no matching function for call to 'to_m1x1'}} fxc-error {{X3017: 'to_m1x1': cannot convert from 'typedef int[1]' to 'int1'}} */
(int1x1)a1;
to_m1x1(s1); /* expected-error {{no matching function for call to 'to_m1x1'}} fxc-error {{X3017: 'to_m1x1': cannot convert from 'struct S1' to 'int1'}} */
(int1x1)s1;
to_a1(i); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'int' to 'typedef int[1]'}} */
(A1)i;
to_a1(v1); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'int1' to 'typedef int[1]'}} */
(A1)v1;
to_a1(m1x1); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'int1' to 'typedef int[1]'}} */
(A1)m1x1;
// Illegal with -strict-udt-casting
to_a1(s1); /* expected-error {{no matching function for call to 'to_a1'}} */
(A1)s1;
to_s1(i); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'int' to 'struct S1'}} */
(S1)i;
to_s1(v1); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'int1' to 'struct S1'}} */
(S1)v1;
to_s1(m1x1); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'int1' to 'struct S1'}} */
(S1)m1x1;
// Illegal with -strict-udt-casting
to_s1(a1); /* expected-error {{no matching function for call to 'to_s1'}} */
(S1)a1;
// =========== Truncation to scalar/single-element ===========
// Single element sources already tested
to_i(v2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_i': implicit truncation of vector type}} */
to_i(m2x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_i': implicit truncation of vector type}} */
to_i(a2); /* expected-error {{no matching function for call to 'to_i'}} fxc-error {{X3017: 'to_i': cannot convert from 'typedef int[2]' to 'int'}} */
(int)a2;
to_i(s2); /* expected-error {{no matching function for call to 'to_i'}} fxc-error {{X3017: 'to_i': cannot convert from 'struct S2' to 'int'}} */
(int)s2;
to_v1(v2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_v1': implicit truncation of vector type}} */
to_v1(m2x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_v1': implicit truncation of vector type}} */
to_v1(a2); /* expected-error {{no matching function for call to 'to_v1'}} fxc-error {{X3017: 'to_v1': cannot convert from 'typedef int[2]' to 'int1'}} */
(int1)a2;
to_v1(s2); /* expected-error {{no matching function for call to 'to_v1'}} fxc-error {{X3017: 'to_v1': cannot convert from 'struct S2' to 'int1'}} */
(int1)s2;
to_m1x1(v2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m1x1': implicit truncation of vector type}} */
to_m1x1(m2x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m1x1': implicit truncation of vector type}} */
to_m1x1(a2); /* expected-error {{no matching function for call to 'to_m1x1'}} fxc-error {{X3017: 'to_m1x1': cannot convert from 'typedef int[2]' to 'int1'}} */
(int1x1)a2;
to_m1x1(s2); /* expected-error {{no matching function for call to 'to_m1x1'}} fxc-error {{X3017: 'to_m1x1': cannot convert from 'struct S2' to 'int1'}} */
(int1x1)s2;
to_a1(v2); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'int2' to 'typedef int[1]'}} */
to_a1(m2x2); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot implicitly convert from 'int2x2' to 'typedef int[1]'}} */
to_a1(a2); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'typedef int[2]' to 'typedef int[1]'}} */
(A1)a2;
to_a1(s2); /* expected-error {{no matching function for call to 'to_a1'}} fxc-error {{X3017: 'to_a1': cannot convert from 'struct S2' to 'typedef int[1]'}} */
(A1)s2;
to_s1(v2); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'int2' to 'struct S1'}} */
to_s1(m2x2); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot implicitly convert from 'int2x2' to 'struct S1'}} */
to_s1(a2); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'typedef int[2]' to 'struct S1'}} */
(S1)a2;
to_s1(s2); /* expected-error {{no matching function for call to 'to_s1'}} fxc-error {{X3017: 'to_s1': cannot convert from 'struct S2' to 'struct S1'}} */
(S1)s2;
// =========== Splatting ===========
// Single element dests already tested
to_v2(i);
to_v2(v1);
to_v2(m1x1);
(int2)a1; /* expected-error {{cannot convert from 'A1' (aka 'int [1]') to 'int2'}} fxc-error {{X3017: cannot convert from 'typedef int[1]' to 'int2'}} */
(int2)s1; /* expected-error {{cannot convert from 'S1' to 'int2'}} fxc-error {{X3017: cannot convert from 'struct S1' to 'int2'}} */
to_m2x2(i);
to_m2x2(v1);
to_m2x2(m1x1);
(int2x2)a1; /* expected-error {{cannot convert from 'A1' (aka 'int [1]') to 'int2x2'}} fxc-error {{X3017: cannot convert from 'typedef int[1]' to 'int2x2'}} */
(int2x2)s1; /* expected-error {{cannot convert from 'S1' to 'int2x2'}} fxc-error {{X3017: cannot convert from 'struct S1' to 'int2x2'}} */
to_a2(i); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int' to 'typedef int[2]'}} */
(A2)i;
to_a2(v1); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int1' to 'typedef int[2]'}} */
(A2)v1;
to_a2(m1x1); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int1' to 'typedef int[2]'}} */
(A2)m1x1;
(A2)a1; /* expected-error {{cannot convert from 'A1' (aka 'int [1]') to 'A2' (aka 'int [2]')}} fxc-error {{X3017: cannot convert from 'typedef int[1]' to 'typedef int[2]'}} */
(A2)s1; /* expected-error {{cannot convert from 'S1' to 'A2' (aka 'int [2]')}} fxc-error {{X3017: cannot convert from 'struct S1' to 'typedef int[2]'}} */
to_s2(i); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int' to 'struct S2'}} */
(S2)i;
to_s2(v1); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int1' to 'struct S2'}} */
(S2)v1;
to_s2(m1x1); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int1' to 'struct S2'}} */
(S2)m1x1;
(S2)a1; /* expected-error {{cannot convert from 'A1' (aka 'int [1]') to 'S2'}} fxc-error {{X3017: cannot convert from 'typedef int[1]' to 'struct S2'}} */
(S2)s1; /* expected-error {{cannot convert from 'S1' to 'S2'}} fxc-error {{X3017: cannot convert from 'struct S1' to 'struct S2'}} */
// =========== Element-preserving ===========
// Single element sources/dests already tested
to_v2(m1x2);
to_v2(m2x1);
to_v4(m2x2);
to_v2(a2); /* expected-error {{no matching function for call to 'to_v2'}} fxc-error {{X3017: 'to_v2': cannot convert from 'typedef int[2]' to 'int2'}} */
(int2)a2;
to_v2(s2); /* expected-error {{no matching function for call to 'to_v2'}} fxc-error {{X3017: 'to_v2': cannot convert from 'struct S2' to 'int2'}} */
(int2)s2;
to_m1x2(v2);
to_m2x1(v2);
to_m2x2(v4);
(int1x2)m2x1; /* expected-error {{cannot convert from 'int2x1' to 'int1x2'}} fxc-error {{X3017: cannot convert from 'int2x1' to 'int2'}} */
(int2x1)m1x2; /* expected-error {{cannot convert from 'int1x2' to 'int2x1'}} fxc-error {{X3017: cannot convert from 'int2' to 'int2x1'}} */
to_m1x2(a2); /* expected-error {{no matching function for call to 'to_m1x2'}} fxc-error {{X3017: 'to_m1x2': cannot convert from 'typedef int[2]' to 'int2'}} */
(int1x2)a2;
to_m2x1(a2); /* expected-error {{no matching function for call to 'to_m2x1'}} fxc-error {{X3017: 'to_m2x1': cannot convert from 'typedef int[2]' to 'int2x1'}} */
(int2x1)a2;
to_m2x2(a4); /* expected-error {{no matching function for call to 'to_m2x2'}} fxc-error {{X3017: 'to_m2x2': cannot convert from 'typedef int[4]' to 'int2x2'}} */
(int2x2)a4;
to_m1x2(s2); /* expected-error {{no matching function for call to 'to_m1x2'}} fxc-error {{X3017: 'to_m1x2': cannot convert from 'struct S2' to 'int2'}} */
(int1x2)s2;
to_m2x1(s2); /* expected-error {{no matching function for call to 'to_m2x1'}} fxc-error {{X3017: 'to_m2x1': cannot convert from 'struct S2' to 'int2x1'}} */
(int2x1)s2;
to_m2x2(s4); /* expected-error {{no matching function for call to 'to_m2x2'}} fxc-error {{X3017: 'to_m2x2': cannot convert from 'struct S4' to 'int2x2'}} */
(int2x2)s4;
to_a2(v2); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int2' to 'typedef int[2]'}} */
(A2)v2;
to_a2(m1x2); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int2' to 'typedef int[2]'}} */
(A2)m1x2;
to_a2(m2x1); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int2x1' to 'typedef int[2]'}} */
(A2)m2x1;
to_a4(m2x2); /* expected-error {{no matching function for call to 'to_a4'}} fxc-error {{X3017: 'to_a4': cannot convert from 'int2x2' to 'typedef int[4]'}} */
(A4)m2x2;
// Illegal with -strict-udt-casting
to_a2(s2); /* expected-error {{no matching function for call to 'to_a2'}} */
(A2)s2;
to_s2(v2); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int2' to 'struct S2'}} */
(S2)v2;
to_s2(m1x2); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int2' to 'struct S2'}} */
(S2)m1x2;
to_s2(m2x1); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int2x1' to 'struct S2'}} */
(S2)m2x1;
to_s4(m2x2); /* expected-error {{no matching function for call to 'to_s4'}} fxc-error {{X3017: 'to_s4': cannot convert from 'int2x2' to 'struct S4'}} */
(S4)m2x2;
// Illegal with -strict-udt-casting
to_s2(a2); /* expected-error {{no matching function for call to 'to_s2'}} */
(S2)a2;
// typedef is same
to_s2(td_s2);
(S2)td_s2;
// derived-to-base implicit cast is ok
to_s2(derivedfrom_s2);
(S2)derivedfrom_s2;
// identical struct of different name is not the same:
to_s2(like_s2); /* expected-error {{no matching function for call to 'to_s2'}} */
(S2)like_s2;
// implicit casting to anonymous struct of identical layout ok
struct { int a, b; } anon2_1 = s2;
// =========== Truncating ===========
// Single element dests already tested
to_v2(v4); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_v2': implicit truncation of vector type}} */
to_v2(m1x3); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_v2': implicit truncation of vector type}} */
to_v2(m3x1); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_v2': implicit truncation of vector type}} */
(int2)m2x2; /* expected-error {{cannot convert from 'int2x2' to 'int2'}} fxc-error {{X3017: cannot convert from 'int2x2' to 'int2'}} */
(int2)m3x3; /* expected-error {{cannot convert from 'int3x3' to 'int2'}} fxc-error {{X3017: cannot convert from 'int3x3' to 'int2'}} */
to_v2(a4); /* expected-error {{no matching function for call to 'to_v2'}} fxc-error {{X3017: 'to_v2': cannot convert from 'typedef int[4]' to 'int2'}} */
(int2)a4;
to_v2(s4); /* expected-error {{no matching function for call to 'to_v2'}} fxc-error {{X3017: 'to_v2': cannot convert from 'struct S4' to 'int2'}} */
(int2)s4;
to_m1x2(v4); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m1x2': implicit truncation of vector type}} */
to_m2x1(v4); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x1': implicit truncation of vector type}} */
to_m1x2(m1x3); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m1x2': implicit truncation of vector type}} */
(int1x2)m3x1; /* expected-error {{cannot convert from 'int3x1' to 'int1x2'}} fxc-error {{X3017: cannot convert from 'int3x1' to 'int2'}} */
to_m1x2(m2x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m1x2': implicit truncation of vector type}} */
to_m2x1(m3x1); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x1': implicit truncation of vector type}} */
(int2x1)m1x3; /* expected-error {{cannot convert from 'int1x3' to 'int2x1'}} fxc-error {{X3017: cannot convert from 'int3' to 'int2x1'}} */
to_m2x1(m2x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x1': implicit truncation of vector type}} */
to_m2x2(m2x3); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x2': implicit truncation of vector type}} */
to_m2x2(m3x2); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x2': implicit truncation of vector type}} */
to_m2x2(m3x3); /* expected-warning {{implicit truncation of vector type}} fxc-warning {{X3206: 'to_m2x2': implicit truncation of vector type}} */
to_m1x2(a4); /* expected-error {{no matching function for call to 'to_m1x2'}} fxc-error {{X3017: 'to_m1x2': cannot convert from 'typedef int[4]' to 'int2'}} */
(int1x2)a4;
to_m2x1(a4); /* expected-error {{no matching function for call to 'to_m2x1'}} fxc-error {{X3017: 'to_m2x1': cannot convert from 'typedef int[4]' to 'int2x1'}} */
(int2x1)a4;
to_m2x2(a5); /* expected-error {{no matching function for call to 'to_m2x2'}} fxc-error {{X3017: 'to_m2x2': cannot implicitly convert from 'typedef int[5]' to 'int2x2'}} */
(int2x2)a5; /* fxc-error {{X3017: cannot convert from 'typedef int[5]' to 'int2x2'}} */
to_m1x2(s4); /* expected-error {{no matching function for call to 'to_m1x2'}} fxc-error {{X3017: 'to_m1x2': cannot convert from 'struct S4' to 'int2'}} */
(int1x2)s4;
to_m2x1(s4); /* expected-error {{no matching function for call to 'to_m2x1'}} fxc-error {{X3017: 'to_m2x1': cannot convert from 'struct S4' to 'int2x1'}} */
(int2x1)s4;
to_m2x2(s5); /* expected-error {{no matching function for call to 'to_m2x2'}} fxc-error {{X3017: 'to_m2x2': cannot implicitly convert from 'struct S5' to 'int2x2'}} */
(int2x2)s5; /* fxc-error {{X3017: cannot convert from 'struct S5' to 'int2x2'}} */
to_a2(v4); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int4' to 'typedef int[2]'}} */
(A2)v4;
to_a2(m1x3); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int3' to 'typedef int[2]'}} */
(A2)m1x3;
to_a2(m3x1); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'int3x1' to 'typedef int[2]'}} */
(A2)m3x1;
to_a2(m2x2); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot implicitly convert from 'int2x2' to 'typedef int[2]'}} */
(A2)m2x2; /* fxc-error {{X3017: cannot convert from 'int2x2' to 'typedef int[2]'}} */
to_a2(m3x3); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot implicitly convert from 'int3x3' to 'typedef int[2]'}} */
(A2)m3x3; /* fxc-error {{X3017: cannot convert from 'int3x3' to 'typedef int[2]'}} */
to_a2(a4); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'typedef int[4]' to 'typedef int[2]'}} */
(A2)a4;
to_a2(s4); /* expected-error {{no matching function for call to 'to_a2'}} fxc-error {{X3017: 'to_a2': cannot convert from 'struct S4' to 'typedef int[2]'}} */
(A2)s4;
to_s2(v4); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int4' to 'struct S2'}} */
(S2)v4;
to_s2(m1x3); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int3' to 'struct S2'}} */
(S2)m1x3;
to_s2(m3x1); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'int3x1' to 'struct S2'}} */
(S2)m3x1;
to_s2(m2x2); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot implicitly convert from 'int2x2' to 'struct S2'}} */
(S2)m2x2; /* fxc-error {{X3017: cannot convert from 'int2x2' to 'struct S2'}} */
to_s2(m3x3); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot implicitly convert from 'int3x3' to 'struct S2'}} */
(S2)m3x3; /* fxc-error {{X3017: cannot convert from 'int3x3' to 'struct S2'}} */
to_s2(a4); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'typedef int[4]' to 'struct S2'}} */
(S2)a4;
to_s2(s4); /* expected-error {{no matching function for call to 'to_s2'}} fxc-error {{X3017: 'to_s2': cannot convert from 'struct S4' to 'struct S2'}} */
(S2)s4;
// implicit casting to anonymous struct of subset layout is not legal
struct { int a, b; } anon2_2;
anon2_2 = derivedfrom_s2; /* expected-error {{cannot implicitly convert from 'DerivedFrom_S2' to 'struct (anonymous struct at }} */
struct { int a, b; } anon2_3;
anon2_3 = s4; /* expected-error {{cannot implicitly convert from 'S4' to 'struct (anonymous struct at }} */
// =========== Extending ===========
// Single element sources already tested (splatting)
(int4)v2; /* expected-error {{cannot convert from 'int2' to 'int4'}} fxc-error {{X3017: cannot convert from 'int2' to 'int4'}} */
(int4)m1x2; /* expected-error {{cannot convert from 'int1x2' to 'int4'}} fxc-error {{X3017: cannot convert from 'int2' to 'int4'}} */
(int4)m2x1; /* expected-error {{cannot convert from 'int2x1' to 'int4'}} fxc-error {{X3017: cannot convert from 'int2x1' to 'int4'}} */
(int4)a2; /* expected-error {{cannot convert from 'A2' (aka 'int [2]') to 'int4'}} fxc-error {{X3017: cannot convert from 'typedef int[2]' to 'int4'}} */
(int4)s2; /* expected-error {{cannot convert from 'S2' to 'int4'}} fxc-error {{X3017: cannot convert from 'struct S2' to 'int4'}} */
(int2x2)v2; /* expected-error {{cannot convert from 'int2' to 'int2x2'}} fxc-error {{X3017: cannot convert from 'int2' to 'int2x2'}} */
(int2x2)m1x2; /* expected-error {{cannot convert from 'int1x2' to 'int2x2'}} fxc-error {{X3017: cannot convert from 'int2' to 'int2x2'}} */
(int2x2)m2x1; /* expected-error {{cannot convert from 'int2x1' to 'int2x2'}} fxc-error {{X3017: cannot convert from 'int2x1' to 'int2x2'}} */
(int3x3)m2x2; /* expected-error {{cannot convert from 'int2x2' to 'int3x3'}} fxc-error {{X3017: cannot convert from 'int2x2' to 'int3x3'}} */
(int2x2)a2; /* expected-error {{cannot convert from 'A2' (aka 'int [2]') to 'int2x2'}} fxc-error {{X3017: cannot convert from 'typedef int[2]' to 'int2x2'}} */
(int2x2)s2; /* expected-error {{cannot convert from 'S2' to 'int2x2'}} fxc-error {{X3017: cannot convert from 'struct S2' to 'int2x2'}} */
(A4)v2; /* expected-error {{cannot convert from 'int2' to 'A4' (aka 'int [4]')}} fxc-error {{X3017: cannot convert from 'int2' to 'typedef int[4]'}} */
(A4)m1x2; /* expected-error {{cannot convert from 'int1x2' to 'A4' (aka 'int [4]')}} fxc-error {{X3017: cannot convert from 'int2' to 'typedef int[4]'}} */
(A4)m2x1; /* expected-error {{cannot convert from 'int2x1' to 'A4' (aka 'int [4]')}} fxc-error {{X3017: cannot convert from 'int2x1' to 'typedef int[4]'}} */
(A5)m2x2; /* expected-error {{cannot convert from 'int2x2' to 'A5' (aka 'int [5]')}} fxc-error {{X3017: cannot convert from 'int2x2' to 'typedef int[5]'}} */
(A4)a2; /* expected-error {{cannot convert from 'A2' (aka 'int [2]') to 'A4' (aka 'int [4]')}} fxc-error {{X3017: cannot convert from 'typedef int[2]' to 'typedef int[4]'}} */
(A4)s2; /* expected-error {{cannot convert from 'S2' to 'A4' (aka 'int [4]')}} fxc-error {{X3017: cannot convert from 'struct S2' to 'typedef int[4]'}} */
(S4)v2; /* expected-error {{cannot convert from 'int2' to 'S4'}} fxc-error {{X3017: cannot convert from 'int2' to 'struct S4'}} */
(S4)m1x2; /* expected-error {{cannot convert from 'int1x2' to 'S4'}} fxc-error {{X3017: cannot convert from 'int2' to 'struct S4'}} */
(S4)m2x1; /* expected-error {{cannot convert from 'int2x1' to 'S4'}} fxc-error {{X3017: cannot convert from 'int2x1' to 'struct S4'}} */
(S5)m2x2; /* expected-error {{cannot convert from 'int2x2' to 'S5'}} fxc-error {{X3017: cannot convert from 'int2x2' to 'struct S5'}} */
(S4)a2; /* expected-error {{cannot convert from 'A2' (aka 'int [2]') to 'S4'}} fxc-error {{X3017: cannot convert from 'typedef int[2]' to 'struct S4'}} */
(S4)s2; /* expected-error {{cannot convert from 'S2' to 'S4'}} fxc-error {{X3017: cannot convert from 'struct S2' to 'struct S4'}} */
}

Просмотреть файл

@ -499,7 +499,7 @@ my_label: local_i = 1; // expected-error {{label is unsupported in HLSL}}
// for without initialization
for (int j;;) { break; }
// ranged for is disallowed
for (int n : local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected ';' in 'for' statement specifier}} expected-error {{semantic is not a valid modifier for a local variable}}
for (int n : local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected ';' in 'for' statement specifier}} expected-warning {{'local_i' interpreted as semantic; previous definition(s) ignored}} expected-error {{semantic is not a valid modifier for a local variable}}
break;
}
for (int n_again in local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected unqualified-id}} expected-error {{unknown type name 'local_i'}} expected-error {{variable declaration in condition must have an initializer}}

Просмотреть файл

@ -51,10 +51,6 @@ __real g___real; // expected-error {{expected unqualified-id}}
__FUNCTION__ g___FUNCTION; // expected-error {{expected unqualified-id}}
__PRETTY__ g___PRETTY; // expected-error {{unknown type name '__PRETTY__'}}
struct s_with_bitfield {
int f_bitfield : 3; // expected-error {{bitfields are not supported in HLSL}}
};
struct s_with_friend {
friend void some_fn(); // expected-error {{'friend' is a reserved keyword in HLSL}}
};
@ -499,7 +495,7 @@ my_label: local_i = 1; // expected-error {{label is unsupported in HLSL}}
// for without initialization
for (int j;;) { break; }
// ranged for is disallowed
for (int n : local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected ';' in 'for' statement specifier}} expected-error {{semantic is not a valid modifier for a local variable}}
for (int n : local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected ';' in 'for' statement specifier}} expected-warning {{'local_i' interpreted as semantic; previous definition(s) ignored}} expected-error {{semantic is not a valid modifier for a local variable}}
break;
}
for (int n_again in local_i) { // expected-error {{expected ';' in 'for' statement specifier}} expected-error {{expected unqualified-id}} expected-error {{unknown type name 'local_i'}} expected-error {{variable declaration in condition must have an initializer}}

Просмотреть файл

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -verify -enable-operator-overloading %s
// This test checks that when we overload new or delete operator
// dxcompiler generates error and no crashes are observed.
struct S
{
float foo;
void * operator new(int size) { // expected-error {{overloading 'operator new' is not allowed}} expected-error {{pointers are unsupported in HLSL}}
return (void *)0; // expected-error {{pointers are unsupported in HLSL}} expected-error {{cannot convert from 'literal int' to 'void *'}} expected-warning {{'operator new' should not return a null pointer unless it is declared 'throw()'}}
}
void operator delete(void *ptr) { // expected-error {{overloading 'operator delete' is not allowed}} expected-error {{pointers are unsupported in HLSL}}
(void) ptr;
}
};
void main() {
S *a = new S(); // expected-error {{'new' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}}
delete a; // expected-error {{'delete' is a reserved keyword in HLSL}}
}

Просмотреть файл

@ -0,0 +1,14 @@
// RUN: %dxc -E main -T ps_6_0 %s | FileCheck -check-prefix=DISABLED %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck -check-prefix=ENABLED %s
// DISABLED: error: 'template' is a reserved keyword in HLSL
// ENABLED: define void @main()
template<typename T>
T f(T a) {
return a + 1;
};
int main(int a:A) : SV_Target {
return f(a);
}

Просмотреть файл

@ -0,0 +1,26 @@
// RUN: %dxc -E main -T vs_6_0 -strict-udt-casting %s | FileCheck %s
// CHECK: switch
struct Vertex
{
float4 position : POSITION0;
float4 color : COLOR0;
float4 a[3] : A;
};
struct Interpolants
{
float4 position : SV_POSITION0;
float4 color : COLOR0;
float4 a[3] : A;
};
uint i;
void main( Vertex In, int j : J, out Interpolants output )
{
output = (Interpolants)In;
output.a[1][i] = 3;
output.a[0] = 4;
}

Просмотреть файл

@ -0,0 +1,20 @@
// RUN: %dxc -E main -T ps_6_0 -enable-operator-overloading %s | FileCheck %s
// CHECK: [[pos_y:%[^ ]+]] = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1, i32 undef)
// CHECK: [[b:%[^ ]+]] = fptosi float [[pos_y]] to i32
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 [[b]])
struct Number {
int n;
void operator=(Number x) {
n = x.n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
Number b = {pos.y};
a = b;
return a.n;
}

Просмотреть файл

@ -0,0 +1,19 @@
// RUN: %dxc -E main -T ps_6_0 -enable-operator-overloading %s | FileCheck %s
// CHECK: define void @main()
// CHECK: %[[pos:[^ ]+]] = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 undef)
// CHECK: %[[a:[^ ]+]] = fptosi float %[[pos]] to i32
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 %[[a]])
struct Number {
int n;
int operator()() {
return n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
return a();
}

Просмотреть файл

@ -0,0 +1,22 @@
// RUN: %dxc -E main -T ps_6_0 -enable-operator-overloading %s | FileCheck %s
// CHECK: [[pos_x:%[^ ]+]] = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 undef)
// CHECK: [[pos_y:%[^ ]+]] = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1, i32 undef)
// CHECK: [[a:%[^ ]+]] = fptosi float [[pos_x]] to i32
// CHECK: [[b:%[^ ]+]] = fptosi float [[pos_y]] to i32
// CHECK: [[star:%[^ ]+]] = mul nsw i32 [[b]], [[a]]
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 [[star]])
struct Number {
int n;
int operator*(Number x) {
return x.n * n;
}
};
int main(float4 pos: SV_Position) : SV_Target {
Number a = {pos.x};
Number b = {pos.y};
return a * b;
}

Просмотреть файл

@ -0,0 +1,199 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 %s -enable-templates -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s /Zi | FileCheck %s
template<typename T>
T test_add(T t0, T t1) {
return t0 + t1;
}
template<typename T>
T test_sub(T t0, T t1) {
return t0 - t1;
}
template<typename T>
T test_mul(T t0, T t1) {
return t0 * t1;
}
template<typename T>
T test_div(T t0, T t1) {
return t0 / t1;
}
template<typename T>
T test_mod(T t0, T t1) {
return t0 % t1;
}
struct S {
int a;
int4 a4;
};
int4 main(int4 a:A) : SV_Target {
int i, j;
unsigned int ui, uj;
int1 i1 = 10, j1 = 11;
int2 i2, j2;
int3 i3, j3;
int4 i4 = int4(1,2,3,4), j4 = int4(5,6,7,8);
int1x1 i1x1, j1x1;
int1x1 i1x2, j1x2;
int1x1 i1x3, j1x3;
int1x1 i1x4, j1x4;
int1x1 i2x1, j2x1;
float x,y;
S s;
bool b1, b2 = true;
int arr1[7], arr2[7];
#ifdef CHECK_DIAGNOSTICS
// DIAG-NOT: define void @main
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
test_add(i, x); // mismatched types
test_add(s, j); // mismatched types
test_add(i, s); // mismatched types
test_add(i, uj); // mismatched types
test_add(b1,j); // mismatched types
test_add(s, s); // can't test_add structs
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
test_sub(i, x); // mismatched types
test_sub(i, x); // mismatched types
test_sub(s, j); // mismatched types
test_sub(i, s); // mismatched types
test_sub(i, uj); // mismatched types
test_sub(b1,j); // mismatched types
test_sub(s, s); // can't test_sub structs
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
test_mul(i, x); // mismatched types
test_mul(i, x); // mismatched types
test_mul(s, j); // mismatched types
test_mul(i, s); // mismatched types
test_mul(i, uj); // mismatched types
test_mul(b1,j); // mismatched types
test_mul(s, s); // can't test_mul structs
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
test_div(i, x); // mismatched types
test_div(i, x); // mismatched types
test_div(s, j); // mismatched types
test_div(i, s); // mismatched types
test_div(i, uj); // mismatched types
test_div(b1,j); // mismatched types
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
// DIAG: deduced conflicting types for parameter
test_mod(i, x); // mismatched types
test_mod(i, x); // mismatched types
test_mod(s, j); // mismatched types
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
test_mod(i, s); // mismatched types
test_mod(i, uj); // mismatched types
test_mod(b1,j); // mismatched types
test_mod(s, s); // can't test_mod structs
return 0;
#else
// These should all compile without diagnostics
// CHECK: define void @main
int r_i = test_add(i,j) + test_sub(i,j) + test_mul(i,j) + test_div(i,j) + test_mod(i,j);
int r_ia = test_add(1,5);
int r_ib = test_add(i,int(6));
int1 r_i1 = test_add(i1,j1) + test_sub(i1,j1) + test_mul(i1,j1) + test_div(i1,j1) + test_mod(i1,j1);
int2 r_i2 = test_add(i2,j2) + test_sub(i2,j2) + test_mul(i2,j2) + test_div(i2,j2) + test_mod(i2,j2);
int3 r_i3 = test_add(i3,j3) + test_sub(i3,j3) + test_mul(i3,j3) + test_div(i3,j3) + test_mod(i3,j3);
int4 r_i4 = test_add(i4,j4) + test_sub(i4,j4) + test_mul(i4,j4) + test_div(i4,j4) + test_mod(i4,j4);
int4 r_i4a = test_add(i4,int4(3,5,7,9));
int4 r_i4b = test_add(int4(2,4,8,16), j4);
s.a4 = test_add<int4>(int4(2,4,8,16), j4);
s.a4 = test_add(int4(2,4,8,16), j4);
int1x1 r_i1x1 = test_add(i1x1, j1x1) + test_sub(i1x1, j1x1) + test_mul(i1x1, j1x1) + test_div(i1x1, j1x1) + test_mod(i1x1, j1x1);
int1x1 r_i1x2 = test_add(i1x2, j1x2);
int1x1 r_i1x3 = test_add(i1x3, j1x3);
int1x1 r_i1x4 = test_add(i1x4, j1x4);
int1x1 r_i2x1 = test_add(i2x1, j2x1) + test_sub(i2x1, j2x1) + test_mul(i2x1, j2x1) + test_div(i2x1, j2x1) + test_mod(i2x1, j2x1);
test_add(i, j);
test_add(x, y);
test_add(1, 2);
test_add(i4.w, j);
test_add(arr1[1], j);
test_add(ui, uj);
test_add(b1,b2);
test_sub(i, j);
test_sub(x, y);
test_sub(1, 2);
test_sub(i4.w, j);
test_sub(arr1[1], j);
test_sub(ui, uj);
test_sub(b1,b2);
test_mul(i, j);
test_mul(x, y);
test_mul(1, 2);
test_mul(i4.w, j);
test_mul(arr1[1], j);
test_mul(ui, uj);
test_mul(b1,b2);
test_div(i, j);
test_div(x, y);
test_div(1, 2);
test_div(i4.w, j);
test_div(arr1[1], j);
test_div(ui, uj);
test_div(b1,b2);
test_mod(i, j);
test_mod(x, y);
test_mod(1, 2);
test_mod(i4.w, j);
test_mod(arr1[1], j);
test_mod(ui, uj);
test_mod(b1,b2);
return r_i4 + r_i4a + r_i4b;
#endif
}

Просмотреть файл

@ -0,0 +1,106 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
// pass - bool, int, float, vector, matrix
// fail - struct, array
template<typename T>
bool my_any(T t0) {
return any(t0);
}
template<typename T>
bool my_all(T t0) {
return all(t0);
}
template<typename T>
bool any_lessthan(T t0, T t1) {
return any(t0 < t1);
}
template<typename T>
bool all_lessthan(T t0, T t1) {
return all(t0 < t1);
}
struct S {
bool4 b;
int i;
};
bool main(int4 a:A) : SV_Target {
int i = 7, j = 6;
int1 i1 = 10, j1 = 11;
int4 i4 = int4(1,2,3,4), j4 = int4(5,6,7,8);
int3x3 i3x3, j3x3;
int iarr[7] = {1,2,3,4,5,6,7}, jarr[7] ;
bool barr[6];
S s1, s2;
#ifdef CHECK_DIAGNOSTICS
// DIAG-NOT: define void @main
// DIAG: not viable: no known conversion from 'S' to 'float'
// DIAG: not viable: no known conversion from 'int [7]' to 'int'
// DIAG: not viable: no known conversion from 'bool [6]' to 'bool'
my_any(s1);
my_any(iarr);
my_any(barr);
// DIAG: not viable: no known conversion from 'S' to 'float'
// DIAG: not viable: no known conversion from 'int [7]' to 'int'
// DIAG: not viable: no known conversion from 'bool [6]' to 'bool'
my_all(s1);
my_all(iarr);
my_all(barr);
return true;
#else
// CHECK: define void @main
my_any(i);
my_any(i1);
my_any(i4);
my_any(i3x3);
bool b1 = all_lessthan(i,j);
bool b2 = any_lessthan(i,j);
bool b3 = any_lessthan(i1,j1);
bool b4 = all_lessthan(i1,j1);
bool b5 = any_lessthan(i4,j4);
bool b6 = all_lessthan(i4,j4);
bool b7 = any_lessthan(i3x3,j3x3);
bool b8 = all_lessthan(i3x3,j3x3);
bool b9 = all_lessthan(i,i4.x);
bool b9a = any_lessthan(i,j4[2]);
float x, y;
float3 x3, y3;
float4x4 x4x4, y4x4;
bool b10 = any_lessthan(x,y);
bool b11 = all_lessthan(x,y);
bool b12 = any_lessthan(x3,y3);
bool b13 = all_lessthan(x3,y3);
bool b14 = any_lessthan(x4x4,y4x4);
bool b15 = all_lessthan(x4x4,y4x4);
bool b16 = any_lessthan(x3,float3(0.1, 2.7, 3.3));
bool b20 = all_lessthan(s1.i,s2.i);
bool b21 = all_lessthan(x4x4[1],y4x4[3].zwyx);
return b1 || b2 || b3 || b4 || b5 || b6 || b7 || b8 || b9 || b10 || b11 || b12 || b13 || b14 || b15 || b16;
#endif
}

Просмотреть файл

@ -0,0 +1,57 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 %s -enable-templates -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
template<typename T0, typename T1>
void assign(inout T0 t0, T1 t1) {
t0 = t1;
}
struct S {
int4 i4;
float2 f2;
float3x3 f3x3;
bool4 b4;
};
void main() : SV_Target {
int i;
int1 i1;
int2 i2;
int3 i3;
int4 i4;
unsigned int j;
unsigned int2x2 j2x2;
float x;
float3 x3;
bool b;
bool2 b2;
S s, t;
float4x3 f4arr[11];
#ifdef CHECK_DIAGNOSTICS
// DIAG-NOT: define void @main
// DIAG: cannot implicitly convert
assign(f4arr, x);
// DIAG: warning: implicit truncation of vector type
// DIAG: warning: implicit truncation of vector type
assign(i, i4);
assign(b, b2);
// DIAG-NOT: error
#else
// CHECK: define void @main
assign(i, j);
assign(i, i1);
assign(i, i1);
assign(i, i1);
assign(i2, i);
assign(s, t);
assign(s.i4, i4);
#endif
}

Просмотреть файл

@ -0,0 +1,151 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s 2>&1 | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
// Check that HLSL bitwise assignment operators deal with dependent types
template<typename T, typename I>
void lshiftassign(inout T t, I i) {
t <<= i;
}
template<typename T>
void lshiftassignby2(inout T t) {
t <<= 2;
}
template<typename T, typename I>
T rshiftassign(T t, I i) {
t >>= i;
return t;
}
template<typename T0, typename T1>
T0 andassign(T0 t0, T1 t1) {
t0 &= t1;
return t0;
}
template<typename T0, typename T1>
T0 orassign(T0 t0, T1 t1) {
t0 |= t1;
return t0;
}
template<typename T0, typename T1>
T0 xorassign(T0 t0, T1 t1) {
t0 ^= t1;
return t0;
}
typedef struct {
int4 a;
} S;
int4 main(int4 a:A) : SV_Target {
int i = 7, j = 6;
unsigned int ui = 7, uj = 6;
int1 i1 = 10, j1 = 11;
int4 i4 = int4(1,2,3,4), j4 = int4(5,6,7,8);
int3x3 i3x3, j3x3;
int iarr[7] = {1,2,3,4,5,6,7}, jarr[7] ;
S s;
bool b;
bool1 b1;
bool3 b3;
bool2x2 b2x2;
float x, y;
float3 x3, y3;
float4x4 x4x4, y4x4;
#ifdef CHECK_DIAGNOSTICS
// DIG-NOT: define void @main
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
lshiftassign(iarr,i);
lshiftassign(i,iarr);
lshiftassign(iarr,iarr);
lshiftassignby2(iarr);
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
lshiftassign(s,i);
lshiftassign(i,s);
lshiftassignby2(s);
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
lshiftassign(x,ui);
lshiftassign(i,x);
lshiftassignby2(x);
andassign(x,i);
andassign(i,x);
orassign(x,i);
orassign(i,x);
xorassign(x,i);
xorassign(i,x);
// DIAG: error: operator cannot be used with a bool lvalue
// DIAG: error: operator cannot be used with a bool lvalue
lshiftassign(b,i);
rshiftassign(b,i);
return 0;
#else
// CHECK: define void @main
// CHECK-NOT: error
// CHECK-NOT: warning
lshiftassign(j,i);
lshiftassign(uj,i);
lshiftassign(j,ui);
lshiftassign(i,b);
lshiftassignby2(j);
lshiftassignby2(ui);
rshiftassign(j,i);
rshiftassign(uj,i);
rshiftassign(j,ui);
rshiftassign(i,b);
andassign(j,i);
andassign(uj,i);
andassign(j,ui);
andassign(i,b);
andassign(b,i);
orassign(j,i);
orassign(uj,i);
orassign(j,ui);
orassign(i,b);
orassign(b,i);
xorassign(j,i);
xorassign(uj,i);
xorassign(j,ui);
xorassign(i,b);
xorassign(b,i);
// lshiftassign(i,3);
// xorassign(b,2);
return 0;
#endif
}

Просмотреть файл

@ -0,0 +1,125 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates -enable-short-circuit %s 2>&1 | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates -enable-short-circuit %s -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
// Check that HLSL bitwise operators deal with dependent types
template<typename T>
T Not(T t) {
return ~t;
}
template<typename T>
T And(T t0, T t1) {
return t0 & t1;
}
template<typename T>
T Or(T t0, T t1) {
return t0 | t1;
}
template<typename T, typename I>
T lshift(T t, I i) {
T r = t << i;
return r;
}
template<typename T, typename I>
T rshift(T t, I i) {
return t >> i;
}
typedef struct {
int4 a;
} S;
int4 main(int4 a:A) : SV_Target {
int i = -7, j = 6;
unsigned int ui = 7, uj = 6;
int1 i1 = 10, j1 = 11;
int4 i4 = int4(1,2,3,4), j4 = int4(5,6,7,8);
int3x3 i3x3, j3x3;
int iarr[7] = {1,2,3,4,5,6,7}, jarr[7] ;
S s;
bool b;
bool1 b1;
bool3 b3;
bool2x2 b2x2;
float x, y;
float3 x3, y3;
float4x4 x4x4, y4x4;
#ifdef CHECK_DIAGNOSTICS
// DIAG-NOT: define void @main
// DIAG: function cannot return array type
// DIAG: function cannot return array type
// DIAG: function cannot return array type
// DIAG: function cannot return array type
// DIAG: function cannot return array type
Not(iarr);
And(iarr,iarr);
Or(iarr,iarr);
lshift(iarr,i);
rshift(iarr,i);
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
// DIAG: error: scalar, vector, or matrix expected
Not(s);
And(s,s);
Or(s,s);
lshift(s,i);
rshift(s,i);
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
// DIAG: error: int or unsigned int type required
Not(x);
And(x,x);
Or(x,x);
lshift(x,i);
lshift(i,x);
rshift(x,i);
rshift(ui,x);
// DIAG-NOT: warning
// DIAG-NOT: error
return 0;
#else
// CHECK: define void @main
int r1 = Not(i);
int r2 = Not(i1);
int4 r3 = Not(i4);
int3x3 r4 = Not(i3x3);
int r5 = Not(iarr[5]);
int r6 = Not(i4.w);
int4 r7 = Not(s.a);
bool3 b3b = Not(b3);
Not(ui);
Not(b);
And(b,b);
Or(b,b);
// Note that << and >> allow bool LHS operands, but <<= and >>= give "error: operator cannot be used with a bool lvalue"
lshift(b,i);
lshift(i,b);
rshift(b,i);
rshift(i,b);
return r1 + r2 + r3.x + r4[3].y + r5 + r6;
#endif
}

Просмотреть файл

@ -0,0 +1,66 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
template<typename T>
T ternary_and(T t0, T t1) {
return t0 && t1 ? t0 : t1;
}
template<typename T>
T ternary_or(T t0, T t1) {
return t0 || t1 ? t0 : t1;
}
typedef struct {
int4 a, b;
} S;
void main() : SV_Target {
bool ba, bb;
bool3 b3a, b3b;
bool4x4 b4x4a, b4x4b;
int ia, ib;
int3 i3a, i3b;
uint ua, ub;
uint2 u2a, u2b;
uint4 u4a, u4b;
float fa, fb;
float4 f4a, f4b;
int iarra[8], iarrb[8];
S sa, sb;
#ifdef CHECK_DIAGNOSTICS
// DIAG-NOT: define void @main
// DIAG: deduced conflicting types for parameter
ternary_or(bb, sa);
// DIAG: function cannot return array type
ternary_or(iarra, iarra);
// DIAG: error: scalar, vector, or matrix expected
ternary_and(sa, sb);
// DIAG: error: scalar, vector, or matrix expected
ternary_or(sa, sb);
#else
// CHECK: define void @main
ternary_and(ba, bb);
ternary_and(b3a, b3b);
ternary_and(b4x4a, b4x4b);
ternary_and(ia, ib);
ternary_and(i3a, i3b);
ternary_and(ua, ub);
ternary_and(u4a, u4b);
ternary_and(fa, fb);
ternary_and(int(fa), ib);
ternary_or(iarra[2], iarra[4]);
ternary_and(sa.a, sb.b);
#endif
}

Просмотреть файл

@ -0,0 +1,45 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s -DCHECK_DIAGNOSTICS | FileCheck %s -check-prefix=DIAG
template<typename T0, typename T1>
T0 lessthan(T1 t0, T1 t1) {
return t0 < t1;
}
typedef struct {
int4 a, b;
} S;
int4 main() : SV_Target {
bool ba, bb;
bool3 b3a, b3b;
bool4x4 b4x4a, b4x4b;
int ia, ib;
int3 i3a, i3b;
uint ua, ub;
uint2 u2a, u2b;
uint4 u4a, u4b;
float fa, fb;
float4 f4a, f4b;
int iarra[8], iarrb[8];
S sa, sb;
#ifdef CHECK_DIAGNOSTICS
// DIAG: error: scalar, vector, or matrix expected
// DIAG-NOT: define void @main
return lessthan<bool>(sa, sb);
#else
// CHECK: define void @main
lessthan<bool>(ia, ib);
return lessthan<bool4>(int4(1,3,7,11),int4(10,8,6,5));
#endif
}

Просмотреть файл

@ -0,0 +1,151 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 %s -enable-templates -DCHECK_DIAGNOSTICS | FileCheck -check-prefix=DIAG %s
template<typename T>
T preinc(T t0) {
T r = ++t0;
return r;
}
template<typename T>
T postinc(T t0) {
T r = t0++;
return r;
}
template<typename T>
T predec(T t0) {
T r = --t0;
return r;
}
template<typename T>
T postdec(T t0) {
T r = t0--;
return r;
}
struct S {
int4 i4;
float2 f2;
float3x3 f3x3;
bool4 b4;
};
void main() : SV_Target {
int i;
int1 i1;
int2 i2;
int3 i3;
int4 i4;
unsigned int j;
unsigned int2x2 j2x2;
float x;
float3 x3;
bool b;
bool2 b2;
S s;
float4x3 f4arr[11];
#ifndef CHECK_DIAGNOSTICS
// CHECK:define void @main
preinc(i);
preinc(i1);
preinc(i2);
preinc(i3);
preinc(i4);
preinc(i4.x);
preinc(i4.yz);
preinc(i4.xyz);
preinc(j);
preinc(j2x2);
preinc(x);
preinc(x3);
preinc(s.i4);
preinc(s.f2);
preinc(s.f3x3);
preinc(f4arr[9]);
preinc(f4arr[9][2]);
preinc(f4arr[3][1].xz);
postinc(i);
postinc(i1);
postinc(i2);
postinc(i3);
postinc(i4);
postinc(i4.x);
postinc(i4.yz);
postinc(i4.xyz);
postinc(j);
postinc(j2x2);
postinc(x);
postinc(x3);
postinc(s.i4);
postinc(s.f2);
postinc(s.f3x3);
postinc(f4arr[9]);
postinc(f4arr[5][2]);
postinc(f4arr[3][1].xz);
predec(i);
predec(i1);
predec(i2);
predec(i3);
predec(i4);
predec(i4.x);
predec(i4.yz);
predec(i4.xyz);
predec(j);
predec(j2x2);
predec(x);
predec(x3);
predec(s.i4);
predec(s.f2);
predec(s.f3x3);
postinc(f4arr[9]);
postinc(f4arr[4][3]);
postinc(f4arr[9][2].yz);
postdec(i);
postdec(i1);
postdec(i2);
postdec(i3);
postdec(i4);
postdec(i4.x);
postdec(i4.yz);
postdec(i4.xyz);
postdec(j);
postdec(j2x2);
postdec(x);
postdec(x3);
postdec(s.i4);
postdec(s.f2);
postdec(s.f3x3);
postdec(f4arr[9]);
postdec(f4arr[4][3]);
postdec(f4arr[9][2].yz);
#else
// DIAG-NOT: define void @main
// DIAG: function cannot return array type
preinc(f4arr);
// DIAG: error: scalar, vector, or matrix expected
preinc(s);
// DIAG: error: operator cannot be used with a bool lvalue
// DIAG: error: operator cannot be used with a bool lvalue
// DIAG: error: operator cannot be used with a bool lvalue
preinc(b);
preinc(b2);
preinc(s.b4);
// DIAG-NOT: error
#endif
}

Просмотреть файл

@ -0,0 +1,44 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0x404FD93640000000)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0x4047269780000000)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0x4045A83E40000000)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0x4045669660000000)
struct MyRandomGeneratorA
{
float seed;
float Rand()
{
// Not a good random number generator
seed = (seed * 17 + 57) / 99.0;
return seed;
}
};
struct MyRandomGeneratorB
{
float Rand()
{
// An even worse random number generator
return 42.0;
}
};
template<typename GeneratorType>
float4 Model(GeneratorType Generator)
{
float4 E;
E.x = Generator.Rand();
E.y = Generator.Rand();
E.z = Generator.Rand();
E.w = Generator.Rand();
return E;
};
float4 main() : SV_TARGET {
MyRandomGeneratorA genA;
genA.seed = 123.0;
MyRandomGeneratorB genB;
return Model<MyRandomGeneratorA>(genA) + Model<MyRandomGeneratorB>(genB);
}

Просмотреть файл

@ -0,0 +1,40 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 125)
// template<unsigned M, unsigned N>
// struct Ackermann {
// enum {
// value = M ? (N ? Ackermann<M-1, Ackermann<M, N-1> >::value
// : Ackermann<M-1, 1>::value)
// : N + 1
// };
// };
template<unsigned int M, unsigned int N>
struct Ackermann {
enum {
value = Ackermann<M-1, Ackermann<M, N-1>::value >::value
};
};
template<unsigned int M> struct Ackermann<M, 0> {
enum {
value = Ackermann<M-1, 1>::value
};
};
template<unsigned int N> struct Ackermann<0, N> {
enum {
value = N + 1
};
};
template<> struct Ackermann<0, 0> {
enum {
value = 1
};
};
int main(int a:A) : SV_Target {
return Ackermann<3, 4>::value;
}

Просмотреть файл

@ -0,0 +1,28 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: error: 'a3' declared as an array with a negative size
template<int N>
void f() {
int a[] = { 1, 2, 3, N };
uint numAs = sizeof(a) / sizeof(int);
}
template void f<17>();
template<int N>
void f1() {
int a0[] = {}; // expected-warning{{zero}}
int a1[] = { 1, 2, 3, N };
int a3[sizeof(a1)/sizeof(int) != 4? 1 : -1]; // expected-error{{negative}}
}
namespace PR13788 {
template <uint __N>
struct S {
int V;
};
template <int N>
void foo() {
S<0> arr[N] = {{ 4 }};
}
}

Просмотреть файл

@ -0,0 +1,50 @@
// RUN: %dxc -T ps_6_0 -enable-templates %s 2>&1| FileCheck %s
// CHECK: error: use of 'X' with tag type that does not match previous declaration
// CHECK: note: in instantiation of template class 'PR6915::D<PR6915::D2>' requested here
// CHECK: note: previous use is here
// CHECK: error: no enum named 'X' in 'PR6915::D3'
// CHECK: error: nested name specifier for a declaration cannot depend on a template parameter
// CHECK: error: nested name specifier for a declaration cannot depend on a template parameter
// CHECK: error: nested name specifier for a declaration cannot depend on a template parameter
// CHECK: error: nested name specifier for a declaration cannot depend on a template parameter
// XCHECK: error: nested name specifier for a declaration cannot depend on a template parameter
// CHECK-NOT: error:
namespace PR6915 {
template <typename T>
class D {
enum T::X v; // expected-error{{use of 'X' with tag type that does not match previous declaration}} \
// expected-error{{no enum named 'X' in 'PR6915::D3'}}
};
struct D1 {
enum X { value };
};
struct D2 {
class X { }; // expected-note{{previous use is here}}
};
struct D3 { };
template class D<D1>;
template class D<D2>; // expected-note{{in instantiation of}}
template class D<D3>; // expected-note{{in instantiation of}}
}
template<typename T>
struct DeclOrDef {
enum T::foo; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
enum T::bar { // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
value
};
};
namespace PR6649 {
template <typename T> struct foo {
class T::bar; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
class T::bar { int x; }; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
};
}
namespace rdar8568507 {
template <class T> struct A makeA(T t);
}

Просмотреть файл

@ -0,0 +1,8 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: error: ISO C++ forbids forward references to 'enum' types
template<typename T>
struct X {
enum E e;
};

Просмотреть файл

@ -0,0 +1,19 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 0, i32 0, i8 0, i32 1)
template<uint n>
struct factorial {
enum { value = n * factorial<n -1>::value };
};
template<>
struct factorial<0> {
enum { value = 1 };
};
bool main(int4 a:A) : SV_Target {
return (factorial<0>::value == 1)
&& (factorial<1>::value == 1)
&& (factorial<3>::value == 6)
&& (factorial<4>::value == 24);
}

Просмотреть файл

@ -0,0 +1,27 @@
// RUN: %dxc -T vs_6_0 -E VSMain -enable-templates -DTYPENAME= %s | FileCheck %s -check-prefix=MISSING
// RUN: %dxc -T vs_6_0 -E VSMain -enable-templates -DTYPENAME=typename %s | FileCheck %s -check-prefix=PRESENT
// MISSING: error: missing 'typename' prior to dependent type name 'TVec::value_type'
// PRESENT: define void @VSMain() {
template <typename T>
struct Vec2 {
T x, y;
T Length() {
return sqrt(x*x + y*y);
}
typedef T value_type;
};
template <typename TVec>
TYPENAME TVec::value_type Length(TVec v) { // <-- Must be "typename TVec::value_type"
return v.Length();
}
void VSMain() {
Vec2<int> v_i;
Vec2<float> v_f;
int a = Length(v_i);
float b = Length(v_f);
}

Просмотреть файл

@ -0,0 +1,59 @@
// RUN: %dxc -E main -T ps_6_0 -strict-udt-casting %s | FileCheck %s
// RUN: %dxc -E main -T ps_6_0 -enable-templates -D USE_TEMPLATE %s | FileCheck %s
// Based on GitHub issue #3563
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 2.000000e+00)
struct LinearRGB
{
float3 RGB;
};
struct LinearYCoCg
{
float3 YCoCg;
};
#ifndef USE_TEMPLATE
// Without -strict-udt-casting
// error: call to 'GetLuma4' is ambiguous
float GetLuma4(LinearRGB In)
{
return In.RGB.g * 2.0 + In.RGB.r + In.RGB.b;
}
float GetLuma4(LinearYCoCg In)
{
return In.YCoCg.x;
}
#else // works but code getting too complicated
template<typename InputColorSpace>
float GetLuma4(InputColorSpace In);
template<>
float GetLuma4<LinearRGB>(LinearRGB In)
{
return In.RGB.g * 2.0 + In.RGB.r + In.RGB.b;
}
template<>
float GetLuma4<LinearYCoCg>(LinearYCoCg In)
{
return In.YCoCg.x;
}
#endif
float4 main() : SV_TARGET {
LinearYCoCg YCoCg = { {1.0f, 0.0, 0.0} };
float f = GetLuma4(YCoCg); // gets .x (1.0f)
LinearRGB Color;
Color.RGB = float3(0, f, 0);
return float4(GetLuma4(Color), 0.0, 0.0, 0.0);
}

Просмотреть файл

@ -0,0 +1,77 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates -strict-udt-casting %s | FileCheck %s
// Based on GitHub issue #3564
// CHECK: error: cannot initialize a variable of type 'LinearYCoCg' with an rvalue of type 'LinearRGB'
struct LinearRGB
{
float3 RGB;
};
struct LinearYCoCg
{
float3 YCoCg;
};
LinearYCoCg RGBToYCoCg(LinearRGB In)
{
float Y = dot(In.RGB, float3(1, 2, 1));
float Co = dot(In.RGB, float3(2, 0, -2));
float Cg = dot(In.RGB, float3(-1, 2, -1));
LinearYCoCg Out;
Out.YCoCg = float3(Y, Co, Cg);
return Out;
}
LinearRGB YCoCgToRGB(LinearYCoCg In)
{
float Y = In.YCoCg.x * float(0.25);
float Co = In.YCoCg.y * float(0.25);
float Cg = In.YCoCg.z * float(0.25);
float R = Y + Co - Cg;
float G = Y + Cg;
float B = Y - Co - Cg;
LinearRGB Out;
Out.RGB = float3(R, G, B);
return Out;
}
template<typename OutputColorSpace, typename InputColorSpace>
OutputColorSpace TransformColor(InputColorSpace In)
{
//static_assert(sizeof(InputColorSpace) == 0, "TransformColor() not implemented");
float Array[!sizeof(InputColorSpace)];
Array[0];
return In;
}
template<>
LinearYCoCg TransformColor<LinearYCoCg, LinearRGB>(LinearRGB In)
{
return RGBToYCoCg(In);
}
template<>
LinearRGB TransformColor<LinearRGB, LinearYCoCg>(LinearYCoCg In)
{
return YCoCgToRGB(In);
}
float4 main() : SV_TARGET {
LinearRGB Color;
Color.RGB = float3(0, 1, 0);
LinearYCoCg Color2 = TransformColor<LinearYCoCg>(Color);
LinearRGB Color3 = TransformColor<LinearRGB>(Color2);
// ISSUE: TransformColor<LinearRGB>() returns LinearRGB, but get cast silently in LinearYCoCg without error.
LinearYCoCg Color4 = TransformColor<LinearRGB>(Color2);
return float4(Color4.YCoCg, 0.0);
}

Просмотреть файл

@ -0,0 +1,12 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK:define void @main
template<typename T>
T foo(T t0, T t1) {
return sin(t0) * cos(t1);
}
float2 main(float4 a:A) : SV_Target {
return foo(a.x, a.y) + foo(a.xy, a.zw);
}

Просмотреть файл

@ -0,0 +1,18 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK:define void @main
struct Test {
template<typename T>
T foo(T t) {
return sin(t);
}
};
float2 main(float4 a:A) : SV_Target {
Test t0;
Test t1;
return t0.foo<float>(a.y) + t1.foo<float2>(a.zw);
}

Просмотреть файл

@ -0,0 +1,14 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK:define void @main
template<typename T>
struct TS {
T t;
};
struct TS<float4> ts;
float4 main() : SV_Target {
return ts.t;
}

Просмотреть файл

@ -0,0 +1,21 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK:define void @main
template<typename T>
struct Test {
T t;
T foo(T t1) {
return sin(t) * cos(t1);
}
};
float2 main(float4 a:A) : SV_Target {
Test<float> t0;
t0.t = a.x;
Test<float2> t1;
t1.t = a.xy;
return t0.foo(a.y) + t1.foo(a.zw);
}

Просмотреть файл

@ -0,0 +1,13 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK:define void @main
template<typename T>
T foo(T t0, T t1) {
return sin(t0) * cos(t1);
}
float2 main(float4 a:A) : SV_Target {
return foo(a.x, a.y) + foo(a.xy, a.zw);
}

Просмотреть файл

@ -0,0 +1,24 @@
// RUN: %dxc -T ps_6_0 -enable-templates %s | FileCheck %s
// Test applying the [] subscript operator in a templated function.
// With the side effect of testing passing matrices, arrays, and vectors as params.
template<typename T>
float4 subscript(T t0) {
return t0[3];
}
// CHECK: define void @main
// CHECK: @dx.op.loadInput.f32
// CHECK: @dx.op.loadInput.f32
// CHECK: @dx.op.loadInput.f32
bool main(float scalar : A, float4 vec : B, float4x4 mat : C, float4 arr[6] : D) : SV_Target {
return subscript(vec) + subscript(mat) + subscript(arr);
}

Просмотреть файл

@ -0,0 +1,31 @@
// RUN: %dxc -DTEMPLATE= -T ps_6_0 -enable-templates %s | FileCheck %s -check-prefix=CHK_FAIL
// RUN: %dxc -DTEMPLATE=template -T ps_6_0 -enable-templates %s | FileCheck %s -check-prefix=CHK_PASS
// CHK_PASS:define void @main
template<typename T>
struct F1 {
template <int B>
struct Iterator {
T t;
};
};
template<typename T>
struct F2 {
// CHK_FAIL: use 'template' keyword to treat 'Iterator' as a dependent template name
typename F1<T>:: TEMPLATE Iterator<0> Mypos; // expected-error {{
};
struct F2<float4> ts;
template <typename T>
float4 f(){
// CHK_FAIL: use 'template' keyword to treat 'Iterator' as a dependent template name
typename F1<T>:: TEMPLATE Iterator<0> Mypos = ts.Mypos;
return Mypos.t;
}
float4 main() : SV_Target {
return f<float4>();
}

Просмотреть файл

@ -0,0 +1,16 @@
// RUN: %dxc -E main -T ps_6_0 -enable-templates %s | FileCheck %s
// CHECK: error: variadic templates are not supported in HLSL
template<typename T>
T summation (T n) {
return n;
};
template<typename T, typename... Args>
T summation(T n, Args... args) {
return n + summation(args...);
};
int main(int a:A) : SV_Target {
return summation(1,3, 11, 7, a);
}

Просмотреть файл

@ -0,0 +1,48 @@
// RUN: %dxc -E main -T vs_6_0 -strict-udt-casting %s | FileCheck %s
// CHECK: SV_RenderTargetArrayIndex or SV_ViewportArrayIndex from any shader feeding rasterizer
struct Vertex
{
float4 position : POSITION0;
float4 color : COLOR0;
uint RTIndex : SV_RenderTargetArrayIndex;
};
struct Interpolants
{
float4 position : SV_POSITION0;
float4 color : COLOR0;
uint RTIndex : SV_RenderTargetArrayIndex;
};
struct Inh : Interpolants {
float a;
};
struct Interpolants2
{
float4 position : SV_POSITION0;
float4 color : COLOR0;
float4 color2 : COLOR2;
};
Interpolants2 c2;
Inh c;
int i;
uint4 i4;
Interpolants main( Vertex In)
{
if (i>1)
return (Interpolants)i4.z;
else if (i>0)
return (Interpolants) c;
else if (i > -1)
return (Interpolants )c2;
return (Interpolants)In;
}

Просмотреть файл

@ -0,0 +1,150 @@
// RUN: %dxc /Tvs_6_0 /Emain -strict-udt-casting %s | FileCheck %s
// Test explicit cast between structs of identical layout where
// the destination struct is marked as out param.
// o1.f1 = input.f1
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 1.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 2.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 3.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 4.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.f3[4] = input.f3[4]
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 0, i8 0, float 1.300000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 0, i8 1, float 1.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 1, i8 0, float 1.500000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 1, i8 1, float 1.600000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 2, i8 0, float 1.700000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 2, i8 1, float 1.800000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 3, i8 0, float 1.900000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 2, i32 3, i8 1, float 2.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.f4 = input.f4
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 3, i32 0, i8 0, i32 21) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 3, i32 0, i8 1, i32 22) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 3, i32 0, i8 2, i32 23) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.s.f5 = input.s.f5
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 4, i32 0, i8 0, float 2.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 4, i32 0, i8 1, float 2.500000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 4, i32 0, i8 2, float 2.600000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 4, i32 0, i8 3, float 2.700000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.s.f6 = input.s.f6
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 5, i32 0, i8 0, float 2.800000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 5, i32 0, i8 1, float 2.900000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 5, i32 0, i8 2, float 3.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.f7 = input.f7
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 6, i32 0, i8 0, i32 1) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f1 = input.f1
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 7, i32 0, i8 0, float 1.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 7, i32 0, i8 1, float 2.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 7, i32 0, i8 2, float 3.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 7, i32 0, i8 3, float 4.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f3[4] = input.f3[4]
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 0, i8 0, float 1.300000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 0, i8 1, float 1.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 1, i8 0, float 1.500000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 1, i8 1, float 1.600000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 2, i8 0, float 1.700000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 2, i8 1, float 1.800000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 3, i8 0, float 1.900000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 9, i32 3, i8 1, float 2.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f4 = input.f4
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 10, i32 0, i8 0, i32 21) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 10, i32 0, i8 1, i32 22) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 10, i32 0, i8 2, i32 23) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f5 = input.f5
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 11, i32 0, i8 0, float 2.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 11, i32 0, i8 1, float 2.500000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 11, i32 0, i8 2, float 2.600000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 11, i32 0, i8 3, float 2.700000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f6 = input.f6
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 12, i32 0, i8 0, float 2.800000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 12, i32 0, i8 1, float 2.900000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 12, i32 0, i8 2, float 3.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f7 = input.f7
// CHECK: call void @dx.op.storeOutput.i32(i32 5, i32 13, i32 0, i8 0, i32 1) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o1.f2 (column_major) = input.f2
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 0, float 5.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 1, float 7.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 2, float 9.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 3, float 1.100000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 1, i8 0, float 6.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 1, i8 1, float 8.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 1, i8 2, float 1.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 1, i8 3, float 1.200000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// o2.f2 (column_major) = input.f2
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 0, i8 0, float 5.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 0, i8 1, float 7.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 0, i8 2, float 9.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 0, i8 3, float 1.100000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 1, i8 0, float 6.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 1, i8 1, float 8.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 1, i8 2, float 1.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 8, i32 1, i8 3, float 1.200000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
struct VSIn_1
{
float4 f5 : VIN4;
float3 f6 : VIN5;
};
struct VSIn
{
float4 f1 : VIN0;
float4x2 f2 : VIN1;
float2 f3[4] : VIN2;
uint3 f4 : VIN3;
VSIn_1 s;
bool f7 : VIN6;
};
struct VSOut_1
{
float4 f5 : VOUT4;
float3 f6 : VOUT5;
};
struct VSOut
{
float4 f1 : VOUT0;
float4x2 f2 : VOUT1;
float2 f3[4] : VOUT2;
uint3 f4 : VOUT3;
VSOut_1 s;
bool f7 : VOUT6;
};
void main(out VSOut o1 : A, out VSOut o2 : B)
{
VSIn input;
input.f1 = float4(1, 2, 3, 4);
input.f2[0][0] = 5;
input.f2[0][1] = 6;
input.f2[1][0] = 7;
input.f2[1][1] = 8;
input.f2[2][0] = 9;
input.f2[2][1] = 10;
input.f2[3][0] = 11;
input.f2[3][1] = 12;
input.f3[0] = float2(13, 14);
input.f3[1] = float2(15, 16);
input.f3[2] = float2(17, 18);
input.f3[3] = float2(19, 20);
input.f4 = uint3(21, 22, 23);
input.s.f5 = float4(24, 25, 26, 27);
input.s.f6 = float3(28, 29, 30);
input.f7 = true;
o1 = (VSOut)input;
o2 = (VSOut)input;
}

Просмотреть файл

@ -0,0 +1,54 @@
// RUN: %dxc -E main -T ps_6_0 -strict-udt-casting %s | FileCheck %s
// github issue #1725
// Test implicit cast scenario between structs of identical layout
// which would crash as reported by a user.
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00)
struct BUFF
{
float4 rt0 : SV_Target0;
};
struct VSOUT_A
{
float4 hclip : SV_Position;
float3 wp : WORLD_POSITION;
};
struct VSOUT_B
{
VSOUT_A position;
float3 normal : NORMAL;
};
struct VSOUT_C
{
VSOUT_A position;
float3 normal : NORMAL;
};
float3 getNormal(in VSOUT_B vsout)
{
return vsout.normal;
}
struct VSOUT_D
{
VSOUT_C standard;
};
void foo(in VSOUT_A stdP)
{
(stdP) = (stdP);
}
BUFF main(VSOUT_D input)
{
foo(input.standard.position); // comment out and it will compile fine
float3 N = getNormal( (VSOUT_B)input.standard ); // comment this out and it will compile fine
return (BUFF)0;
}

Просмотреть файл

@ -0,0 +1,62 @@
// RUN: %dxc /Tgs_6_0 /Emain -strict-udt-casting %s | FileCheck %s
// github issue #1560
// CHECK: main
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 1.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 2.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 3.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 4.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 0, float 5.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 1, float 6.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 2, float 7.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 3, float 8.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.emitStream(i32 97, i8 0) ; EmitStream(streamId)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 9.000000e+00) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 1.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 1.100000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 1.200000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 0, float 1.300000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 1, float 1.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 2, float 1.500000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 3, float 1.600000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.emitStream(i32 97, i8 0) ; EmitStream(streamId)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 1.700000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 1.800000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 1.900000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 2.000000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 0, float 2.100000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 1, float 2.200000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 2, float 2.300000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 1, i32 0, i8 3, float 2.400000e+01) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
// CHECK: call void @dx.op.emitStream(i32 97, i8 0) ; EmitStream(streamId)
// CHECK: ret void
struct VSOutGSIn
{
float4 clr : COLOR0;
float4 pos : SV_Position;
};
struct GSOutPSIn
{
float4 clr : COLOR0;
float4 pos : SV_Position;
};
[maxvertexcount(3)]
void main(inout TriangleStream<GSOutPSIn> stream)
{
VSOutGSIn tri[3];
tri[0].clr = float4(1, 2, 3, 4);
tri[0].pos = float4(5, 6, 7, 8);
tri[1].clr = float4(9, 10, 11, 12);
tri[1].pos = float4(13, 14, 15, 16);
tri[2].clr = float4(17, 18, 19, 20);
tri[2].pos = float4(21, 22, 23, 24);
stream.Append((GSOutPSIn)tri[0]);
stream.Append((GSOutPSIn)tri[1]);
stream.Append((GSOutPSIn)tri[2]);
}

Просмотреть файл

@ -0,0 +1,23 @@
// RUN: %dxc -E main -T vs_6_0 -strict-udt-casting %s | FileCheck %s
// Tests declarations and uses of anonymous structs.
// CHECK: call i32 @dx.op.loadInput.i32
// CHECK: call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32
// CHECK: add nsw i32
// CHECK: call void @dx.op.storeOutput.i32
typedef struct { int x; } typedefed;
struct { int x; } global;
struct Outer
{
struct { int x; } field;
};
int main(Outer input : IN) : OUT
{
struct { int x; } local = input.field;
typedefed retval = (typedefed)local;
return retval.x + global.x;
}

Просмотреть файл

@ -0,0 +1,135 @@
// RUN: %dxc /Zi /T vs_6_2 /E main %s | FileCheck %s
RWByteAddressBuffer BufferOut : register(u0);
// The store of p.y into the temporary was not
// getting extended to 32 bits, so uninitialized
// bits of the temporary were used. 7366161.
struct foo {
int x : 8;
int : 8;
int y : 16;
};
int main(struct foo p : IN0, int x : IN1) : OUT {
// CHECK: %[[val:.*]] = {{.*}}loadInput{{.*}} i32 0, i32 0, {{.*}}
// CHECK: ashr i32 %[[val]]
BufferOut.Store(p.x, asuint(p.y));
x = (p.y > x ? x : p.y);
return x;
}
struct M {
uint f0;
uint bf0 : 8;
uint bf1 : 24;
uint f1;
uint : 8;
uint bf2 : 16;
uint : 8;
uint f2;
};
void m(uint3 xyz : IN) {
M m;
m.f0 = 0;
m.bf1 = xyz.x;
m.f1 = xyz.y;
m.bf2 = xyz.z;
m.f2 = 1;
BufferOut.Store(m.f1*16, asuint(m.bf1 + m.bf2));
return;
}
struct S {
uint : 8;
uint : 8;
uint x : 8;
} s;
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x", {{.*}}, size: 8, align: 32, offset: 16)
// Below adapted from clang test suite.
// PR14638; make sure this doesn't crash.
struct A {
bool m_sorted : 1;
};
void func1(bool b, A a1)
{
if ((a1.m_sorted = b)) {}
}
struct TEST2
{
int subid:32;
int :0;
};
typedef struct _TEST3
{
TEST2 foo;
TEST2 foo2;
} TEST3;
void test() {
TEST3 test =
{
{0, 0},
{0, 0}
};
}
struct P1 {
uint l_Packed;
uint k_Packed : 6,
i_Packed : 15,
j_Packed : 11;
};
struct P2 {
uint l_Packed;
uint k_Packed : 6,
i_Packed : 15;
uint c;
};
struct P1 sM_Packed;
int p() : OUT {
struct P2 x;
return (x.i_Packed != 0);
}
struct Bork {
unsigned int f1 : 3;
unsigned int f2 : 30;
};
void bork(Bork hdr : IN) {
hdr.f1 = 7;
hdr.f2 = 927;
}
struct F {
bool b1 : 1;
bool b2 : 7;
};
bool f() : OUT
{
F f = { true, true };
return f.b1 != 1;
}
struct s8_0 { uint : 0; };
struct s8_1 { double x; };
struct s8 { s8_0 a; s8_1 b; };
s8 g() : OUT { s8 s; s.b.x = 0.0; return s; }
// Exclude quoted source file
// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}

Просмотреть файл

@ -1,6 +0,0 @@
// RUN: %dxc /T vs_6_0 /E main %s | FileCheck %s
// CHECK: error: bitfields are not supported in HLSL
struct Struct { uint field : 1; };
void main() {}

Просмотреть файл

@ -0,0 +1,35 @@
// RUN: %dxc -E main -T vs_6_0 -strict-udt-casting %s | FileCheck %s
// CHECK: @main
struct Vertex
{
float4 position : POSITION0;
float4 color : COLOR0;
};
struct Interpolants
{
float4 position : SV_POSITION0;
float4 color : COLOR0;
};
struct T {
float4 t;
};
struct TA {
T ta[2];
};
TA test(T t[2]) {
TA ta = { t };
return ta;
}
Interpolants main( Vertex In)
{
TA ta = (TA)In;
return (Interpolants)test(ta.ta);
}

Просмотреть файл

@ -0,0 +1,85 @@
// RUN: %dxc -E main -T ps_6_0 -Od -strict-udt-casting %s | FileCheck %s
//
// CHECK: @main
//
// Regression test for certain allocas not being split by SROA because
// SROA_Helper::LowerMemcpy returned true but didn't actually remove all uses
// of the alloca.
//
// Consider the following example:
//
// a = alloca MyStruct
// b = alloca MyStruct
// c = alloca MyStruct
// ...
// memcpy(b, a, sizeof(MyStruct))
// ...
// memcpy(c, b, sizeof(MyStruct))
//
// When SROA_Helper::LowerMemcpy is working on b, ReplaceMemcpy replaces the
// memcpy with loads and stores and returns true:
//
// a = alloca MyStruct
// b = alloca MyStruct
// c = alloca MyStruct
// ...
// b->member1 = a->member1;
// b->member2 = a->member2;
// ...
// b->memberN = a->memberN;
// ...
// memcpy(c, b, sizeof(MyStruct))
//
// At this point SROA_Helper::LowerMemcpy returned true because it incorrectly
// assumed that all uses of `b` has been removed because it only has one store
// which is memcpy, and ReplaceMemcpy has replaced it, even though the alloca
// is still being used.
//
struct MyStruct {
float4 foo;
float4 bar;
float4 baz;
};
cbuffer cb : register(b0) {
float4 foo;
float4 bar;
float4 baz;
};
MyStruct make() {
MyStruct local;
local.foo = foo;
local.bar = bar;
local.baz = baz;
return local;
}
MyStruct transform_mul(MyStruct arg_0) {
MyStruct st[1] = {{
arg_0.foo * 2,
arg_0.bar * 2,
arg_0.baz * 2,
}};
return arg_0;
}
MyStruct transform(MyStruct arg) {
MyStruct ret;
ret = transform_mul(arg);
return ret;
}
float4 main() : SV_Target {
MyStruct v0 = (MyStruct)0;
v0 = make();
MyStruct v1[1] = {transform(v0)};
MyStruct v2[1] = {transform(v1[0])};
MyStruct v3[1] = {transform(v2[0])};
MyStruct v4[1] = {transform(v3[0])};
return v4[0].foo + v4[0].bar + v4[0].baz;
}

Просмотреть файл

@ -0,0 +1,19 @@
// RUN: %dxc -E main -T gs_6_0 -strict-udt-casting %s | FileCheck %s
// Regression test for an SROA bug where the flattening the output stream argument
// would not handle the case where its input had already been SROA'd.
// CHECK: define void @main()
// CHECK: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 0)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float {{.*}})
// CHECK: call void @dx.op.emitStream(i32 97, i8 0)
// CHECK: ret void
struct GSIn { float value : TEXCOORD0; };
struct GSOut { float value : TEXCOORD0; };
[maxvertexcount(1)]
void main(point GSIn input[1], inout PointStream<GSOut> output)
{
output.Append((GSOut)input[0]);
}

Просмотреть файл

@ -0,0 +1,19 @@
// RUN: %dxc -E main -T gs_6_0 -strict-udt-casting %s | FileCheck %s
// Regression test for an SROA bug where the flattening the output stream argument
// would not handle the case where its input had already been SROA'd.
// CHECK: define void @main()
// CHECK: call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 0)
// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float {{.*}})
// CHECK: call void @dx.op.emitStream(i32 97, i8 0)
// CHECK: ret void
struct GSIn { float value : TEXCOORD0; };
struct GSOut { float value : TEXCOORD0; };
[maxvertexcount(1)]
void main(inout PointStream<GSOut> output, point GSIn input[1])
{
output.Append((GSOut)input[0]);
}

Просмотреть файл

@ -0,0 +1,36 @@
// RUN: %dxc -T lib_6_x -default-linkage external -strict-udt-casting %s | FileCheck %s
// CHECK: define <4 x float>
// CHECK-SAME: main
// CHECK-NOT: bitcast
// CHECK-NOT: CallStruct
// CHECK: ParamStruct
// CHECK: call void @llvm.lifetime.start
// CHECK-NOT: bitcast
// CHECK-NOT: CallStruct
// CHECK-LABEL: ret <4 x float>
struct ParamStruct {
int i;
float f;
};
struct CallStruct {
int i;
float f;
};
void modify(inout ParamStruct s) {
s.f += 1;
}
void modify_ext(inout ParamStruct s);
CallStruct g_struct;
float4 main() : SV_Target {
CallStruct local = g_struct;
modify((ParamStruct)local);
modify_ext((ParamStruct)local);
return local.f;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше