Merge remote-tracking branch 'origin/hlsl-2021' into merge-hlsl2021-master
This commit is contained in:
Коммит
a4dfa1c40c
|
@ -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,9 +3075,8 @@ 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());
|
||||
// For structs, we GEP to the field that the record layout suggests.
|
||||
Addr = Builder.CreateStructGEP(nullptr, Addr, Idx, field->getName());
|
||||
// Get the access type.
|
||||
llvm::Type *PtrTy = llvm::Type::getIntNPtrTy(
|
||||
getLLVMContext(), Info.StorageSize,
|
||||
|
|
|
@ -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,32 +3700,34 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
|
|||
return tmp5;
|
||||
}
|
||||
// HLSL Change Starts
|
||||
if (CGF.getLangOpts().HLSL &&
|
||||
(hlsl::IsHLSLVecType(E->getType()) || E->getType()->isArithmeticType())) {
|
||||
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
|
||||
llvm::Value *LHS = Visit(lhsExpr);
|
||||
llvm::Value *RHS = Visit(rhsExpr);
|
||||
if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(CondV->getType())) {
|
||||
llvm::VectorType *ResultVT = cast<llvm::VectorType>(LHS->getType());
|
||||
llvm::Value *result = llvm::UndefValue::get(ResultVT);
|
||||
for (unsigned i = 0; i < VT->getNumElements(); i++) {
|
||||
llvm::Value *EltCond = Builder.CreateExtractElement(CondV, i);
|
||||
llvm::Value *EltL = Builder.CreateExtractElement(LHS, i);
|
||||
llvm::Value *EltR = Builder.CreateExtractElement(RHS, i);
|
||||
llvm::Value *EltSelect = Builder.CreateSelect(EltCond, EltL, EltR);
|
||||
result = Builder.CreateInsertElement(result, EltSelect, i);
|
||||
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);
|
||||
if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(CondV->getType())) {
|
||||
llvm::VectorType *ResultVT = cast<llvm::VectorType>(LHS->getType());
|
||||
llvm::Value *result = llvm::UndefValue::get(ResultVT);
|
||||
for (unsigned i = 0; i < VT->getNumElements(); i++) {
|
||||
llvm::Value *EltCond = Builder.CreateExtractElement(CondV, i);
|
||||
llvm::Value *EltL = Builder.CreateExtractElement(LHS, i);
|
||||
llvm::Value *EltR = Builder.CreateExtractElement(RHS, i);
|
||||
llvm::Value *EltSelect = Builder.CreateSelect(EltCond, EltL, EltR);
|
||||
result = Builder.CreateInsertElement(result, EltSelect, i);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Builder.CreateSelect(CondV, LHS, RHS);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return Builder.CreateSelect(CondV, LHS, RHS);
|
||||
}
|
||||
}
|
||||
if (CGF.getLangOpts().HLSL && 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});
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
? diag::warn_cxx98_compat_variadic_templates
|
||||
: diag::ext_variadic_templates);
|
||||
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,41 +2411,57 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
|
|||
objInstr = accessToBaseInstr;
|
||||
objectType = accessToBaseInstr->getAstResultType();
|
||||
}
|
||||
|
||||
// If not already a variable, we need to create a temporary variable and
|
||||
// pass the object pointer to the function. Example:
|
||||
// getObject().objectMethod();
|
||||
// Also, any parameter passed to the member function must be of Function
|
||||
// storage class.
|
||||
if (objInstr->isRValue()) {
|
||||
args.push_back(createTemporaryVar(
|
||||
objectType, getAstTypeName(objectType),
|
||||
// May need to load to use as initializer
|
||||
loadIfGLValue(object, objInstr), object->getLocStart()));
|
||||
} else {
|
||||
// Based on SPIR-V spec, function parameter must always be in Function
|
||||
// scope. If we pass a non-function scope argument, we need
|
||||
// the legalization.
|
||||
if (objInstr->getStorageClass() != spv::StorageClass::Function ||
|
||||
!isMemoryObjectDeclaration(objInstr))
|
||||
needsLegalization = true;
|
||||
|
||||
args.push_back(objInstr);
|
||||
}
|
||||
|
||||
// We do not need to create a new temporary variable for the this
|
||||
// object. Use the evaluated argument.
|
||||
vars.push_back(args.back());
|
||||
isTempVar.push_back(false);
|
||||
}
|
||||
} 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();
|
||||
// Also, any parameter passed to the member function must be of Function
|
||||
// storage class.
|
||||
if (objInstr->isRValue()) {
|
||||
args.push_back(createTemporaryVar(
|
||||
objectType, getAstTypeName(objectType),
|
||||
// May need to load to use as initializer
|
||||
loadIfGLValue(object, objInstr), object->getLocStart()));
|
||||
} else {
|
||||
// Based on SPIR-V spec, function parameter must always be in Function
|
||||
// scope. If we pass a non-function scope argument, we need
|
||||
// the legalization.
|
||||
if (objInstr->getStorageClass() != spv::StorageClass::Function ||
|
||||
!isMemoryObjectDeclaration(objInstr))
|
||||
needsLegalization = true;
|
||||
|
||||
args.push_back(objInstr);
|
||||
}
|
||||
|
||||
// We do not need to create a new temporary variable for the this
|
||||
// object. Use the evaluated argument.
|
||||
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,7 +8562,12 @@ 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;
|
||||
}
|
||||
|
|
|
@ -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,20 +292,46 @@ void LookupResult::configure() {
|
|||
IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus,
|
||||
isForRedeclaration());
|
||||
|
||||
// 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.
|
||||
switch (NameInfo.getName().getCXXOverloadedOperator()) {
|
||||
case OO_New:
|
||||
case OO_Delete:
|
||||
case OO_Array_New:
|
||||
case OO_Array_Delete:
|
||||
getSema().DeclareGlobalNewDelete();
|
||||
break;
|
||||
// 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.
|
||||
switch (NameInfo.getName().getCXXOverloadedOperator()) {
|
||||
case OO_New:
|
||||
case OO_Delete:
|
||||
case OO_Array_New:
|
||||
case OO_Array_Delete:
|
||||
getSema().DeclareGlobalNewDelete();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
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;
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче