diff --git a/include/dxc/DxcReflection/DxcReflectionContainer.h b/include/dxc/DxcReflection/DxcReflectionContainer.h new file mode 100644 index 0000000000..0111cba9c2 --- /dev/null +++ b/include/dxc/DxcReflection/DxcReflectionContainer.h @@ -0,0 +1,1008 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// DxcReflectionContainer.h // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include "dxc/WinAdapter.h" +// need to disable this as it is voilated by this header +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +// Need to instruct non-windows compilers on what an interface is +#define interface struct +#endif + +#include "d3d12shader.h" +#include "dxc/dxcreflect.h" + +#pragma warning(disable : 4201) + +namespace hlsl { + +struct ReflectionError { + + const char *err; + const char *func; + + uint32_t index; // For example which elementId made this error + bool hasIndex; + uint8_t pad[3]; + + constexpr ReflectionError() + : err(nullptr), func(nullptr), index(0), hasIndex(false), pad{0, 0, 0} {} + + constexpr ReflectionError(const char *err, const char *func) + : err(err), func(func), index(0), hasIndex(false), pad{0, 0, 0} {} + + constexpr ReflectionError(const char *err, const char *func, uint32_t index) + : err(err), func(func), index(index), hasIndex(true), pad{0, 0, 0} {} + + std::string toString() const { + + if (!err) + return ""; + + std::string res = err; + + if (hasIndex) + res += " (at index " + std::to_string(index) + ")"; + + if (func) + res += " (" + std::string(func) + ")"; + + return res; + } + + operator bool() const { return err; } +}; + +static constexpr const ReflectionError ReflectionErrorSuccess = {}; + +#ifndef NDEBUG +#if defined(_MSC_VER) +#define HLSL_REFL_ERR_FUNC_NAME __FUNCTION__ +#elif defined(__clang__) || defined(__GNUC__) +#define HLSL_REFL_ERR_FUNC_NAME __PRETTY_FUNCTION__ +#else +#define HLSL_REFL_ERR_FUNC_NAME __func__ +#endif +#define HLSL_REFL_ERR_STRING(x) #x +#define HLSL_REFL_ERR_STRING2(x) HLSL_REFL_ERR_STRING(x) +#define HLSL_REFL_ERR(x, ...) \ + ReflectionError(x " at " __FILE__ ":" HLSL_REFL_ERR_STRING2(__LINE__), \ + HLSL_REFL_ERR_FUNC_NAME, ##__VA_ARGS__) +#else +#define HLSL_REFL_ERR(x, ...) ReflectionError(x, nullptr, ##__VA_ARGS__) +#endif + +class ReflectionNode { + + uint32_t LocalIdParentLo; // 24 : 8 + + union { + uint32_t ParentHiAnnotationsType32; + struct { + uint16_t ParentHi; + uint8_t Annotations; + uint8_t Type; + }; + }; + + uint32_t ChildCountFwdBckLo; // 24 : 8 + + union { + uint32_t AnnotationStartFwdBckHi; + struct { + uint16_t AnnotationStart; + uint16_t FwdBckHi; + }; + }; + + union { + uint32_t SemanticIdInterpolationMode; + struct { + uint16_t SemanticId; + uint8_t InterpolationMode; // D3D_INTERPOLATION_MODE + uint8_t Padding; + }; + }; + + void SetFwdBck(uint32_t v) { + FwdBckHi = v >> 8; + ChildCountFwdBckLo &= 0xFFFFFF; + ChildCountFwdBckLo |= v << 24; + } + + ReflectionNode(D3D12_HLSL_NODE_TYPE NodeType, bool IsFwdDeclare, + uint32_t LocalId, uint16_t AnnotationStart, + uint32_t ChildCount, uint32_t ParentId, + uint8_t AnnotationCount, uint16_t SemanticId, + D3D_INTERPOLATION_MODE InterpolationMode) + : LocalIdParentLo(LocalId | (ParentId << 24)), ParentHi(ParentId >> 8), + Annotations(AnnotationCount), Type(NodeType), + ChildCountFwdBckLo(ChildCount | (0xFFu << 24)), + AnnotationStart(AnnotationStart), FwdBckHi(0xFFFF), + SemanticId(SemanticId), InterpolationMode(InterpolationMode), + Padding(0) { + + if (IsFwdDeclare) + Type |= 0x80; + } + +public: + ReflectionNode() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionNode &OutNode, D3D12_HLSL_NODE_TYPE NodeType, + bool IsFwdDeclare, uint32_t LocalId, uint16_t AnnotationStart, + uint32_t ChildCount, uint32_t ParentId, uint8_t AnnotationCount, + uint16_t SemanticId, D3D_INTERPOLATION_MODE InterpolationMode) { + + if (NodeType < D3D12_HLSL_NODE_TYPE_START || + NodeType > D3D12_HLSL_NODE_TYPE_END) + return HLSL_REFL_ERR("Invalid NodeType"); + + if (InterpolationMode < D3D_INTERPOLATION_UNDEFINED || + InterpolationMode > D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE) + return HLSL_REFL_ERR("Invalid interpolation mode"); + + if (LocalId >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("LocalId out of bounds"); + + if (ParentId >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("ParentId out of bounds"); + + if (ChildCount >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("ChildCount out of bounds"); + + if (IsFwdDeclare && AnnotationCount) + return HLSL_REFL_ERR("Fwd declares aren't allowed to have annotations"); + + OutNode = ReflectionNode(NodeType, IsFwdDeclare, LocalId, AnnotationStart, + ChildCount, ParentId, AnnotationCount, SemanticId, + InterpolationMode); + return ReflectionErrorSuccess; + } + + bool IsFwdDeclare() const { return Type >> 7; } + + // FwdBck is the only one that is allowed to break the DAG. + // Example: + // Node 0 (struct T;) <- IsFwdDeclare() and points to definition + // Node 1 uses struct T; + // Node 2 (struct T { float T; };) <- no fwd declare and points to fwd + // declare. + // + // So the following are defined: + // IsFwdDeclare() && IsFwdDefined(): GetFwdBck() should point to a valid node + // that points back to the fwd declare. + // !IsFwdDeclare() && IsFwdDefined(): GetFwdBck() should point to a valid fwd + // declare that points back to it. + // Backwards declare should point to a NodeId < self and Forwards to > self. + // Forward declares aren't allowed to have any children except functions, + // which can have parameters only (inc. return). + // If there's a name, they should match. + // Must be same node type too. + // Only allowed on functions, struct/union and enums. + + uint32_t GetFwdBck() const { + return uint32_t(ChildCountFwdBckLo >> 24) | (uint32_t(FwdBckHi) << 8); + } + + bool IsFwdBckDefined() const { return GetFwdBck() != ((1 << 24) - 1); } + + [[nodiscard]] ReflectionError ResolveFwdDeclare(uint32_t SelfId, + ReflectionNode &Definition, + uint32_t DefinitionId) { + + if (SelfId >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("SelfId out of bounds"); + + if (DefinitionId >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("DefinitionId out of bounds"); + + assert(DefinitionId != SelfId && "NodeId can't be definition id!"); + assert(IsFwdDeclare() && + "Can't run ResolveFwdDeclare on a node that's no fwd decl"); + + assert(!Definition.IsFwdBckDefined() && !IsFwdBckDefined() && + "Fwd & backward declare must not be defined yet"); + + SetFwdBck(DefinitionId); + Definition.SetFwdBck(SelfId); + + return ReflectionErrorSuccess; + } + + // For example if Enum, maps into Enums[LocalId] + uint32_t GetLocalId() const { return LocalIdParentLo << 8 >> 8; } + uint32_t GetAnnotationStart() const { return AnnotationStart; } + + uint32_t GetSemanticId() const { + return SemanticId == uint16_t(-1) ? uint32_t(-1) : SemanticId; + } + + D3D_INTERPOLATION_MODE GetInterpolationMode() const { + return D3D_INTERPOLATION_MODE(InterpolationMode); + } + + D3D12_HLSL_NODE_TYPE GetNodeType() const { + return D3D12_HLSL_NODE_TYPE(Type & 0x7F); + } + + // Includes recursive children + uint32_t GetChildCount() const { return ChildCountFwdBckLo << 8 >> 8; } + + uint32_t GetAnnotationCount() const { return Annotations; } + + uint32_t GetParentId() const { + return uint32_t(LocalIdParentLo >> 24) | (uint32_t(ParentHi) << 8); + } + + [[nodiscard]] ReflectionError IncreaseChildCount() { + + if (GetChildCount() >= ((1u << 24) - 1)) + return HLSL_REFL_ERR("Child count out of bounds"); + + ++ChildCountFwdBckLo; + return ReflectionErrorSuccess; + } + + bool operator==(const ReflectionNode &other) const { + return LocalIdParentLo == other.LocalIdParentLo && + ParentHiAnnotationsType32 == other.ParentHiAnnotationsType32 && + ChildCountFwdBckLo == other.ChildCountFwdBckLo && + AnnotationStartFwdBckHi == other.AnnotationStartFwdBckHi && + SemanticIdInterpolationMode == other.SemanticIdInterpolationMode; + } +}; + +class ReflectionNodeSymbol { + + union { + struct { + uint32_t NameId; // Local name (not including parent's name) + + uint16_t FileSourceId; //-1 == no file info + uint16_t SourceLineCount; + }; + uint64_t NameIdFileNameIdSourceLineCount; + }; + + union { + struct { + uint16_t SourceColumnStartLo; + uint16_t SourceColumnEndLo; + uint32_t ColumnHiSourceLinePad; // 6 : 6 : 20 + }; + uint64_t SourceColumnStartEndLo; + }; + + ReflectionNodeSymbol(uint32_t NameId, uint16_t FileSourceId, + uint16_t SourceLineCount, uint32_t SourceLineStart, + uint32_t SourceColumnStart, uint32_t SourceColumnEnd) + : NameId(NameId), FileSourceId(FileSourceId), + SourceLineCount(SourceLineCount), + SourceColumnStartLo(uint16_t(SourceColumnStart)), + SourceColumnEndLo(uint16_t(SourceColumnEnd)), + ColumnHiSourceLinePad((SourceColumnStart >> 16) | + (SourceColumnEnd >> 16 << 6) | + (SourceLineStart << 12)) {} + +public: + ReflectionNodeSymbol() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionNodeSymbol &Symbol, uint32_t NameId, + uint16_t FileSourceId, uint16_t SourceLineCount, + uint32_t SourceLineStart, uint32_t SourceColumnStart, + uint32_t SourceColumnEnd) { + + if (SourceColumnStart >= (1u << 22)) + return HLSL_REFL_ERR("SourceColumnStart out of bounds"); + + if (SourceColumnEnd >= (1u << 22)) + return HLSL_REFL_ERR("SourceColumnEnd out of bounds"); + + if (SourceLineStart >= ((1u << 20) - 1)) + return HLSL_REFL_ERR("SourceLineStart out of bounds"); + + Symbol = ReflectionNodeSymbol(NameId, FileSourceId, SourceLineCount, + SourceLineStart, SourceColumnStart, + SourceColumnEnd); + return ReflectionErrorSuccess; + } + + uint32_t GetNameId() const { return NameId; } + + uint16_t GetFileSourceId() const { return FileSourceId; } + bool HasFileSource() const { return FileSourceId != uint16_t(-1); } + uint16_t GetSourceLineCount() const { return SourceLineCount; } + + uint32_t GetSourceLineStart() const { + return uint32_t(ColumnHiSourceLinePad >> 12); + } + + uint32_t GetSourceColumnStart() const { + return SourceColumnStartLo | ((ColumnHiSourceLinePad & 0x3F) << 16); + } + + uint32_t GetSourceColumnEnd() const { + return SourceColumnEndLo | ((ColumnHiSourceLinePad & (0x3F << 6)) << 10); + } + + bool operator==(const ReflectionNodeSymbol &other) const { + return NameIdFileNameIdSourceLineCount == + other.NameIdFileNameIdSourceLineCount && + SourceColumnStartEndLo == other.SourceColumnStartEndLo; + } +}; + +struct ReflectionEnumeration { + + uint32_t NodeId; + D3D12_HLSL_ENUM_TYPE Type; + + bool operator==(const ReflectionEnumeration &other) const { + return NodeId == other.NodeId && Type == other.Type; + } +}; + +struct ReflectionEnumValue { + + int64_t Value; + uint32_t NodeId; + + bool operator==(const ReflectionEnumValue &other) const { + return Value == other.Value && NodeId == other.NodeId; + } +}; + +struct ReflectionFunctionParameter { // Mirrors D3D12_PARAMETER_DESC without + // duplicating data (typeId holds some) + + uint32_t TypeId; + uint32_t NodeId; + + uint32_t Flags; // D3D_PARAMETER_FLAGS + + bool operator==(const ReflectionFunctionParameter &other) const { + return TypeId == other.TypeId && NodeId == other.NodeId && + Flags == other.Flags; + } +}; + +// A statement is a for or a while statement. +// - if HasConditionVar(): a variable in the condition +// - NodeCount children (For: init children) +// - Rest of the body (body) +class ReflectionScopeStmt { + + uint32_t NodeId; + uint32_t NodeCount_HasConditionVar_HasElse; + + ReflectionScopeStmt(uint32_t NodeId, uint32_t NodeCount, bool HasConditionVar, + bool IfAndHasElse) + : NodeId(NodeId), + NodeCount_HasConditionVar_HasElse(NodeCount | + (HasConditionVar ? (1u << 30) : 0) | + (IfAndHasElse ? (1u << 31) : 0)) {} + +public: + ReflectionScopeStmt() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionScopeStmt &Statement, uint32_t NodeId, + uint32_t NodeCount, bool HasConditionVar, bool IfAndHasElse) { + + if (NodeCount >= (1u << 30)) + return HLSL_REFL_ERR("NodeCount out of bounds"); + + Statement = + ReflectionScopeStmt(NodeId, NodeCount, HasConditionVar, IfAndHasElse); + return ReflectionErrorSuccess; + } + + uint32_t GetNodeId() const { return NodeId; } + + // Node count represents one of two things: + // - If: The amount of nodes in the 'if' part of the branch (to be able to + // find the else part) + // - For: The amount of nodes in the initialize part of the for + uint32_t GetNodeCount() const { + return NodeCount_HasConditionVar_HasElse << 2 >> 2; + } + + bool HasConditionVar() const { + return (NodeCount_HasConditionVar_HasElse >> 30) & 1; + } + bool HasElse() const { return (NodeCount_HasConditionVar_HasElse >> 31) & 1; } + + bool operator==(const ReflectionScopeStmt &Other) const { + return NodeId == Other.NodeId && + NodeCount_HasConditionVar_HasElse == + Other.NodeCount_HasConditionVar_HasElse; + } +}; + +// An if/switch statement holds the following. +// - if HasConditionVar(): a variable in the switch condition (unused for if) +// - BranchCount (inc. default/else, implicit->childCount) +// Each branch then has a: +// - counter (or value for switch/case (non default)) +// - if HasConditionVar(): a variable in the if +// - nodeCount (implicit) for the contents. +class ReflectionIfSwitchStmt { + + uint32_t NodeId; + + union { + uint32_t ConditionVarElseOrDefault; + struct { + uint16_t Padding; + bool ConditionVar; + bool ElseOrDefault; + }; + }; + + ReflectionIfSwitchStmt(uint32_t NodeId, bool ConditionVar, bool ElseOrDefault) + : NodeId(NodeId), Padding(0), ConditionVar(ConditionVar), + ElseOrDefault(ElseOrDefault) {} + +public: + ReflectionIfSwitchStmt() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionIfSwitchStmt &IfSwitchStmt, uint32_t NodeId, + bool HasConditionVar, bool HasElseOrDefault) { + + IfSwitchStmt = + ReflectionIfSwitchStmt(NodeId, HasConditionVar, HasElseOrDefault); + return ReflectionErrorSuccess; + } + + uint32_t GetNodeId() const { return NodeId; } + + bool HasConditionVar() const { return ConditionVar; } + bool HasElseOrDefault() const { return ElseOrDefault; } + + bool operator==(const ReflectionIfSwitchStmt &Other) const { + return NodeId == Other.NodeId && + ConditionVarElseOrDefault == Other.ConditionVarElseOrDefault; + } +}; + +class ReflectionBranchStmt { + + union { + uint64_t NodeIdConditionVarType; + struct { + uint32_t NodeId; + bool ConditionVar; + bool ComplexCase; + uint8_t ValueType; // D3D12_HLSL_ENUM_TYPE + uint8_t Padding; + }; + }; + + uint64_t Value; + + ReflectionBranchStmt(uint32_t NodeId, bool ConditionVar, bool ComplexCase, + D3D12_HLSL_ENUM_TYPE ValueType, uint64_t Value) + : NodeId(NodeId), ConditionVar(ConditionVar), ComplexCase(ComplexCase), + ValueType(ValueType), Padding(0), Value(Value) {} + +public: + ReflectionBranchStmt() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionBranchStmt &BranchStmt, uint32_t NodeId, + bool ConditionVar, bool ComplexCase, + D3D12_HLSL_ENUM_TYPE ValueType, uint64_t Value) { + + if (ValueType < D3D12_HLSL_ENUM_TYPE_UINT || + ValueType > D3D12_HLSL_ENUM_TYPE_INT16_T) + return HLSL_REFL_ERR("ValueType out of bounds"); + + BranchStmt = ReflectionBranchStmt(NodeId, ConditionVar, ComplexCase, + ValueType, Value); + return ReflectionErrorSuccess; + } + + // Only (16-bit, 32-bit or 64-bit)(signed, unsigned) + D3D12_HLSL_ENUM_TYPE GetValueType() const { + return D3D12_HLSL_ENUM_TYPE(ValueType); + } + + uint32_t GetNodeId() const { return NodeId; } + uint64_t GetValue() const { return Value; } // Manually cast this + bool HasConditionVar() const { return ConditionVar; } + bool IsComplexCase() const { return ComplexCase; } + + bool operator==(const ReflectionBranchStmt &Other) const { + return NodeIdConditionVarType == Other.NodeIdConditionVarType && + Value == Other.Value; + } +}; + +class ReflectionFunction { + + uint32_t NodeId; + uint32_t NumParametersHasReturnAndDefinition; + + ReflectionFunction(uint32_t NodeId, uint32_t NumParameters, bool HasReturn, + bool HasDefinition) + : NodeId(NodeId), + NumParametersHasReturnAndDefinition(NumParameters | + (HasReturn ? (1u << 30) : 0) | + (HasDefinition ? (1u << 31) : 0)) {} + +public: + ReflectionFunction() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionFunction &Function, uint32_t NodeId, + uint32_t NumParameters, bool HasReturn, bool HasDefinition) { + + if (NumParameters >= (1u << 30)) + return HLSL_REFL_ERR("NumParameters out of bounds"); + + Function = + ReflectionFunction(NodeId, NumParameters, HasReturn, HasDefinition); + return ReflectionErrorSuccess; + } + + uint32_t GetNodeId() const { return NodeId; } + + uint32_t GetNumParameters() const { + return NumParametersHasReturnAndDefinition << 2 >> 2; + } + + bool HasReturn() const { + return (NumParametersHasReturnAndDefinition >> 30) & 1; + } + + bool HasDefinition() const { + return (NumParametersHasReturnAndDefinition >> 31) & 1; + } + + bool operator==(const ReflectionFunction &other) const { + return NodeId == other.NodeId && + NumParametersHasReturnAndDefinition == + other.NumParametersHasReturnAndDefinition; + } +}; + +class ReflectionShaderResource { // Almost maps to D3D12_SHADER_INPUT_BIND_DESC, + // minus + // the Name (and uID replaced with NodeID) and added + // arrayIndex and better packing + + union { + struct { + uint8_t Type; // D3D_SHADER_INPUT_TYPE + uint8_t Dimension; // D3D_SRV_DIMENSION + uint8_t ReturnType; // D3D_RESOURCE_RETURN_TYPE + uint8_t uFlags; + + uint32_t BindCount; + }; + uint64_t TypeDimensionReturnTypeFlagsBindCount; + }; + + uint32_t Pad; + uint32_t NodeId; + + union { + struct { + uint32_t ArrayId; // Only if BindCount > 1 and the array is 2D+ (else -1) + uint32_t BufferId; // If cbuffer or structured buffer + }; + uint64_t ArrayIdBufferId; + }; + + ReflectionShaderResource(D3D_SHADER_INPUT_TYPE Type, uint32_t BindCount, + uint32_t uFlags, D3D_RESOURCE_RETURN_TYPE ReturnType, + D3D_SRV_DIMENSION Dimension, uint32_t NodeId, + uint32_t ArrayId, uint32_t BufferId) + : Type(Type), Dimension(Dimension), ReturnType(ReturnType), + uFlags(uFlags), BindCount(BindCount), Pad(0), NodeId(NodeId), + ArrayId(ArrayId), BufferId(BufferId) {} + +public: + ReflectionShaderResource() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionShaderResource &Register, D3D_SHADER_INPUT_TYPE Type, + uint32_t BindCount, uint32_t uFlags, + D3D_RESOURCE_RETURN_TYPE ReturnType, D3D_SRV_DIMENSION Dimension, + uint32_t NodeId, uint32_t ArrayId, uint32_t BufferId) { + + if (Type < D3D_SIT_CBUFFER || Type > D3D_SIT_UAV_FEEDBACKTEXTURE) + return HLSL_REFL_ERR("Invalid type"); + + if (ReturnType < 0 || ReturnType > D3D_RETURN_TYPE_CONTINUED) + return HLSL_REFL_ERR("Invalid return type"); + + if (Dimension < D3D_SRV_DIMENSION_UNKNOWN || + Dimension > D3D_SRV_DIMENSION_BUFFEREX) + return HLSL_REFL_ERR("Invalid srv dimension"); + + if (uFlags >> 8) + return HLSL_REFL_ERR("Invalid user flags"); + + Register = ReflectionShaderResource(Type, BindCount, uFlags, ReturnType, + Dimension, NodeId, ArrayId, BufferId); + return ReflectionErrorSuccess; + } + + D3D_RESOURCE_RETURN_TYPE GetReturnType() const { + return D3D_RESOURCE_RETURN_TYPE(ReturnType); + } + + D3D_SRV_DIMENSION GetDimension() const { + return D3D_SRV_DIMENSION(Dimension); + } + + uint32_t GetFlags() const { return uFlags; } + D3D_SHADER_INPUT_TYPE GetType() const { return D3D_SHADER_INPUT_TYPE(Type); } + uint32_t GetBindCount() const { return BindCount; } + uint32_t GetNodeId() const { return NodeId; } + uint32_t GetArrayId() const { return ArrayId; } + uint32_t GetBufferId() const { return BufferId; } + + bool operator==(const ReflectionShaderResource &other) const { + return TypeDimensionReturnTypeFlagsBindCount == + other.TypeDimensionReturnTypeFlagsBindCount && + NodeId == other.NodeId && ArrayIdBufferId == other.ArrayIdBufferId; + } +}; + +class ReflectionArray { + + uint32_t ArrayElemStart; + + ReflectionArray(uint32_t ArrayElem, uint32_t ArrayStart) + : ArrayElemStart((ArrayElem << 26) | ArrayStart) {} + +public: + ReflectionArray() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionArray &Arr, uint32_t ArrayElem, uint32_t ArrayStart) { + + if (ArrayElem <= 1 || ArrayElem > 32) + return HLSL_REFL_ERR("ArrayElem out of bounds"); + + if (ArrayStart >= (1u << 26)) + return HLSL_REFL_ERR("ArrayStart out of bounds"); + + Arr = ReflectionArray(ArrayElem, ArrayStart); + return ReflectionErrorSuccess; + } + + bool operator==(const ReflectionArray &Other) const { + return Other.ArrayElemStart == ArrayElemStart; + } + + uint32_t ArrayElem() const { return ArrayElemStart >> 26; } + uint32_t ArrayStart() const { return ArrayElemStart << 6 >> 6; } +}; + +struct ReflectionArrayOrElements { + + uint32_t ElementsOrArrayId; + + ReflectionArrayOrElements() = default; + ReflectionArrayOrElements(uint32_t arrayId, uint32_t arraySize) + : ElementsOrArrayId(arrayId != (uint32_t)-1 + ? ((1u << 31) | arrayId) + : (arraySize > 1 ? arraySize : 0)) {} + + bool IsMultiDimensionalArray() const { return ElementsOrArrayId >> 31; } + bool IsArray() const { return ElementsOrArrayId; } + bool Is1DArray() const { return IsArray() && !IsMultiDimensionalArray(); } + + uint32_t Get1DElements() const { + return IsMultiDimensionalArray() ? 0 : ElementsOrArrayId; + } + + uint32_t GetMultiDimensionalArrayId() const { + return IsMultiDimensionalArray() ? (ElementsOrArrayId << 1 >> 1) + : (uint32_t)-1; + } + + bool operator==(const ReflectionArrayOrElements &Other) const { + return Other.ElementsOrArrayId == ElementsOrArrayId; + } +}; + +class ReflectionVariableType { // Almost maps to CShaderReflectionType and + // D3D12_SHADER_TYPE_DESC, but tightly packed and + // easily serializable + + uint32_t MemberData; // 24 : 8 (start, count) + + union { + struct { + uint8_t Class; // D3D_SHADER_VARIABLE_CLASS + uint8_t Type; // D3D_SHADER_VARIABLE_TYPE + uint8_t Rows; + uint8_t Columns; + }; + uint32_t ClassTypeRowsColums; + }; + + uint32_t BaseClass; // -1 if none, otherwise a type index + uint32_t InterfaceOffsetAndCount; // 24 : 8 (start, count) + + ReflectionArrayOrElements + UnderlyingArray; // No sugar (e.g. F32x4a4 in using F32x4a4 = F32x4[4] + // becomes float4[4]) + + ReflectionVariableType(uint32_t BaseClass, + ReflectionArrayOrElements ElementsOrArrayIdUnderlying, + D3D_SHADER_VARIABLE_CLASS Class, + D3D_SHADER_VARIABLE_TYPE Type, uint8_t Rows, + uint8_t Columns, uint32_t MembersCount, + uint32_t MembersStart, uint32_t InterfaceOffset, + uint32_t InterfaceCount) + : MemberData(MembersStart | (MembersCount << 24)), Class(Class), + Type(Type), Rows(Rows), Columns(Columns), BaseClass(BaseClass), + InterfaceOffsetAndCount(InterfaceOffset | (InterfaceCount << 24)), + UnderlyingArray(ElementsOrArrayIdUnderlying) {} + +public: + bool operator==(const ReflectionVariableType &Other) const { + return Other.MemberData == MemberData && + Other.UnderlyingArray == UnderlyingArray && + ClassTypeRowsColums == Other.ClassTypeRowsColums && + BaseClass == Other.BaseClass && + InterfaceOffsetAndCount == Other.InterfaceOffsetAndCount; + } + + D3D_SHADER_VARIABLE_CLASS GetClass() const { + return D3D_SHADER_VARIABLE_CLASS(Class); + } + + D3D_SHADER_VARIABLE_TYPE GetType() const { + return D3D_SHADER_VARIABLE_TYPE(Type); + } + + uint8_t GetRows() const { return Rows; } + uint8_t GetColumns() const { return Columns; } + + uint32_t GetBaseClass() const { return BaseClass; } + + uint32_t GetMemberCount() const { return MemberData >> 24; } + uint32_t GetMemberStart() const { return MemberData << 8 >> 8; } + + ReflectionArrayOrElements GetUnderlyingArray() const { + return UnderlyingArray; + } + + uint32_t GetInterfaceCount() const { return InterfaceOffsetAndCount >> 24; } + uint32_t GetInterfaceStart() const { + return InterfaceOffsetAndCount << 8 >> 8; + } + + ReflectionVariableType() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionVariableType &Type, uint32_t BaseClass, + ReflectionArrayOrElements ElementsOrArrayIdUnderlying, + D3D_SHADER_VARIABLE_CLASS Class, + D3D_SHADER_VARIABLE_TYPE VariableType, uint8_t Rows, + uint8_t Columns, uint32_t MembersCount, uint32_t MembersStart, + uint32_t InterfaceOffset, uint32_t InterfaceCount) { + + if (Class < D3D_SVC_SCALAR || Class > D3D_SVC_INTERFACE_POINTER) + return HLSL_REFL_ERR("Invalid class"); + + if (VariableType < D3D_SVT_VOID || VariableType > D3D_SVT_UINT64) + return HLSL_REFL_ERR("Invalid type"); + + if (MembersStart >= (1u << 24)) + return HLSL_REFL_ERR("Member start out of bounds"); + + if (InterfaceOffset >= (1u << 24)) + return HLSL_REFL_ERR("Interface start out of bounds"); + + if (MembersCount >= (1u << 8)) + return HLSL_REFL_ERR("Member count out of bounds"); + + if (InterfaceCount >= (1u << 8)) + return HLSL_REFL_ERR("Interface count out of bounds"); + + Type = ReflectionVariableType( + BaseClass, ElementsOrArrayIdUnderlying, Class, VariableType, Rows, + Columns, MembersCount, MembersStart, InterfaceOffset, InterfaceCount); + return ReflectionErrorSuccess; + } +}; + +struct ReflectionVariableTypeSymbol { + + // Keep sugar (F32x4a4 = F32x4[4] stays F32x4a4, doesn't become float4[4] like + // in underlying name + array) + ReflectionArrayOrElements DisplayArray; + + // For example F32x4[4] stays F32x4 (array in DisplayArray) + uint32_t DisplayNameId; + + // F32x4[4] would turn into float4 (array in UnderlyingArray) + uint32_t UnderlyingNameId; + + bool operator==(const ReflectionVariableTypeSymbol &Other) const { + return Other.DisplayArray == DisplayArray && + DisplayNameId == Other.DisplayNameId && + UnderlyingNameId == Other.UnderlyingNameId; + } + + ReflectionVariableTypeSymbol() = default; + ReflectionVariableTypeSymbol( + ReflectionArrayOrElements ElementsOrArrayIdDisplay, + uint32_t DisplayNameId, uint32_t UnderlyingNameId) + : DisplayArray(ElementsOrArrayIdDisplay), DisplayNameId(DisplayNameId), + UnderlyingNameId(UnderlyingNameId) {} +}; + +struct ReflectionShaderBuffer { // Almost maps to + // CShaderReflectionConstantBuffer and + // D3D12_SHADER_BUFFER_DESC + + D3D_CBUFFER_TYPE Type; + uint32_t NodeId; + + bool operator==(const ReflectionShaderBuffer &other) const { + return Type == other.Type && NodeId == other.NodeId; + } +}; + +class ReflectionAnnotation { + + uint32_t StringNonDebugAndIsBuiltin; + + ReflectionAnnotation(uint32_t StringNonDebug, bool IsBuiltin) + : StringNonDebugAndIsBuiltin(StringNonDebug | + (IsBuiltin ? (1u << 31) : 0)) {} + +public: + ReflectionAnnotation() = default; + + [[nodiscard]] static ReflectionError + Initialize(ReflectionAnnotation &Annotation, uint32_t StringNonDebug, + bool IsBuiltin) { + + if (StringNonDebug >= (1u << 31)) + return HLSL_REFL_ERR("String non debug out of bounds"); + + Annotation = ReflectionAnnotation(StringNonDebug, IsBuiltin); + return ReflectionErrorSuccess; + } + + bool operator==(const ReflectionAnnotation &other) const { + return StringNonDebugAndIsBuiltin == other.StringNonDebugAndIsBuiltin; + } + + bool GetIsBuiltin() const { return StringNonDebugAndIsBuiltin >> 31; } + + uint32_t GetStringNonDebug() const { + return StringNonDebugAndIsBuiltin << 1 >> 1; + } +}; + +// Note: Regarding nodes, node 0 is the root node (global scope) +// If a node is a fwd declare you should inspect the fwd node id. +// If a node isn't a fwd declare but has a backward id, the node should be +// ignored during traversal. (That node can be defined in a different +// namespace or type while it's declared elsewhere). +struct ReflectionData { + + D3D12_HLSL_REFLECTION_FEATURE Features{}; + + std::vector Strings; + std::unordered_map StringsToId; + + std::vector StringsNonDebug; + std::unordered_map StringsToIdNonDebug; + + std::vector Sources; + std::unordered_map StringToSourceId; + + std::vector Nodes; // 0 = Root node (global scope) + + std::vector Registers; + std::vector Functions; + + std::vector Enums; + std::vector EnumValues; + + std::vector Parameters; + std::vector Annotations; + + std::vector Arrays; + std::vector ArraySizes; + + std::vector MemberTypeIds; + std::vector TypeList; + std::vector Types; + std::vector Buffers; + + std::vector Statements; + std::vector IfSwitchStatements; + std::vector BranchStatements; + + // Can be stripped if !(D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + + std::vector NodeSymbols; + std::vector MemberNameIds; + std::vector TypeSymbols; + + // Only generated if deserialized with MakeNameLookupTable or + // GenerateNameLookupTable is called (and if symbols aren't stripped) + + std::unordered_map FullyResolvedToNodeId; + std::vector NodeIdToFullyResolved; + std::unordered_map FullyResolvedToMemberId; + + [[nodiscard]] ReflectionError + RegisterString(uint32_t &StringId, const std::string &Name, bool IsNonDebug); + + [[nodiscard]] ReflectionError + PushArray(uint32_t &ArrayId, uint32_t ArraySizeFlat, + const std::vector &ArraySize); + + [[nodiscard]] ReflectionError + RegisterTypeList(const std::vector &TypeIds, uint32_t &Offset, + uint8_t &Len); + + static D3D_CBUFFER_TYPE GetBufferType(uint8_t Type); + + void Dump(std::vector &Bytes) const; + std::string ToJson(bool HideFileInfo = false, + bool IsHumanFriendly = true) const; + + void StripSymbols(); + bool GenerateNameLookupTable(); + + ReflectionData() = default; + [[nodiscard]] ReflectionError Deserialize(const std::vector &Bytes, + bool MakeNameLookupTable); + + bool IsSameNonDebug(const ReflectionData &Other) const { + return StringsNonDebug == Other.StringsNonDebug && Nodes == Other.Nodes && + Registers == Other.Registers && Functions == Other.Functions && + Enums == Other.Enums && EnumValues == Other.EnumValues && + Annotations == Other.Annotations && Arrays == Other.Arrays && + ArraySizes == Other.ArraySizes && + MemberTypeIds == Other.MemberTypeIds && TypeList == Other.TypeList && + Types == Other.Types && Buffers == Other.Buffers && + Parameters == Other.Parameters && Statements == Other.Statements && + IfSwitchStatements == Other.IfSwitchStatements && + BranchStatements == Other.BranchStatements; + } + + bool operator==(const ReflectionData &Other) const { + return IsSameNonDebug(Other) && Strings == Other.Strings && + Sources == Other.Sources && NodeSymbols == Other.NodeSymbols && + MemberNameIds == Other.MemberNameIds && + TypeSymbols == Other.TypeSymbols; + } +}; + +} // namespace hlsl + +#pragma warning(default : 4201) diff --git a/include/dxc/Support/ErrorCodes.h b/include/dxc/Support/ErrorCodes.h index 5239c8118c..d49ab29210 100644 --- a/include/dxc/Support/ErrorCodes.h +++ b/include/dxc/Support/ErrorCodes.h @@ -157,4 +157,5 @@ // 0X80AA001F - DXIL container Program Version mismatches Dxil module shader // model #define DXC_E_INCORRECT_PROGRAM_VERSION \ - DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR, FACILITY_DXC, (0x001F)) \ No newline at end of file + DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR, FACILITY_DXC, (0x001F)) + \ No newline at end of file diff --git a/include/dxc/Support/HLSLOptions.h b/include/dxc/Support/HLSLOptions.h index 010bb6f572..f253830b62 100644 --- a/include/dxc/Support/HLSLOptions.h +++ b/include/dxc/Support/HLSLOptions.h @@ -52,6 +52,7 @@ enum HlslFlags { CoreOption = (1 << 15), ISenseOption = (1 << 16), RewriteOption = (1 << 17), + ReflectOption = (1 << 18) }; enum ID { @@ -79,6 +80,9 @@ static const unsigned DxcFlags = /// Flags for dxr.exe command-line tool. static const unsigned DxrFlags = HlslFlags::RewriteOption | HlslFlags::DriverOption; +/// Flags for dxreflector.exe command-line tool. +static const unsigned DxreflectorFlags = + HlslFlags::ReflectOption | HlslFlags::DriverOption; /// Flags for IDxcIntelliSense APIs. static const unsigned ISenseFlags = HlslFlags::CoreOption | HlslFlags::ISenseOption; @@ -114,6 +118,17 @@ struct RewriterOpts { bool DeclGlobalCB = false; // OPT_rw_decl_global_cb }; +struct ReflectOpts { + bool Basics = false; // OPT_reflect_basics + bool Functions = false; // OPT_reflect_functions + bool Namespaces = false; // OPT_reflect_namespaces + bool UserTypes = false; // OPT_reflect_user_types + bool Scopes = false; // OPT_reflect_scopes + bool DisableSymbols = false; // OPT_reflect_disable_symbols + bool ShowFileInfo = false; // OPT_reflect_show_file_info + bool ShowRawData = false; // OPT_reflect_show_raw_data +}; + /// Use this class to capture all options. class DxcOpts { public: @@ -246,6 +261,9 @@ class DxcOpts { // Rewriter Options RewriterOpts RWOpt; + // Reflector Options + ReflectOpts ReflOpt; + std::vector Warnings; bool IsRootSignatureProfile() const; diff --git a/include/dxc/Support/HLSLOptions.td b/include/dxc/Support/HLSLOptions.td index cd7dfb2f0c..49aab4bce5 100644 --- a/include/dxc/Support/HLSLOptions.td +++ b/include/dxc/Support/HLSLOptions.td @@ -29,6 +29,9 @@ def ISenseOption : OptionFlag; // RewriteOption - This is considered a "rewriter" HLSL option. def RewriteOption : OptionFlag; +// ReflectOption - This is considered a "reflector" HLSL option. +def ReflectOption : OptionFlag; + ////////////////////////////////////////////////////////////////////////////// // Groups @@ -70,6 +73,7 @@ def hlsloptz_Group : OptionGroup<"HLSL Optimization">, HelpText<"Optimization Op def hlslutil_Group : OptionGroup<"HLSL Utility">, HelpText<"Utility Options">; def hlslcore_Group : OptionGroup<"HLSL Core">, HelpText<"Common Options">; def hlslrewrite_Group : OptionGroup<"HLSL Rewriter">, HelpText<"Rewriter Options">; +def hlslreflect_Group : OptionGroup<"HLSL Reflector">, HelpText<"Reflector Options">; def spirv_Group : OptionGroup<"SPIR-V CodeGen">, HelpText<"SPIR-V CodeGen Options">; // SPIRV Change @@ -86,11 +90,11 @@ def spirv_Group : OptionGroup<"SPIR-V CodeGen">, HelpText<"SPIR-V CodeGen Option // The general approach is to include only things that are in use, in the // same order as in Options.td. -def D : JoinedOrSeparate<["-", "/"], "D">, Group, Flags<[CoreOption, RewriteOption]>, +def D : JoinedOrSeparate<["-", "/"], "D">, Group, Flags<[CoreOption, RewriteOption, ReflectOption]>, HelpText<"Define macro">; def H : Flag<["-"], "H">, Flags<[CoreOption]>, Group, HelpText<"Show header includes and nesting depth">; -def I : JoinedOrSeparate<["-", "/"], "I">, Group, Flags<[CoreOption, RewriteOption]>, +def I : JoinedOrSeparate<["-", "/"], "I">, Group, Flags<[CoreOption, RewriteOption, ReflectOption]>, HelpText<"Add directory to include search path">; def O0 : Flag<["-", "/"], "O0">, Group, Flags<[CoreOption]>, HelpText<"Optimization Level 0">; @@ -302,13 +306,13 @@ def pack_optimized : Flag<["-", "/"], "pack-optimized">, Group, HelpText<"Optimize signature packing assuming identical signature provided for each connecting stage">; def pack_optimized_ : Flag<["-", "/"], "pack_optimized">, Group, Flags<[CoreOption, HelpHidden]>, HelpText<"Optimize signature packing assuming identical signature provided for each connecting stage">; -def hlsl_version : Separate<["-", "/"], "HV">, Group, Flags<[CoreOption, RewriteOption]>, +def hlsl_version : Separate<["-", "/"], "HV">, Group, Flags<[CoreOption, RewriteOption, ReflectOption]>, HelpText<"HLSL version (2016, 2017, 2018, 2021). Default is 2021">; -def no_warnings : Flag<["-", "/"], "no-warnings">, Group, Flags<[CoreOption, RewriteOption]>, +def no_warnings : Flag<["-", "/"], "no-warnings">, Group, Flags<[CoreOption, RewriteOption, ReflectOption]>, HelpText<"Suppress warnings">; def rootsig_define : Separate<["-", "/"], "rootsig-define">, Group, Flags<[CoreOption]>, HelpText<"Read root signature from a #define">; -def enable_16bit_types: Flag<["-", "/"], "enable-16bit-types">, Flags<[CoreOption, RewriteOption, DriverOption]>, Group, +def enable_16bit_types: Flag<["-", "/"], "enable-16bit-types">, Flags<[CoreOption, RewriteOption, ReflectOption, DriverOption]>, Group, HelpText<"Enable 16bit types and disable min precision types. Available in HLSL 2018 and shader model 6.2">; def ignore_line_directives : Flag<["-", "/"], "ignore-line-directives">, HelpText<"Ignore line directives">, Flags<[CoreOption]>, Group; def auto_binding_space : Separate<["-", "/"], "auto-binding-space">, Group, Flags<[CoreOption]>, @@ -321,7 +325,7 @@ def default_linkage : Separate<["-", "/"], "default-linkage">, Group; def precise_output : Separate<["-", "/"], "precise-output">, Group, Flags<[CoreOption, HelpHidden]>, HelpText<"Mark output semantic as precise">; -def encoding : Separate<["-", "/"], "encoding">, Group, Flags<[CoreOption, RewriteOption, DriverOption]>, +def encoding : Separate<["-", "/"], "encoding">, Group, Flags<[CoreOption, RewriteOption, ReflectOption, DriverOption]>, HelpText<"Set default encoding for source inputs and text outputs (utf8|utf16(win)|utf32(*nix)|wide) default=utf8">; def validator_version : Separate<["-", "/"], "validator-version">, Group, Flags<[CoreOption, HelpHidden]>, HelpText<"Override validator version for module. Format: ; Default: DXIL.dll version or current internal version.">; @@ -345,9 +349,9 @@ def enable_lifetime_markers : Flag<["-", "/"], "enable-lifetime-markers">, Group HelpText<"Enable generation of lifetime markers">; def disable_lifetime_markers : Flag<["-", "/"], "disable-lifetime-markers">, Group, Flags<[CoreOption, HelpHidden]>, HelpText<"Disable generation of lifetime markers where they would be otherwise (6.6+)">; -def enable_payload_qualifiers : Flag<["-", "/"], "enable-payload-qualifiers">, Group, Flags<[CoreOption, RewriteOption, DriverOption]>, +def enable_payload_qualifiers : Flag<["-", "/"], "enable-payload-qualifiers">, Group, Flags<[CoreOption, RewriteOption, ReflectOption, DriverOption]>, HelpText<"Enables support for payload access qualifiers for raytracing payloads in SM 6.6.">; -def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group, Flags<[CoreOption, RewriteOption, DriverOption]>, +def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group, Flags<[CoreOption, RewriteOption, ReflectOption, DriverOption]>, HelpText<"Disables support for payload access qualifiers for raytracing payloads in SM 6.7.">; def disable_exception_handling : Flag<["-", "/"], "disable-exception-handling">, Group, Flags<[DriverOption, HelpHidden]>, HelpText<"Disable dxc handling of exceptions">; @@ -448,12 +452,12 @@ def fvk_bind_counter_heap : MultiArg<["-"], "fvk-bind-counter-heap", 2>, MetaVar ////////////////////////////////////////////////////////////////////////////// // fxc-based flags that don't match those previously defined. -def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption]>, Group, MetaVarName<"">, +def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption, ReflectOption]>, Group, MetaVarName<"">, /* hctdb_instrhelp.get_target_profiles()*/ // VALRULE-TEXT:BEGIN HelpText<"Set target profile. \n\t: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7, ps_6_8, ps_6_9, ps_6_10, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, vs_6_7, vs_6_8, vs_6_9, vs_6_10, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, gs_6_7, gs_6_8, gs_6_9, gs_6_10, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5, hs_6_6, hs_6_7, hs_6_8, hs_6_9, hs_6_10, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5, ds_6_6, ds_6_7, ds_6_8, ds_6_9, ds_6_10, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, cs_6_7, cs_6_8, cs_6_9, cs_6_10, \n\t\t lib_6_1, lib_6_2, lib_6_3, lib_6_4, lib_6_5, lib_6_6, lib_6_7, lib_6_8, lib_6_9, lib_6_10, \n\t\t ms_6_5, ms_6_6, ms_6_7, ms_6_8, ms_6_9, ms_6_10, \n\t\t as_6_5, as_6_6, as_6_7, as_6_8, as_6_9, as_6_10, \n\t\t ">; // VALRULE-TEXT:END -def entrypoint : JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption, RewriteOption]>, Group, +def entrypoint : JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption, RewriteOption, ReflectOption]>, Group, HelpText<"Entry point name">; // /I - already defined above def _vi : Flag<["-", "/"], "Vi">, Alias, Flags<[CoreOption]>, Group, @@ -489,7 +493,7 @@ def Gis : Flag<["-", "/"], "Gis">, HelpText<"Force IEEE strictness">, Flags<[Cor def denorm : JoinedOrSeparate<["-", "/"], "denorm">, HelpText<"select denormal value options (any, preserve, ftz). any is the default.">, Flags<[CoreOption]>, Group; -def Fo : JoinedOrSeparate<["-", "/"], "Fo">, MetaVarName<"">, HelpText<"Output object file">, Flags<[CoreOption, RewriteOption, DriverOption]>, Group; +def Fo : JoinedOrSeparate<["-", "/"], "Fo">, MetaVarName<"">, HelpText<"Output object file">, Flags<[CoreOption, RewriteOption, ReflectOption, DriverOption]>, Group; // def Fl : JoinedOrSeparate<["-", "/"], "Fl">, MetaVarName<"">, HelpText<"Output a library">; def Fc : JoinedOrSeparate<["-", "/"], "Fc">, MetaVarName<"">, HelpText<"Output assembly code listing file">, Flags<[DriverOption]>, Group; //def Fx : JoinedOrSeparate<["-", "/"], "Fx">, MetaVarName<"">, HelpText<"Output assembly code and hex listing file">; @@ -576,6 +580,28 @@ def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, Flags<[DriverOption def nologo : Flag<["-", "/"], "nologo">, Group, Flags<[DriverOption, HelpHidden]>, HelpText<"Suppress copyright message">; +////////////////////////////////////////////////////////////////////////////// +// Reflector Options + +def reflect_basics : Flag<["-", "/"], "reflect-basics">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL (registers, constants and annotations).">; +def reflect_functions : Flag<["-", "/"], "reflect-functions">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL functions.">; +def reflect_namespaces : Flag<["-", "/"], "reflect-namespaces">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL nodes in namespaces rather than only the global namespace.">; +def reflect_user_types : Flag<["-", "/"], "reflect-user-types">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL user types (typedef, using, struct, enum).">; +def reflect_scopes : Flag<["-", "/"], "reflect-scopes">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL scopes (variables and structs defined in functions).">; +def reflect_disable_symbols : Flag<["-", "/"], "reflect-disable-symbols">, Group, Flags<[ReflectOption]>, + HelpText<"Reflect HLSL disable symbols.">; + +def reflect_show_file_info : Flag<["-", "/"], "reflect-show-file-info">, Group, Flags<[ReflectOption]>, + HelpText<"Show file symbol info in the reflection output json.">; + +def reflect_show_raw_data : Flag<["-", "/"], "reflect-show-raw-data">, Group, Flags<[ReflectOption]>, + HelpText<"Show raw data without prettifying in the reflection output json.">; + ////////////////////////////////////////////////////////////////////////////// // Rewriter Options diff --git a/include/dxc/Test/DxcTestUtils.h b/include/dxc/Test/DxcTestUtils.h index 292206d6de..e59303da75 100644 --- a/include/dxc/Test/DxcTestUtils.h +++ b/include/dxc/Test/DxcTestUtils.h @@ -130,6 +130,8 @@ class FileRunCommandPart { LPCWSTR dumpName = nullptr); FileRunCommandResult RunDxc(dxc::DllLoader &DllSupport, const FileRunCommandResult *Prior); + FileRunCommandResult RunDxReflector(dxc::DllLoader &DllSupport, + const FileRunCommandResult *Prior); FileRunCommandResult RunDxv(dxc::DllLoader &DllSupport, const FileRunCommandResult *Prior); FileRunCommandResult RunOpt(dxc::DllLoader &DllSupport, diff --git a/include/dxc/WinAdapter.h b/include/dxc/WinAdapter.h index d02ad1ac38..908408f558 100644 --- a/include/dxc/WinAdapter.h +++ b/include/dxc/WinAdapter.h @@ -321,6 +321,7 @@ typedef DWORD *LPDWORD; typedef uint32_t UINT32; typedef uint64_t UINT64; +typedef int64_t INT64; typedef signed char INT8, *PINT8; typedef signed int INT32, *PINT32; diff --git a/include/dxc/dxcreflect.h b/include/dxc/dxcreflect.h new file mode 100644 index 0000000000..958caff857 --- /dev/null +++ b/include/dxc/dxcreflect.h @@ -0,0 +1,387 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxcreflect.h // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Provides declarations for the DirectX Compiler reflection components. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __DXC_REFLECT__ +#define __DXC_REFLECT__ + +#ifndef _WIN32 +#include "./WinAdapter.h" +// need to disable this as it is voilated by this header +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +// Need to instruct non-windows compilers on what an interface is +#define interface struct +#endif + +#include "d3d12shader.h" +#include "./dxcapi.h" + +#ifdef _MSC_VER +#define CLSID_SCOPE __declspec(selectany) extern +#else +#define CLSID_SCOPE +#endif + +// Expose HLSL reflection before DXIL/SPIRV generation. +// (Ran after the preprocessed HLSL is obtained). +// This is useful to avoid custom parsers from reinventing the wheel. +// You could use it to find all entrypoints even if [shader("")] isn't used, +// Find struct/enum information, find out about optimized out registers, etc. +// This is a limited AST that doesn't include anything beyond symbols +// (so no details about instructions). + +enum D3D12_HLSL_REFLECTION_FEATURE { + + D3D12_HLSL_REFLECTION_FEATURE_NONE = 0, + + // Includes cbuffer and registers only + D3D12_HLSL_REFLECTION_FEATURE_BASICS = 1 << 0, + + D3D12_HLSL_REFLECTION_FEATURE_FUNCTIONS = 1 << 1, + D3D12_HLSL_REFLECTION_FEATURE_NAMESPACES = 1 << 2, + + // Include user types (struct, enum, typedef, etc.) + D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES = 1 << 3, + + // Variables, structs, functions defined in functions + D3D12_HLSL_REFLECTION_FEATURE_SCOPES = 1 << 4, + + // Symbol info (stripping this will remove names and file location info) + D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO = 1 << 16, + + D3D12_HLSL_REFLECTION_FEATURE_ALL = + D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO - 1 +}; + +inline D3D12_HLSL_REFLECTION_FEATURE & +operator|=(D3D12_HLSL_REFLECTION_FEATURE &a, D3D12_HLSL_REFLECTION_FEATURE b) { + return a = (D3D12_HLSL_REFLECTION_FEATURE)(uint32_t(a) | uint32_t(b)); +} + +inline D3D12_HLSL_REFLECTION_FEATURE & +operator&=(D3D12_HLSL_REFLECTION_FEATURE &a, D3D12_HLSL_REFLECTION_FEATURE b) { + return a = (D3D12_HLSL_REFLECTION_FEATURE)(uint32_t(a) & uint32_t(b)); +} + +inline D3D12_HLSL_REFLECTION_FEATURE +operator~(D3D12_HLSL_REFLECTION_FEATURE a) { + return (D3D12_HLSL_REFLECTION_FEATURE)~uint32_t(a); +} + +struct D3D12_HLSL_REFLECTION_DESC { + D3D12_HLSL_REFLECTION_FEATURE Features; + UINT BufferCount; + UINT ResourceCount; + UINT FunctionCount; + UINT EnumCount; + UINT NodeCount; + UINT TypeCount; + UINT StructCount; + UINT UnionCount; + UINT InterfaceCount; +}; + +struct D3D12_HLSL_FUNCTION_DESC { + LPCSTR Name; // Function name + UINT FunctionParameterCount; // Number of logical parameters in the function + // signature (not including return) + BOOL HasReturn; // TRUE, if function returns a value, false - it is a + // subroutine + UINT NodeId; +}; + +enum D3D12_HLSL_ENUM_TYPE { + + D3D12_HLSL_ENUM_TYPE_UINT, + D3D12_HLSL_ENUM_TYPE_INT, + D3D12_HLSL_ENUM_TYPE_UINT64_T, + D3D12_HLSL_ENUM_TYPE_INT64_T, + D3D12_HLSL_ENUM_TYPE_UINT16_T, + D3D12_HLSL_ENUM_TYPE_INT16_T, + + D3D12_HLSL_ENUM_TYPE_START = D3D12_HLSL_ENUM_TYPE_UINT, + D3D12_HLSL_ENUM_TYPE_END = D3D12_HLSL_ENUM_TYPE_INT16_T +}; + +struct D3D12_HLSL_ENUM_DESC { + LPCSTR Name; + UINT ValueCount; + D3D12_HLSL_ENUM_TYPE Type; + UINT NodeId; +}; + +struct D3D12_HLSL_ENUM_VALUE { + LPCSTR Name; + INT64 Value; + UINT NodeId; +}; + +struct D3D12_HLSL_ANNOTATION { + LPCSTR Name; + BOOL IsBuiltin; +}; + +enum D3D12_HLSL_NODE_TYPE { + + D3D12_HLSL_NODE_TYPE_REGISTER, + D3D12_HLSL_NODE_TYPE_FUNCTION, + D3D12_HLSL_NODE_TYPE_ENUM, + D3D12_HLSL_NODE_TYPE_ENUM_VALUE, + D3D12_HLSL_NODE_TYPE_NAMESPACE, + + D3D12_HLSL_NODE_TYPE_VARIABLE, // localId points to the type + D3D12_HLSL_NODE_TYPE_TYPEDEF, // ^ + + D3D12_HLSL_NODE_TYPE_STRUCT, // has Variables as member like buffers do, + // localId is the typeId (if not fwd decl) + D3D12_HLSL_NODE_TYPE_UNION, // ^ + + D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE, + + D3D12_HLSL_NODE_TYPE_INTERFACE, + D3D12_HLSL_NODE_TYPE_PARAMETER, + + // Control flow (Stmts or SwitchIfStmt), for full inspection of what variables + // exist where and scopes + + D3D12_HLSL_NODE_TYPE_IF_ROOT, + D3D12_HLSL_NODE_TYPE_SCOPE, + D3D12_HLSL_NODE_TYPE_DO, + D3D12_HLSL_NODE_TYPE_SWITCH, + D3D12_HLSL_NODE_TYPE_WHILE, + D3D12_HLSL_NODE_TYPE_FOR, + + D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE, + + // All branches (BranchStmt) + + D3D12_HLSL_NODE_TYPE_CASE, + D3D12_HLSL_NODE_TYPE_DEFAULT, + + D3D12_HLSL_NODE_TYPE_USING, + + D3D12_HLSL_NODE_TYPE_IF_FIRST, + D3D12_HLSL_NODE_TYPE_ELSE_IF, + D3D12_HLSL_NODE_TYPE_ELSE, + + D3D12_HLSL_NODE_TYPE_RESERVED = + 1 << 7, // Highest bit; reserved as an indicator for fwd declarations + + D3D12_HLSL_NODE_TYPE_START = D3D12_HLSL_NODE_TYPE_REGISTER, + + // Don't forget to properly update NodeTypeToString + D3D12_HLSL_NODE_TYPE_END = D3D12_HLSL_NODE_TYPE_ELSE, + D3D12_HLSL_NODE_TYPE_INVALID +}; + +struct D3D12_HLSL_NODE { + LPCSTR Name; + LPCSTR Semantic; + D3D12_HLSL_NODE_TYPE Type; + UINT LocalId; + UINT ChildCount; + UINT Parent; + UINT AnnotationCount; + UINT FwdBckDeclareNode; // If UINT_MAX has no forward / backward declare + BOOL IsFwdDeclare; + D3D_INTERPOLATION_MODE InterpolationMode; +}; + +struct D3D12_HLSL_NODE_SYMBOL { + LPCSTR FileName; + UINT LineId; + UINT LineCount; + UINT ColumnStart; + UINT ColumnEnd; +}; + +struct D3D12_ARRAY_DESC { + UINT ArrayDims; + UINT ArrayLengths[32]; // SPV_REFLECT_MAX_ARRAY_DIMS +}; + +struct D3D12_SHADER_INPUT_BIND_DESC1 { + D3D12_SHADER_INPUT_BIND_DESC Desc; + D3D12_ARRAY_DESC ArrayInfo; +}; + +typedef struct _D3D12_SHADER_TYPE_DESC1 { + D3D12_SHADER_TYPE_DESC Desc; + LPCSTR DisplayName; // Display name (not underlying name) + UINT DisplayElements; +} D3D12_SHADER_TYPE_DESC1; + +DECLARE_INTERFACE_(ID3D12ShaderReflectionType1, ID3D12ShaderReflectionType) { + STDMETHOD(GetDesc1)(THIS_ _Out_ D3D12_SHADER_TYPE_DESC1 * pDesc) PURE; + STDMETHOD(GetArrayDesc)(THIS_ _Out_ D3D12_ARRAY_DESC * pArrayDesc) PURE; + STDMETHOD(GetDisplayArrayDesc) + (THIS_ _Out_ D3D12_ARRAY_DESC * pArrayDesc) PURE; +}; + +typedef interface IHLSLReflectionData IHLSLReflectionData; + +// {7016F834-AE85-4C86-A473-8C2C981DD370} +interface DECLSPEC_UUID("7016f834-ae85-4c86-a473-8c2c981dd370") + IHLSLReflectionData; +DEFINE_GUID(IID_IHLSLReflectionData, 0x7016f834, 0xae85, 0x4c86, 0xa4, 0x73, + 0x8c, 0x2c, 0x98, 0x1d, 0xd3, 0x70); + +#undef INTERFACE +#define INTERFACE IHLSLReflectionData + +DECLARE_INTERFACE_(IHLSLReflectionData, IUnknown) { + + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_HLSL_REFLECTION_DESC * pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex) + (THIS_ _In_ UINT Index) PURE; + + // The D3D12_SHADER_INPUT_BIND_DESC permits providing invalid Space and + // BindPoint. In the future, implementations could decide to return this + // depending on the backend. But since this is HLSL frontend reflection, we + // don't know the bindings on the backend. + + STDMETHOD(GetResourceBindingDesc) + (THIS_ _In_ UINT ResourceIndex, _Out_ D3D12_SHADER_INPUT_BIND_DESC1 * pDesc) + PURE; + + STDMETHOD(GetFunctionDesc) + (THIS_ _In_ UINT FunctionIndex, THIS_ _Out_ D3D12_HLSL_FUNCTION_DESC * pDesc) + PURE; + + // Use D3D_RETURN_PARAMETER_INDEX to get description of the return value. + STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter) + (THIS_ _In_ UINT FunctionIndex, THIS_ _In_ INT ParameterIndex) PURE; + + STDMETHOD(GetStructTypeByIndex) + (THIS_ _In_ UINT Index, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetUnionTypeByIndex) + (THIS_ _In_ UINT Index, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetInterfaceTypeByIndex) + (THIS_ _In_ UINT Index, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetTypeByIndex) + (THIS_ _In_ UINT Index, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetEnumDesc) + (THIS_ _In_ UINT EnumIndex, _Out_ D3D12_HLSL_ENUM_DESC * pDesc) PURE; + + STDMETHOD(GetEnumValueByIndex) + (THIS_ _In_ UINT EnumIndex, _In_ UINT ValueIndex, + _Out_ D3D12_HLSL_ENUM_VALUE * pValueDesc) PURE; + + STDMETHOD(GetAnnotationByIndex) + (THIS_ _In_ UINT NodeId, _In_ UINT Index, + _Out_ D3D12_HLSL_ANNOTATION * pAnnotation) PURE; + + STDMETHOD(GetNodeDesc) + (THIS_ _In_ UINT NodeId, _Out_ D3D12_HLSL_NODE * pDesc) PURE; + + STDMETHOD(GetChildNode) + (THIS_ _In_ UINT NodeId, THIS_ _In_ UINT ChildId, _Out_ UINT * pChildNodeId) + PURE; + + STDMETHOD(GetChildDesc) + (THIS_ _In_ UINT NodeId, THIS_ _In_ UINT ChildId, + _Out_ D3D12_HLSL_NODE * pDesc) PURE; + + // Only available if symbols aren't stripped + + STDMETHOD(GetNodeSymbolDesc) + (THIS_ _In_ UINT NodeId, _Out_ D3D12_HLSL_NODE_SYMBOL * pSymbol) PURE; + + // Name helpers + + STDMETHOD(GetNodeByName) + (THIS_ _In_ LPCSTR Name, _Out_ UINT * pNodeId) PURE; + + STDMETHOD(GetNodeSymbolDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_NODE_SYMBOL * pSymbol) PURE; + + STDMETHOD(GetNodeDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_NODE * pDesc) PURE; + + STDMETHOD(GetAnnotationByIndexAndName) + (THIS_ _In_ LPCSTR Name, _In_ UINT Index, + _Out_ D3D12_HLSL_ANNOTATION * pAnnotation) PURE; + + STDMETHOD(GetEnumDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_ENUM_DESC * pDesc) PURE; + + STDMETHOD(GetEnumValueByNameAndIndex) + (THIS_ _In_ LPCSTR Name, _In_ UINT ValueIndex, + _Out_ D3D12_HLSL_ENUM_VALUE * pValueDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName) + (THIS_ _In_ LPCSTR Name) PURE; + + STDMETHOD(GetFunctionDescByName) + (THIS_ _In_ LPCSTR Name, THIS_ _Out_ D3D12_HLSL_FUNCTION_DESC * pDesc) PURE; + + STDMETHOD(GetResourceBindingDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_SHADER_INPUT_BIND_DESC1 * pDesc) PURE; + + STDMETHOD(GetStructTypeByName) + (THIS_ _In_ LPCSTR Name, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetUnionTypeByName) + (THIS_ _In_ LPCSTR Name, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; + + STDMETHOD(GetInterfaceTypeByName) + (THIS_ _In_ LPCSTR Name, _Outptr_ ID3D12ShaderReflectionType * *ppType) PURE; +}; + +struct ReflectorFormatSettings { + bool IsHumanReadable; + bool PrintFileInfo; +}; + +#undef INTERFACE + +CLSID_SCOPE const CLSID + CLSID_DxcReflector = {/* ba5a8d8e-bf71-435a-977f-1677d7bcccc1 */ + 0xba5a8d8e, + 0xbf71, + 0x435a, + {0x16, 0x77, 0xd7, 0xbc, 0xcc, 0xc1}}; + +CROSS_PLATFORM_UUIDOF(IHLSLReflector, "ba5a8d8e-bf71-435a-977f-1677d7bcccc1") +struct IHLSLReflector : public IUnknown { + + virtual HRESULT STDMETHODCALLTYPE FromSource( + IDxcBlobEncoding *pSource, + // Optional file name for pSource. Used in errors and include handlers. + LPCWSTR pSourceName, + // Compiler arguments + LPCWSTR *pArguments, UINT32 argCount, + // Defines + DxcDefine *pDefines, UINT32 defineCount, + // user-provided interface to handle #include directives (optional) + IDxcIncludeHandler *pIncludeHandler, IDxcResult **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE + FromBlob(IDxcBlob *data, IHLSLReflectionData **ppReflection) = 0; + + virtual HRESULT STDMETHODCALLTYPE ToBlob(IHLSLReflectionData *reflection, + IDxcBlob **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE ToString(IHLSLReflectionData *reflection, + ReflectorFormatSettings Settings, + IDxcBlobEncoding **ppResult) = 0; +}; + +#endif diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 0c9330b1d1..d174720f0b 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -991,7 +991,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, // XXX TODO: Sort this out, since it's required for new API, but a separate // argument for old APIs. if ((flagsToInclude & hlsl::options::DriverOption) && - !(flagsToInclude & hlsl::options::RewriteOption) && + !(flagsToInclude & + (hlsl::options::RewriteOption | hlsl::options::ReflectOption)) && opts.TargetProfile.empty() && !opts.DumpBin && opts.Preprocess.empty() && !opts.RecompileFromBinary) { // Target profile is required in arguments only for drivers when compiling; @@ -1374,6 +1375,23 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, } } + if (flagsToInclude & hlsl::options::ReflectOption) { + opts.ReflOpt.Basics = Args.hasFlag(OPT_reflect_basics, OPT_INVALID, false); + opts.ReflOpt.Functions = + Args.hasFlag(OPT_reflect_functions, OPT_INVALID, false); + opts.ReflOpt.Namespaces = + Args.hasFlag(OPT_reflect_namespaces, OPT_INVALID, false); + opts.ReflOpt.UserTypes = + Args.hasFlag(OPT_reflect_user_types, OPT_INVALID, false); + opts.ReflOpt.Scopes = Args.hasFlag(OPT_reflect_scopes, OPT_INVALID, false); + opts.ReflOpt.DisableSymbols = + Args.hasFlag(OPT_reflect_disable_symbols, OPT_INVALID, false); + opts.ReflOpt.ShowFileInfo = + Args.hasFlag(OPT_reflect_show_file_info, OPT_INVALID, false); + opts.ReflOpt.ShowRawData = + Args.hasFlag(OPT_reflect_show_raw_data, OPT_INVALID, false); + } + opts.Args = std::move(Args); return 0; } diff --git a/tools/clang/include/clang/Basic/LangOptions.h b/tools/clang/include/clang/Basic/LangOptions.h index 433b767c8d..bb8a895e22 100644 --- a/tools/clang/include/clang/Basic/LangOptions.h +++ b/tools/clang/include/clang/Basic/LangOptions.h @@ -164,6 +164,7 @@ class LangOptions : public LangOptionsBase { bool EnablePayloadAccessQualifiers = false; bool DumpImplicitTopLevelDecls = true; bool ExportShadersOnly = false; + bool PreserveUnknownAnnotations = false; hlsl::DXIL::DefaultLinkage DefaultLinkage = hlsl::DXIL::DefaultLinkage::Default; /// Whether use row major as default matrix major. diff --git a/tools/clang/lib/Sema/SemaDeclAttr.cpp b/tools/clang/lib/Sema/SemaDeclAttr.cpp index 085874a0ed..1ffbfe149e 100644 --- a/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -4585,6 +4585,58 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, // though they were unknown attributes. if (Attr.getKind() == AttributeList::UnknownAttribute || !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) { + + //HLSL change, language option to maintain unknown annotations. + //This is extremely useful for extending the language for providing extra reflection info. + //These annotations are accessible through IHLSLReflectionData. + + const LangOptions &LangOpts = S.Context.getLangOpts(); + + if (LangOpts.HLSL && LangOpts.PreserveUnknownAnnotations) { + + //In the case of oxc::stage("compute") clang only maintains oxc::stage. + //We get around this by instantiating a lexer and finding the end of the annotation (]]). + //We don't do any cleanup and pass the inside of [[]] as is, so any external parsing can be done on it. + + SourceRange AttrRange = Attr.getRange(); + + const SourceManager &SM = S.Context.getSourceManager(); + const LangOptions &LO = S.Context.getLangOpts(); + FileID FID = SM.getFileID(Attr.getLoc()); + StringRef Buffer = SM.getBufferData(FID); + const char *AttrData = SM.getCharacterData(AttrRange.getBegin()); + + SourceLocation BeginLoc = AttrRange.getBegin(); + SourceLocation EndLoc = AttrRange.getEnd(); + + Lexer Lex(SM.getLocForStartOfFile(FID), LangOpts, Buffer.begin(), + AttrData, Buffer.end()); + + Token Tok; + while (!Lex.LexFromRawLexer(Tok)) { //Search until ]] + + if (!Tok.is(tok::r_square)) + continue; + + Token Next; + if (Lex.LexFromRawLexer(Next)) + break; + + if (!Next.is(tok::r_square)) + continue; + + EndLoc = Tok.getLocation(); + break; + } + + StringRef FullAttrSpelling = Lexer::getSourceText( + CharSourceRange::getCharRange(BeginLoc, EndLoc), SM, LO); + + D->addAttr(AnnotateAttr::CreateImplicit(S.Context, FullAttrSpelling, + Attr.getLoc())); + return; + } + S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? diag::warn_unhandled_ms_attribute_ignored : diag::warn_unknown_attribute_ignored) diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/array_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/array_test.hlsl new file mode 100644 index 0000000000..f6ee17f6a1 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/array_test.hlsl @@ -0,0 +1,908 @@ +// RUN: %dxreflector %s | FileCheck %s + +typedef float farr4[4]; +typedef float farr4x3[4][3]; +typedef float farr4x3x5[4][3][5]; + +typedef farr4 farr4a6[6]; +typedef farr4x3 farr4x3a6a7[6][7]; +typedef farr4x3x5 farr4x3x5a6a7a8[6][7][8]; + +typedef float f32; + +typedef f32 f32arr4[4]; +typedef f32 f32arr4x3[4][3]; +typedef f32 f32arr4x3x5[4][3][5]; + +typedef f32arr4 f32arr4a6[6]; +typedef f32arr4x3 f32arr4x3a6a7[6][7]; +typedef f32arr4x3x5 f32arr4x3x5a6a7a8[6][7][8]; + +farr4 arr0[2]; +farr4x3 arr1[2]; +farr4x3x5 arr2[2]; + +farr4a6 arr3[2]; +farr4x3a6a7 arr4[2]; +farr4x3x5a6a7a8 arr5[2]; + +f32arr4 arr6[2]; +f32arr4x3 arr7[2]; +f32arr4x3x5 arr8[2]; + +f32arr4a6 arr9[2]; +f32arr4x3a6a7 arr10[2]; +f32arr4x3x5a6a7a8 arr11[2]; + +struct Test { + + farr4 arr0[2]; + farr4x3 arr1[2]; + farr4x3x5 arr2[2]; + + farr4a6 arr3[2]; + farr4x3a6a7 arr4[2]; + farr4x3x5a6a7a8 arr5[2]; + + f32arr4 arr6[2]; + f32arr4x3 arr7[2]; + f32arr4x3x5 arr8[2]; + + f32arr4a6 arr9[2]; + f32arr4x3a6a7 arr10[2]; + f32arr4x3x5a6a7a8 arr11[2]; +}; + +void func( + Test t[2], + farr4 arr0[2], + farr4x3 arr1[2], + farr4x3x5 arr2[2], + farr4a6 arr3[2], + farr4x3a6a7 arr4[2], + farr4x3x5a6a7a8 arr5[2], + f32arr4 arr6[2], + f32arr4x3 arr7[2], + f32arr4x3x5 arr8[2], + f32arr4a6 arr9[2], + f32arr4x3a6a7 arr10[2], + f32arr4x3x5a6a7a8 arr11[2]) { } + +Texture2D tex0[4]; +Texture2D tex1[4][3]; +Texture2D tex2[4][3][2]; + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "farr4", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "farr4x3", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float", +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "farr4x3x5", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float", +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "farr4a6", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "farr4", +// CHECK: "ArraySize": [ +// CHECK: 6 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "farr4x3a6a7", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3", +// CHECK: "ArraySize": [ +// CHECK: 6, +// CHECK: 7 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "farr4x3x5a6a7a8", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 6, +// CHECK: 7, +// CHECK: 8 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ], +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4x3", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32", +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3 +// CHECK: ], +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4x3x5", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32", +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5 +// CHECK: ], +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4a6", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4", +// CHECK: "ArraySize": [ +// CHECK: 6 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4x3a6a7", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3", +// CHECK: "ArraySize": [ +// CHECK: 6, +// CHECK: 7 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32arr4x3x5a6a7a8", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 6, +// CHECK: 7, +// CHECK: 8 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr0", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr1", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr2", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr3", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr4", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr5", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr6", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr7", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr8", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr9", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr10", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr11", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "arr0", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr1", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr2", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr3", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr4", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr5", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "farr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr6", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr7", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr8", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr9", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr10", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "arr11", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32arr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "func", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "t": { +// CHECK: "TypeName": "Test", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr0": { +// CHECK: "TypeName": "farr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr1": { +// CHECK: "TypeName": "farr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr2": { +// CHECK: "TypeName": "farr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr3": { +// CHECK: "TypeName": "farr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr4": { +// CHECK: "TypeName": "farr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr5": { +// CHECK: "TypeName": "farr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr6": { +// CHECK: "TypeName": "f32arr4", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr7": { +// CHECK: "TypeName": "f32arr4x3", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr8": { +// CHECK: "TypeName": "f32arr4x3x5", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr9": { +// CHECK: "TypeName": "f32arr4a6", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 6, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr10": { +// CHECK: "TypeName": "f32arr4x3a6a7", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 6, +// CHECK: 7, +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "arr11": { +// CHECK: "TypeName": "f32arr4x3x5a6a7a8", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 5, +// CHECK: 6, +// CHECK: 7, +// CHECK: 8, +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tex0", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "float", +// CHECK: "BindCount": 4, +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tex1", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "float", +// CHECK: "BindCount": 12, +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3 +// CHECK: ], +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tex2", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "float", +// CHECK: "BindCount": 24, +// CHECK: "ArraySize": [ +// CHECK: 4, +// CHECK: 3, +// CHECK: 2 +// CHECK: ], +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/enums.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/enums.hlsl new file mode 100644 index 0000000000..002f6ac67d --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/enums.hlsl @@ -0,0 +1,553 @@ +// RUN: %dxreflector -T lib_6_4 -enable-16bit-types %s | FileCheck %s + +enum Test { + Test_A, + Test_B, + Test_C +}; + +enum class Test2 { + A, + B, + C +}; + +enum class Test3 : int { + A, + B, + C +}; + +enum class Test4 : uint64_t { + A, + B, + C +}; + +enum class Test5 : int64_t { + A, + B, + C +}; + +enum class Test6 : uint { + A, + B, + C +}; + +enum class Test7 : int16_t { + A, + B, + C +}; + +enum class Test8 : uint16_t { + A, + B, + C +}; + +Test a; +Test2 b; +Test3 c; +Test4 d; +Test5 e; +Test6 f; +Test7 g; +Test8 h; + +struct A { + Test a; + Test2 b; + Test3 c; + Test4 d; + Test5 e; + Test6 f; + Test7 g; + Test8 h; +}; + +StructuredBuffer sbuf; + +void test( + Test a, + Test2 b, + Test3 c, + Test4 d, + Test5 e, + Test6 f, + Test7 g, + Test8 h) {} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test", +// CHECK: "EnumType": "uint", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "Test_A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "Test_B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "Test_C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test2", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test2", +// CHECK: "EnumType": "int", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test3", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test3", +// CHECK: "EnumType": "int", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test4", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test4", +// CHECK: "EnumType": "uint64_t", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test5", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test5", +// CHECK: "EnumType": "int64_t", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test6", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test6", +// CHECK: "EnumType": "uint", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test7", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test7", +// CHECK: "EnumType": "int16_t", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test8", +// CHECK: "NodeType": "Enum", +// CHECK: "Enum": { +// CHECK: "Name": "Test8", +// CHECK: "EnumType": "uint16_t", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 2, +// CHECK: "Symbol": { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "UnderlyingName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test2", +// CHECK: "UnderlyingName": "int" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test3", +// CHECK: "UnderlyingName": "int" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test4", +// CHECK: "UnderlyingName": "uint64_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test5", +// CHECK: "UnderlyingName": "int64_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test6", +// CHECK: "UnderlyingName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "g", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test7", +// CHECK: "UnderlyingName": "int16_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test8", +// CHECK: "UnderlyingName": "uint16_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "UnderlyingName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test2", +// CHECK: "UnderlyingName": "int" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test3", +// CHECK: "UnderlyingName": "int" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test4", +// CHECK: "UnderlyingName": "uint64_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test5", +// CHECK: "UnderlyingName": "int64_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test6", +// CHECK: "UnderlyingName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "g", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test7", +// CHECK: "UnderlyingName": "int16_t" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test8", +// CHECK: "UnderlyingName": "uint16_t" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sbuf", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "Test", +// CHECK: "UnderlyingName": "uint" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "Test2", +// CHECK: "UnderlyingName": "int" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "Test3", +// CHECK: "UnderlyingName": "int" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "TypeName": "Test4", +// CHECK: "UnderlyingName": "uint64_t" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "TypeName": "Test5", +// CHECK: "UnderlyingName": "int64_t" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "TypeName": "Test6", +// CHECK: "UnderlyingName": "uint" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "g", +// CHECK: "TypeName": "Test7", +// CHECK: "UnderlyingName": "int16_t" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "TypeName": "Test8", +// CHECK: "UnderlyingName": "uint16_t" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "Test", +// CHECK: "UnderlyingName": "uint" +// CHECK: }, +// CHECK: "b": { +// CHECK: "TypeName": "Test2", +// CHECK: "UnderlyingName": "int" +// CHECK: }, +// CHECK: "c": { +// CHECK: "TypeName": "Test3", +// CHECK: "UnderlyingName": "int" +// CHECK: }, +// CHECK: "d": { +// CHECK: "TypeName": "Test4", +// CHECK: "UnderlyingName": "uint64_t" +// CHECK: }, +// CHECK: "e": { +// CHECK: "TypeName": "Test5", +// CHECK: "UnderlyingName": "int64_t" +// CHECK: }, +// CHECK: "f": { +// CHECK: "TypeName": "Test6", +// CHECK: "UnderlyingName": "uint" +// CHECK: }, +// CHECK: "g": { +// CHECK: "TypeName": "Test7", +// CHECK: "UnderlyingName": "int16_t" +// CHECK: }, +// CHECK: "h": { +// CHECK: "TypeName": "Test8", +// CHECK: "UnderlyingName": "uint16_t" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/functions_semantics_interpolation.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/functions_semantics_interpolation.hlsl new file mode 100644 index 0000000000..e6b9ccc443 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/functions_semantics_interpolation.hlsl @@ -0,0 +1,125 @@ +// RUN: %dxreflector %s | FileCheck %s + +struct Test { + float3 pos : POSITION0; + nointerpolation uint test : FLAT0; +}; + +void testFunction(inout uint a, out uint b, in uint c) { + b = a | c; +} + +[[oxc::stage("vertex")]] +float4 mainVS(float2 uv : TEXCOORD0, nointerpolation uint test : KAAS0, Test t) : SV_POSITION { + return float4(uv * 2 - 1, 0, 1); +} + +[shader("pixel")] +float4 mainPS(float4 pos : SV_POSITION) : SV_TARGET { + return float4(pos.xy, 0, 1); +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "pos", +// CHECK: "NodeType": "Variable", +// CHECK: "Semantic": "POSITION0", +// CHECK: "Type": { +// CHECK: "Name": "float3" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Variable", +// CHECK: "Semantic": "FLAT0", +// CHECK: "Interpolation": "Constant", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "testFunction", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "uint", +// CHECK: "Access": "inout" +// CHECK: }, +// CHECK: "b": { +// CHECK: "TypeName": "uint", +// CHECK: "Access": "out" +// CHECK: }, +// CHECK: "c": { +// CHECK: "TypeName": "uint", +// CHECK: "Access": "in" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "mainVS", +// CHECK: "NodeType": "Function", +// CHECK: "Semantic": "SV_POSITION", +// CHECK: "Annotations": [ +// CHECK: {{"\[\[oxc::stage\(\\\"vertex\\\"\)\]\]"}} +// CHECK: ], +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "uv": { +// CHECK: "TypeName": "float2", +// CHECK: "Semantic": "TEXCOORD0" +// CHECK: }, +// CHECK: "test": { +// CHECK: "TypeName": "uint", +// CHECK: "Semantic": "KAAS0", +// CHECK: "Interpolation": "Constant" +// CHECK: }, +// CHECK: "t": { +// CHECK: "TypeName": "Test" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "mainPS", +// CHECK: "NodeType": "Function", +// CHECK: "Semantic": "SV_TARGET", +// CHECK: "Annotations": [ +// CHECK: "[shader(\"pixel\")]" +// CHECK: ], +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "pos": { +// CHECK: "TypeName": "float4", +// CHECK: "Semantic": "SV_POSITION" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test.hlsl new file mode 100644 index 0000000000..957f49a0ab --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test.hlsl @@ -0,0 +1,187 @@ +// RUN: %dxreflector %s | FileCheck %s + +namespace tst { + struct Tst; + struct A { + float a(); + }; +} + +struct Test; +struct Test; + +struct Never0; + +struct A { + float a; + float t(Test t); + float t2(tst::Tst a); + float neverDeclared(Never0 a); +}; + +struct Test { + float a; +}; + +struct tst::Tst { + float a; +}; + +float A::t(Test t) { return 2; } +float A::t2(tst::Tst a) { return 2; } +float tst::A::a() { return 2; } + +float neverDeclared(Never0 a); + +float4 test(); +float4 test(); + +float4 test() { return 0.xxxx; } + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "tst", +// CHECK: "NodeType": "Namespace", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "Tst", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Never0", +// CHECK: "NodeType": "Struct" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "t": { +// CHECK: "TypeName": "Test" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t2", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "tst::Tst" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "neverDeclared", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "HasDefinition": false, +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "Never0" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "neverDeclared", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "HasDefinition": false, +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "Never0" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test2.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test2.hlsl new file mode 100644 index 0000000000..ed1d9c8548 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/fwd_declare_test2.hlsl @@ -0,0 +1,55 @@ +// RUN: %dxreflector -reflect-functions %s | FileCheck %s + +struct PSInput { + float4 color : COLOR; +}; + +struct Test; + +struct A { + float a; + float t(Test t); +}; + +struct Test { + float a; +}; + +float A::t(Test t) { + return 2; +} + +[[oxc::stage("pixel")]] +float4 PSMain(PSInput input) : SV_TARGET +{ + A a; + Test t; + return input.color * a.t(t); +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Functions", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "PSMain", +// CHECK: "NodeType": "Function", +// CHECK: "Semantic": "SV_TARGET", +// CHECK: "Annotations": [ +// CHECK: {{"\[\[oxc::stage\(\\\"pixel\\\"\)\]\]"}} +// CHECK: ], +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "input": { +// CHECK: "TypeName": "PSInput" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } \ No newline at end of file diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/inheritance.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/inheritance.hlsl new file mode 100644 index 0000000000..b327efd5bd --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/inheritance.hlsl @@ -0,0 +1,194 @@ +// RUN: %dxreflector %s | FileCheck %s + +struct A { + float4 color1 : COLOR1; +}; + +interface B { }; + +interface C { + float4 test(); +}; + +struct PSInput : A, B, C { + float4 color : COLOR; + float4 test() { return 2; } +}; + +StructuredBuffer buf; +PSInput var; + +float4 PSMain(PSInput input) : SV_TARGET { + return input.color1 * input.color * buf[0].color; +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "color1", +// CHECK: "NodeType": "Variable", +// CHECK: "Semantic": "COLOR1", +// CHECK: "Type": { +// CHECK: "Name": "float4" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "B", +// CHECK: "NodeType": "Interface" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "C", +// CHECK: "NodeType": "Interface", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "HasDefinition": false, +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "PSInput", +// CHECK: "NodeType": "Struct", +// CHECK: "Class": { +// CHECK: "BaseClass": { +// CHECK: "Name": "A" +// CHECK: }, +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "Name": "B" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "color", +// CHECK: "NodeType": "Variable", +// CHECK: "Semantic": "COLOR", +// CHECK: "Type": { +// CHECK: "Name": "float4" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "buf", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "PSInput", +// CHECK: "BaseClass": { +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "color1", +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "Name": "B" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "color", +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "var", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "PSInput", +// CHECK: "BaseClass": { +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "color1", +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "Name": "B" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "color", +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "PSMain", +// CHECK: "NodeType": "Function", +// CHECK: "Semantic": "SV_TARGET", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "input": { +// CHECK: "TypeName": "PSInput" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/raw_data_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/raw_data_test.hlsl new file mode 100644 index 0000000000..b31dfecb05 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/raw_data_test.hlsl @@ -0,0 +1,972 @@ +// RUN: %dxreflector -reflect-show-raw-data %s | FileCheck %s + +typedef float B; +float a[2][3]; + +enum class Test { + A, + B +}; + +interface C {}; + +struct A : C { + float a; + void test() {} +}; + +ConstantBuffer b; + +[[oxc::fancy]] +void test(A a, uint b) { + + if(b) { float a0; } + else if(b != 1) { float a1; } + else { float a2; } + + do { float a3; } while(0); + + if(uint d = b ^ 23) { float a4; } + else if(uint d = b ^ 22) { float a5; } + else { float a6; } + + switch(uint d = b ^ 23) { + default: { float a7; break; } + } + + switch(b) { + case 0: { float a8; break; } + case 1: { float a9; break; } + default: break; + } + + while(false) { float a10; break; } + + for(int i = 0; i < 16; ++i) { + float a11; + } + + for(int i = 0, j = 0; i < 16; ++i, ++j) { + float a12; + } + + for(int i = 0, j = 0; bool k = i < 16; ++i, ++j) { + float a12; + } + + { float a13; } +} + +namespace tst { + float a; +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Strings": [ +// CHECK: "", +// CHECK: "float", +// CHECK: "{{.*}}raw_data_test.hlsl", +// CHECK: "B", +// CHECK: "a", +// CHECK: "Test", +// CHECK: "A", +// CHECK: "C", +// CHECK: "test", +// CHECK: "b", +// CHECK: "uint", +// CHECK: "a0", +// CHECK: "a1", +// CHECK: "a2", +// CHECK: "a3", +// CHECK: "d", +// CHECK: "a4", +// CHECK: "a5", +// CHECK: "a6", +// CHECK: "a7", +// CHECK: "a8", +// CHECK: "a9", +// CHECK: "a10", +// CHECK: "int", +// CHECK: "i", +// CHECK: "a11", +// CHECK: "j", +// CHECK: "a12", +// CHECK: "bool", +// CHECK: "k", +// CHECK: "a13", +// CHECK: "tst" +// CHECK: ], +// CHECK: "StringsNonDebug": [ +// CHECK: "oxc::fancy" +// CHECK: ], +// CHECK: "Sources": [ +// CHECK: "{{.*}}raw_data_test.hlsl" +// CHECK: ], +// CHECK: "SourcesAsId": [ +// CHECK: 2 +// CHECK: ], +// CHECK: "Nodes": [ +// CHECK: { +// CHECK: "NodeId": 0, +// CHECK: "NodeType": "Namespace", +// CHECK: "NodeTypeId": 4, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": -1, +// CHECK: "ChildCount": 60, +// CHECK: "ChildStart": 1 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 1, +// CHECK: "NodeType": "Typedef", +// CHECK: "NodeTypeId": 6, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 0 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 2, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 0 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 3, +// CHECK: "NodeType": "Enum", +// CHECK: "NodeTypeId": 2, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 0, +// CHECK: "ChildCount": 2, +// CHECK: "ChildStart": 4 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 4, +// CHECK: "NodeType": "EnumValue", +// CHECK: "NodeTypeId": 3, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 3 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 5, +// CHECK: "NodeType": "EnumValue", +// CHECK: "NodeTypeId": 3, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 3 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 6, +// CHECK: "NodeType": "Interface", +// CHECK: "NodeTypeId": 10, +// CHECK: "LocalId": 2, +// CHECK: "ParentId": 0 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 7, +// CHECK: "NodeType": "Struct", +// CHECK: "NodeTypeId": 7, +// CHECK: "LocalId": 3, +// CHECK: "ParentId": 0, +// CHECK: "ChildCount": 2, +// CHECK: "ChildStart": 8 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 8, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 7 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 9, +// CHECK: "NodeType": "Function", +// CHECK: "NodeTypeId": 1, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 7 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 10, +// CHECK: "NodeType": "Register", +// CHECK: "NodeTypeId": 0, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 0, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 11 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 11, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 4, +// CHECK: "ParentId": 10 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 12, +// CHECK: "NodeType": "Function", +// CHECK: "NodeTypeId": 1, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 0, +// CHECK: "ChildCount": 46, +// CHECK: "ChildStart": 13, +// CHECK: "AnnotationStart": 0, +// CHECK: "AnnotationCount": 1, +// CHECK: "Annotations": [ +// CHECK: "{{\[\[oxc::fancy\]\]}}" +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 13, +// CHECK: "NodeType": "Parameter", +// CHECK: "NodeTypeId": 11, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 12 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 14, +// CHECK: "NodeType": "Parameter", +// CHECK: "NodeTypeId": 11, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 12 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 15, +// CHECK: "NodeType": "IfRoot", +// CHECK: "NodeTypeId": 12, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 6, +// CHECK: "ChildStart": 16 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 16, +// CHECK: "NodeType": "IfFirst", +// CHECK: "NodeTypeId": 22, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 15, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 17 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 17, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 16 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 18, +// CHECK: "NodeType": "ElseIf", +// CHECK: "NodeTypeId": 23, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 15, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 19 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 19, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 18 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 20, +// CHECK: "NodeType": "Else", +// CHECK: "NodeTypeId": 24, +// CHECK: "LocalId": 2, +// CHECK: "ParentId": 15, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 21 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 21, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 20 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 22, +// CHECK: "NodeType": "Do", +// CHECK: "NodeTypeId": 14, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 23 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 23, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 22 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 24, +// CHECK: "NodeType": "IfRoot", +// CHECK: "NodeTypeId": 12, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 8, +// CHECK: "ChildStart": 25 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 25, +// CHECK: "NodeType": "IfFirst", +// CHECK: "NodeTypeId": 22, +// CHECK: "LocalId": 3, +// CHECK: "ParentId": 24, +// CHECK: "ChildCount": 2, +// CHECK: "ChildStart": 26 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 26, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 6, +// CHECK: "ParentId": 25 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 27, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 25 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 28, +// CHECK: "NodeType": "ElseIf", +// CHECK: "NodeTypeId": 23, +// CHECK: "LocalId": 4, +// CHECK: "ParentId": 24, +// CHECK: "ChildCount": 2, +// CHECK: "ChildStart": 29 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 29, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 6, +// CHECK: "ParentId": 28 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 30, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 28 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 31, +// CHECK: "NodeType": "Else", +// CHECK: "NodeTypeId": 24, +// CHECK: "LocalId": 5, +// CHECK: "ParentId": 24, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 32 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 32, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 31 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 33, +// CHECK: "NodeType": "Switch", +// CHECK: "NodeTypeId": 15, +// CHECK: "LocalId": 2, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 3, +// CHECK: "ChildStart": 34 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 34, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 6, +// CHECK: "ParentId": 33 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 35, +// CHECK: "NodeType": "Default", +// CHECK: "NodeTypeId": 20, +// CHECK: "LocalId": 6, +// CHECK: "ParentId": 33, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 36 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 36, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 35 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 37, +// CHECK: "NodeType": "Switch", +// CHECK: "NodeTypeId": 15, +// CHECK: "LocalId": 3, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 5, +// CHECK: "ChildStart": 38 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 38, +// CHECK: "NodeType": "Case", +// CHECK: "NodeTypeId": 19, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 37, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 39 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 39, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 38 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 40, +// CHECK: "NodeType": "Case", +// CHECK: "NodeTypeId": 19, +// CHECK: "LocalId": 8, +// CHECK: "ParentId": 37, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 41 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 41, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 40 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 42, +// CHECK: "NodeType": "Default", +// CHECK: "NodeTypeId": 20, +// CHECK: "LocalId": 9, +// CHECK: "ParentId": 37 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 43, +// CHECK: "NodeType": "While", +// CHECK: "NodeTypeId": 16, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 44 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 44, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 43 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 45, +// CHECK: "NodeType": "For", +// CHECK: "NodeTypeId": 17, +// CHECK: "LocalId": 1, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 2, +// CHECK: "ChildStart": 46 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 46, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 45 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 47, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 45 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 48, +// CHECK: "NodeType": "For", +// CHECK: "NodeTypeId": 17, +// CHECK: "LocalId": 2, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 3, +// CHECK: "ChildStart": 49 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 49, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 48 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 50, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 48 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 51, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 48 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 52, +// CHECK: "NodeType": "For", +// CHECK: "NodeTypeId": 17, +// CHECK: "LocalId": 3, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 4, +// CHECK: "ChildStart": 53 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 53, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 8, +// CHECK: "ParentId": 52 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 54, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 52 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 55, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 7, +// CHECK: "ParentId": 52 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 56, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 52 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 57, +// CHECK: "NodeType": "Scope", +// CHECK: "NodeTypeId": 13, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 12, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 58 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 58, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 57 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 59, +// CHECK: "NodeType": "Namespace", +// CHECK: "NodeTypeId": 4, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 0, +// CHECK: "ChildCount": 1, +// CHECK: "ChildStart": 60 +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 60, +// CHECK: "NodeType": "Variable", +// CHECK: "NodeTypeId": 5, +// CHECK: "LocalId": 0, +// CHECK: "ParentId": 59 +// CHECK: } +// CHECK: ], +// CHECK: "Registers": [ +// CHECK: { +// CHECK: "RegisterId": 0, +// CHECK: "NodeId": 10, +// CHECK: "Name": "b", +// CHECK: "RegisterType": "cbuffer", +// CHECK: "BufferId": 0 +// CHECK: } +// CHECK: ], +// CHECK: "Functions": [ +// CHECK: { +// CHECK: "FunctionId": 0, +// CHECK: "NodeId": 9, +// CHECK: "Name": "test", +// CHECK: "HasDefinition": true, +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "FunctionId": 1, +// CHECK: "NodeId": 12, +// CHECK: "Name": "test", +// CHECK: "HasDefinition": true, +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeId": 5, +// CHECK: "TypeName": "A" +// CHECK: }, +// CHECK: "b": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: ], +// CHECK: "Parameters": [ +// CHECK: { +// CHECK: "ParamName": "a", +// CHECK: "TypeId": 5, +// CHECK: "TypeName": "A" +// CHECK: }, +// CHECK: { +// CHECK: "ParamName": "b", +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "uint" +// CHECK: } +// CHECK: ], +// CHECK: "Enums": [ +// CHECK: { +// CHECK: "EnumId": 0, +// CHECK: "NodeId": 3, +// CHECK: "Name": "Test", +// CHECK: "EnumType": "int", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "ValueId": 0, +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A", +// CHECK: "NameId": 6 +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "ValueId": 1, +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B", +// CHECK: "NameId": 3 +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ], +// CHECK: "EnumValues": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A", +// CHECK: "NameId": 6 +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B", +// CHECK: "NameId": 3 +// CHECK: } +// CHECK: } +// CHECK: ], +// CHECK: "Annotations": [ +// CHECK: { +// CHECK: "StringId": 0, +// CHECK: "Contents": "oxc::fancy", +// CHECK: "Type": "User" +// CHECK: } +// CHECK: ], +// CHECK: "Arrays": [ +// CHECK: { +// CHECK: "ArrayElem": 2, +// CHECK: "ArrayStart": 0, +// CHECK: "ArraySizes": [ +// CHECK: 2, +// CHECK: 3 +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "ArrayElem": 2, +// CHECK: "ArrayStart": 2, +// CHECK: "ArraySizes": [ +// CHECK: 2, +// CHECK: 3 +// CHECK: ] +// CHECK: } +// CHECK: ], +// CHECK: "ArraySizes": [ +// CHECK: 2, +// CHECK: 3, +// CHECK: 2, +// CHECK: 3 +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ], +// CHECK: "TypeList": [ +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Types": [ +// CHECK: { +// CHECK: "TypeId": 0, +// CHECK: "Name": "float" +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 1, +// CHECK: "Name": "float", +// CHECK: "ArraySize": [ +// CHECK: 2, +// CHECK: 3 +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 3, +// CHECK: "Name": "A", +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 4, +// CHECK: "Name": "A", +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 5, +// CHECK: "Name": "A", +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 6, +// CHECK: "Name": "uint" +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 7, +// CHECK: "Name": "int" +// CHECK: }, +// CHECK: { +// CHECK: "TypeId": 8, +// CHECK: "Name": "bool" +// CHECK: } +// CHECK: ], +// CHECK: "Buffers": [ +// CHECK: { +// CHECK: "BufferId": 0, +// CHECK: "NodeId": 10, +// CHECK: "Name": "b", +// CHECK: "Type": "cbuffer", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 11, +// CHECK: "ChildId": 0, +// CHECK: "Name": "b", +// CHECK: "TypeId": 4, +// CHECK: "TypeName": "A", +// CHECK: "Interfaces": [ +// CHECK: { +// CHECK: "TypeId": 2, +// CHECK: "Name": "C" +// CHECK: } +// CHECK: ], +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NameId": 4, +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ], +// CHECK: "Statements": [ +// CHECK: { +// CHECK: "Type": "While", +// CHECK: "NodeId": 43, +// CHECK: "Body": 1 +// CHECK: }, +// CHECK: { +// CHECK: "Type": "For", +// CHECK: "NodeId": 45, +// CHECK: "Init": 1, +// CHECK: "Body": 1 +// CHECK: }, +// CHECK: { +// CHECK: "Type": "For", +// CHECK: "NodeId": 48, +// CHECK: "Init": 2, +// CHECK: "Body": 1 +// CHECK: }, +// CHECK: { +// CHECK: "Type": "For", +// CHECK: "NodeId": 52, +// CHECK: "HasConditionVar": true, +// CHECK: "Init": 2, +// CHECK: "Body": 1 +// CHECK: } +// CHECK: ], +// CHECK: "IfSwitchStatements": [ +// CHECK: { +// CHECK: "Type": "IfRoot", +// CHECK: "NodeId": 15, +// CHECK: "HasElseOrDefault": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "IfRoot", +// CHECK: "NodeId": 24, +// CHECK: "HasElseOrDefault": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Switch", +// CHECK: "NodeId": 33, +// CHECK: "HasConditionVar": true, +// CHECK: "HasElseOrDefault": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Switch", +// CHECK: "NodeId": 37, +// CHECK: "HasElseOrDefault": true +// CHECK: } +// CHECK: ], +// CHECK: "BranchStatements": [ +// CHECK: { +// CHECK: "Type": "IfFirst", +// CHECK: "NodeId": 16, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "ElseIf", +// CHECK: "NodeId": 18, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Else", +// CHECK: "NodeId": 20, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "IfFirst", +// CHECK: "NodeId": 25, +// CHECK: "HasConditionVar": true, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "ElseIf", +// CHECK: "NodeId": 28, +// CHECK: "HasConditionVar": true, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Else", +// CHECK: "NodeId": 31, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Default", +// CHECK: "NodeId": 35, +// CHECK: "IsComplexCase": true +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Case", +// CHECK: "NodeId": 38, +// CHECK: "ValueType": "uint", +// CHECK: "Value": 0 +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Case", +// CHECK: "NodeId": 40, +// CHECK: "ValueType": "uint", +// CHECK: "Value": 1 +// CHECK: }, +// CHECK: { +// CHECK: "Type": "Default", +// CHECK: "NodeId": 42, +// CHECK: "IsComplexCase": true +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/recursive_buffer.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/recursive_buffer.hlsl new file mode 100644 index 0000000000..565896d149 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/recursive_buffer.hlsl @@ -0,0 +1,268 @@ +// RUN: %dxreflector %s | FileCheck %s + +struct A { + float a; +}; + +struct B { + A a; + float b; +}; + +struct C { + B b; + float c; +}; + +struct D { + C c; + float d; +}; + +StructuredBuffer buf; +D var; + +void test(D d) { } + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "B", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "C", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "B", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "D", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "C", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "B", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "buf", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "C", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "B", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "var", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "C", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "B", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "A", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "d": { +// CHECK: "TypeName": "D" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/relatively_empty.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/relatively_empty.hlsl new file mode 100644 index 0000000000..de6e2672cf --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/relatively_empty.hlsl @@ -0,0 +1,14 @@ +// RUN: %dxreflector %s | FileCheck %s + +#define EMPTY + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/resource_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/resource_test.hlsl new file mode 100644 index 0000000000..2f0f347975 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/resource_test.hlsl @@ -0,0 +1,733 @@ +// RUN: %dxreflector %s | FileCheck %s + +typedef RWByteAddressBuffer RWBAB; + +RWByteAddressBuffer output0; +RWByteAddressBuffer output1 : SEMA; +RWByteAddressBuffer output2 : register(u1); +RWByteAddressBuffer output3[12]; +RWBAB output4; + +struct Test { + float a; +}; + +typedef float f32; + +typedef StructuredBuffer sbufferFloat; +typedef StructuredBuffer sbufferF32; +typedef StructuredBuffer sbufferTest; + +StructuredBuffer input0; +StructuredBuffer input1; +StructuredBuffer input2; +sbufferFloat input3; +sbufferF32 input4; +sbufferTest input5; + +typedef ByteAddressBuffer BAB; + +ByteAddressBuffer input6; +BAB input7; + +typedef Texture2D t2d; +typedef Texture3D t3d; +typedef TextureCube tcub; +typedef Texture1D t1d; +typedef Texture2DMS t2dms; + +Texture2D input8; +Texture3D input9; +TextureCube input10; +Texture1D input11; +Texture2DMS input12; + +t2d input13; +t3d input14; +tcub input15; +t1d input16; +t2dms input17; + +typedef Texture2D t2duint; + +Texture2D input18; +t2duint input19; + +typedef SamplerState samp; + +SamplerState sampler0; +samp sampler1; + +cbuffer test : register(b0) { float a; }; +cbuffer test2 { float b; }; + +typedef ConstantBuffer cbufTest; + +ConstantBuffer test3; +cbufTest test4; + +float e; + +//TODO: Disable listing this as if it's a struct, but needs a builtin type in DX headers. +typedef RaytracingAccelerationStructure rtas; + +RaytracingAccelerationStructure rtas0; +rtas rtas1; + +[shader("compute")] +[numthreads(16, 16, 1)] +void main(uint id : SV_DispatchThreadID) { } + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "RWBAB", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "RWByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "output0", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RWByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "output1", +// CHECK: "NodeType": "Register", +// CHECK: "Semantic": "SEMA", +// CHECK: "Register": { +// CHECK: "RegisterType": "RWByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "output2", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RWByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "output3", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RWByteAddressBuffer", +// CHECK: "BindCount": 12 +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "output4", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RWByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f32", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sbufferFloat", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "StructuredBuffer", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sbufferF32", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "StructuredBuffer", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "f32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sbufferTest", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "StructuredBuffer", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "Test" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input0", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input1", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input2", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input3", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input4", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "f32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input5", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "BAB", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "ByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input6", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "ByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input7", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "ByteAddressBuffer" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t2d", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Texture2D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "vector", +// CHECK: "UnderlyingName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t3d", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Texture3D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "vector", +// CHECK: "UnderlyingName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tcub", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "TextureCube", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "vector", +// CHECK: "UnderlyingName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t1d", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Texture1D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "vector", +// CHECK: "UnderlyingName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t2dms", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Texture2DMS", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "float4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input8", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input9", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture3D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input10", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "TextureCube", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input11", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture1D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input12", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2DMS", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input13", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input14", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture3D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input15", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "TextureCube", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input16", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture1D", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input17", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2DMS", +// CHECK: "ReturnType": "float", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "t2duint", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Texture2D", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "$Element", +// CHECK: "TypeName": "uint4" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input18", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "uint", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "input19", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "Texture", +// CHECK: "Dimension": "Texture2D", +// CHECK: "ReturnType": "uint", +// CHECK: "Flags": [ +// CHECK: "TextureComponent0", +// CHECK: "TextureComponent1" +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "samp", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "SamplerState" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sampler0", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "SamplerState" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "sampler1", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "SamplerState" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "cbuffer", +// CHECK: "Flags": [ +// CHECK: "UserPacked" +// CHECK: ] +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test2", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "cbuffer", +// CHECK: "Flags": [ +// CHECK: "UserPacked" +// CHECK: ] +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "cbufTest", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "ConstantBuffer", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "TypeName": "Test" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test3", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "cbuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "test3", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test4", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "cbuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "test4", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "rtas", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "RaytracingAccelerationStructure", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "TypeName": "int" +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "rtas0", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RaytracingAccelerationStructure" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "rtas1", +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterType": "RaytracingAccelerationStructure" +// CHECK: } +// CHECK: } +// CHECK: { +// CHECK: "Name": "main", +// CHECK: "NodeType": "Function", +// CHECK: "Annotations": [ +// CHECK: "[shader(\"compute\")]" +// CHECK: ], +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "id": { +// CHECK: "TypeName": "uint", +// CHECK: "Semantic": "SV_DispatchThreadID" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } \ No newline at end of file diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/sources_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/sources_test.hlsl new file mode 100644 index 0000000000..d4e1861d54 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/sources_test.hlsl @@ -0,0 +1,200 @@ +// RUN: %dxreflector -reflect-show-file-info %s | FileCheck %s + +typedef float B; +float a; + +enum class Test { + A, + B +}; + +struct A { + float a; + void test() {} +}; + +void test(A a, float b) {} + +namespace tst { + float a; +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "B", +// CHECK: "NodeType": "Typedef", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 3, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 16 +// CHECK: }, +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 4, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 8 +// CHECK: }, +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Enum", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 6, +// CHECK: "LineCount": 4, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 2 +// CHECK: }, +// CHECK: "Enum": { +// CHECK: "Name": "Test", +// CHECK: "EnumType": "int", +// CHECK: "Values": [ +// CHECK: { +// CHECK: "Value": 0, +// CHECK: "Symbol": { +// CHECK: "Name": "A", +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 7, +// CHECK: "ColumnStart": 2, +// CHECK: "ColumnEnd": 3 +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Value": 1, +// CHECK: "Symbol": { +// CHECK: "Name": "B", +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 8, +// CHECK: "ColumnStart": 2, +// CHECK: "ColumnEnd": 3 +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "A", +// CHECK: "NodeType": "Struct", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 11, +// CHECK: "LineCount": 4, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 2 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 12, +// CHECK: "ColumnStart": 2, +// CHECK: "ColumnEnd": 9 +// CHECK: }, +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 13, +// CHECK: "ColumnStart": 2, +// CHECK: "ColumnEnd": 16 +// CHECK: }, +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 16, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 27 +// CHECK: }, +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 16, +// CHECK: "ColumnStart": 11, +// CHECK: "ColumnEnd": 14 +// CHECK: }, +// CHECK: "TypeName": "A" +// CHECK: }, +// CHECK: "b": { +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 16, +// CHECK: "ColumnStart": 16, +// CHECK: "ColumnEnd": 23 +// CHECK: }, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tst", +// CHECK: "NodeType": "Namespace", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 18, +// CHECK: "LineCount": 3, +// CHECK: "ColumnStart": 1, +// CHECK: "ColumnEnd": 2 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Symbol": { +// CHECK: "Source": "{{.*}}sources_test.hlsl", +// CHECK: "LineId": 19, +// CHECK: "ColumnStart": 2, +// CHECK: "ColumnEnd": 9 +// CHECK: }, +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/stmt_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/stmt_test.hlsl new file mode 100644 index 0000000000..94c9a090a4 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/stmt_test.hlsl @@ -0,0 +1,708 @@ +// RUN: %dxreflector %s | FileCheck %s + +void test(uint b) { + + if(uint d0 = b ^ 0x13) { + float c0; + } + + else { + float c1; + } + + if(uint d1 = b ^ 0x13) { + float c2; + } + + else if(uint d2 = b ^ 0x12) { + float c3; + uint e; + int f; + } + + else { + float c4; + } + + if(false) { + float c20; + } + + else if(false) { + float c21; + } + + if(true) { + float c25; + if(true) { + float c24; + } + else { + if(true) { + float c22; + } + float c23; + } + } + + while(true) { + float c5; + break; + } + + while(uint d3 = b ^ 0x13) { + float c6; + break; + } + + do { + float c7; + break; + } while(b ^ 0x13); + + { + float c8; + } + + for(uint i = 0; i < 5; ++i) { + float c9; + } + + [unroll] + for(uint i0 = 0; i0 < 2; ++i0) { + float c10; + } + + for(uint i1 = 0, j = 5; bool k = i1 < 2; ++i1, ++j) { + float c11; + } + + if(b == 0) { + float c12; + } + else if(b == 1) { + float c13; + } + else if(b == 2) { + float c14; + } + else if(b == 3) { + float c15; + } + else { + float c16; + float c17; + } + + switch(uint d4 = b ^ 0x13) { + case 0: + float c17; + break; + } + + switch(b) { + case 0: + break; + default: + break; + } + + switch(b) { + default: + break; + } + + switch(b) { + case 0: { + float c18; + break; + } + case 1: { + float c19; + break; + } + case 2: { + float c20; + break; + } + case 3: { + float c21; + break; + } + default: { + float c22; + break; + } + } +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "test", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "b": { +// CHECK: "TypeName": "uint" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Branch": { +// CHECK: "Condition": { +// CHECK: "Name": "d0", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c0", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Else", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c1", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Branch": { +// CHECK: "Condition": { +// CHECK: "Name": "d1", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c2", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "ElseIf", +// CHECK: "Branch": { +// CHECK: "Condition": { +// CHECK: "Name": "d2", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c3", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "int" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Else", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c4", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c20", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "ElseIf", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c21", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c25", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c24", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Else", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c22", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c23", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "While", +// CHECK: "While": { +// CHECK: "Body": [ +// CHECK: { +// CHECK: "Name": "c5", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "While", +// CHECK: "While": { +// CHECK: "Condition": { +// CHECK: "Name": "d3", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: }, +// CHECK: "Body": [ +// CHECK: { +// CHECK: "Name": "c6", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Do", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c7", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Scope", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c8", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "For", +// CHECK: "For": { +// CHECK: "Init": [ +// CHECK: { +// CHECK: "Name": "i", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ], +// CHECK: "Body": [ +// CHECK: { +// CHECK: "Name": "c9", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "For", +// CHECK: "For": { +// CHECK: "Init": [ +// CHECK: { +// CHECK: "Name": "i0", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ], +// CHECK: "Body": [ +// CHECK: { +// CHECK: "Name": "c10", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "For", +// CHECK: "For": { +// CHECK: "Condition": { +// CHECK: "Name": "k", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "bool" +// CHECK: } +// CHECK: }, +// CHECK: "Init": [ +// CHECK: { +// CHECK: "Name": "i1", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "j", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ], +// CHECK: "Body": [ +// CHECK: { +// CHECK: "Name": "c11", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "IfRoot", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "IfFirst", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c12", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "ElseIf", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c13", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "ElseIf", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c14", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "ElseIf", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c15", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Else", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c16", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c17", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Switch", +// CHECK: "Switch": { +// CHECK: "Condition": { +// CHECK: "Name": "d4", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 0 +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Switch", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 0 +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Default" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Switch", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "Default" +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Switch", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 0 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c18", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 1 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c19", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 2 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c20", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Case", +// CHECK: "Case": { +// CHECK: "Type": "uint", +// CHECK: "Value": 3 +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c21", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeType": "Default", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "c22", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/stripped_variable_types.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/stripped_variable_types.hlsl new file mode 100644 index 0000000000..758808e990 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/stripped_variable_types.hlsl @@ -0,0 +1,306 @@ +// RUN: %dxreflector -reflect-disable-symbols %s | FileCheck %s + +struct T { + uint otherData[4]; +}; + +groupshared uint groupData[16]; +static const uint staticData[4] = { 0, 1, 2, 3 }; +uint dynamicData[4]; +StructuredBuffer other; + +struct Test { + static const uint staticData = 0; + static float adds(float a, float b) { return a + b; } + float add(float a, float b) { return a + b; } +}; + +namespace tst { + + static const uint staticData[4] = { 0, 1, 2, 3 }; + float add(float a, float b) { return a + b; } + + struct Test { + static const uint staticData = 0; + static float adds(float a, float b) { return a + b; } + float add(float a, float b) { return a + b; } + }; +} + +typedef float f32; + +f32 add(float a, float b) { return a + b; } + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 1, +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 2, +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "TypeId": 0, +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 3, +// CHECK: "NodeType": "GroupsharedVariable", +// CHECK: "Type": { +// CHECK: "TypeId": 2, +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 16 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 4, +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "TypeId": 0, +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 5, +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "TypeId": 0, +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 6, +// CHECK: "NodeType": "Register", +// CHECK: "Register": { +// CHECK: "RegisterId": 0, +// CHECK: "NodeId": 6, +// CHECK: "RegisterType": "StructuredBuffer" +// CHECK: }, +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 7, +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "TypeId": 3, +// CHECK: "Members": [ +// CHECK: { +// CHECK: "TypeId": 0, +// CHECK: "TypeName": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 8, +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 9, +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "TypeId": 5, +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 10, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 0, +// CHECK: "NodeId": 10, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 14, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 1, +// CHECK: "NodeId": 14, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 18, +// CHECK: "NodeType": "Namespace", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 19, +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "TypeId": 0, +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 20, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 2, +// CHECK: "NodeId": 20, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 24, +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "NodeId": 25, +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "TypeId": 5, +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 26, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 3, +// CHECK: "NodeId": 26, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 30, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 4, +// CHECK: "NodeId": 30, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 34, +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "TypeId": 6, +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "NodeId": 35, +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "FunctionId": 5, +// CHECK: "NodeId": 35, +// CHECK: "Params": { +// CHECK: "0": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: }, +// CHECK: "1": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeId": 6, +// CHECK: "TypeName": "float" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/templates_and_using.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/templates_and_using.hlsl new file mode 100644 index 0000000000..25bfbba4ec --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/templates_and_using.hlsl @@ -0,0 +1,414 @@ +// RUN: %dxreflector %s | FileCheck %s + +//TODO: Expose these to the AST, now they get ignored +// unless they get instantiated in a variable, struct member or function param +// This means you have to be a bit careful when walking the tree +// since some things might be missing. +template +struct ForSomeReasonAVector { + + T data[N]; + + template + void add(ForSomeReasonAVector v) { + for(uint i = 0; i < M && i < N; ++i) + data[i] += v.data[i]; + } +}; + +template +ForSomeReasonAVector pow2(ForSomeReasonAVector v) { + for(uint i = 0; i < M; ++i) + v.data[i] *= v.data[i]; +} + +template +using Test = float[N]; + +//Supported types using a using or template type + +typedef ForSomeReasonAVector F32x4; +typedef ForSomeReasonAVector U32x2; +typedef Test<4> Test4; +typedef Test<2> Test2; + +struct Struct { + ForSomeReasonAVector a; + ForSomeReasonAVector b; + Test<4> c; + Test<2> d; + F32x4 e; + U32x2 f; + Test4 g; + Test2 h; +}; + +ForSomeReasonAVector a; +ForSomeReasonAVector b; +Test<4> c; +Test<2> d; +F32x4 e; +U32x2 f; +Test4 g; +Test2 h; + +void func( + ForSomeReasonAVector a, + ForSomeReasonAVector b, + Test<4> c, + Test<2> d, + F32x4 e, + U32x2 f, + Test4 g, + Test2 h +) { } + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "F32x4", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "U32x2", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "unsigned int", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test4", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Test<4>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test2", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "Test<2>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Struct", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "unsigned int", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test<4>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test<2>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32x4", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "U32x2", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "unsigned int", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "g", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test4", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test2", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "ForSomeReasonAVector", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "unsigned int", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test<4>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test<2>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32x4", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "float", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "U32x2", +// CHECK: "UnderlyingName": "ForSomeReasonAVector", +// CHECK: "Members": [ +// CHECK: { +// CHECK: "Name": "data", +// CHECK: "TypeName": "unsigned int", +// CHECK: "ArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "g", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test4", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "h", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "Test2", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "func", +// CHECK: "NodeType": "Function", +// CHECK: "Function": { +// CHECK: "Params": { +// CHECK: "a": { +// CHECK: "TypeName": "ForSomeReasonAVector" +// CHECK: }, +// CHECK: "b": { +// CHECK: "TypeName": "ForSomeReasonAVector", +// CHECK: "UnderlyingName": "ForSomeReasonAVector" +// CHECK: }, +// CHECK: "c": { +// CHECK: "TypeName": "Test<4>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: }, +// CHECK: "d": { +// CHECK: "TypeName": "Test<2>", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: }, +// CHECK: "e": { +// CHECK: "TypeName": "F32x4", +// CHECK: "UnderlyingName": "ForSomeReasonAVector" +// CHECK: }, +// CHECK: "f": { +// CHECK: "TypeName": "U32x2", +// CHECK: "UnderlyingName": "ForSomeReasonAVector" +// CHECK: }, +// CHECK: "g": { +// CHECK: "TypeName": "Test4", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: }, +// CHECK: "h": { +// CHECK: "TypeName": "Test2", +// CHECK: "UnderlyingName": "float", +// CHECK: "UnderlyingArraySize": [ +// CHECK: 2 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: "ReturnType": { +// CHECK: "TypeName": "void" +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/using_test.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/using_test.hlsl new file mode 100644 index 0000000000..ace6243106 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/using_test.hlsl @@ -0,0 +1,130 @@ +// RUN: %dxreflector %s | FileCheck %s + +using F32 = float; +using F64 = double; + +typedef float F32x; +typedef double F64x; + +using F32a = F32; +typedef F32 F32a2; + +struct Test { + F32 a; + F64 b; + F32x c; + F64x d; + F32a e; + F32a2 f; +}; + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "F32", +// CHECK: "NodeType": "Using", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "F64", +// CHECK: "NodeType": "Using", +// CHECK: "Type": { +// CHECK: "Name": "double" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "F32x", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "F64x", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "double" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "F32a", +// CHECK: "NodeType": "Using", +// CHECK: "Type": { +// CHECK: "Name": "F32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "F32a2", +// CHECK: "NodeType": "Typedef", +// CHECK: "Type": { +// CHECK: "Name": "F32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "a", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "b", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F64", +// CHECK: "UnderlyingName": "double" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "c", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32x", +// CHECK: "UnderlyingName": "float" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "d", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F64x", +// CHECK: "UnderlyingName": "double" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "e", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32a", +// CHECK: "UnderlyingName": "F32" +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "f", +// CHECK: "NodeType": "Variable", +// CHECK: "Type": { +// CHECK: "Name": "F32a2", +// CHECK: "UnderlyingName": "F32" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/test/HLSLFileCheck/dxreflector/variable_types.hlsl b/tools/clang/test/HLSLFileCheck/dxreflector/variable_types.hlsl new file mode 100644 index 0000000000..0b972fe291 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/dxreflector/variable_types.hlsl @@ -0,0 +1,92 @@ +// RUN: %dxreflector %s | FileCheck %s + +groupshared uint groupData[16]; +static const uint staticData[4] = { 0, 1, 2, 3 }; + +struct Test { + static const uint staticData = 0; +}; + +namespace tst { + + static const uint staticData[4] = { 0, 1, 2, 3 }; + + struct Test { + static const uint staticData = 0; + }; +} + +// CHECK: { +// CHECK: "Features": [ +// CHECK: "Basics", +// CHECK: "Functions", +// CHECK: "Namespaces", +// CHECK: "UserTypes", +// CHECK: "Scopes", +// CHECK: "Symbols" +// CHECK: ], +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "groupData", +// CHECK: "NodeType": "GroupsharedVariable", +// CHECK: "Type": { +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 16 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "staticData", +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "staticData", +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: }, +// CHECK: { +// CHECK: "Name": "tst", +// CHECK: "NodeType": "Namespace", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "staticData", +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "Name": "uint", +// CHECK: "ArraySize": [ +// CHECK: 4 +// CHECK: ] +// CHECK: } +// CHECK: }, +// CHECK: { +// CHECK: "Name": "Test", +// CHECK: "NodeType": "Struct", +// CHECK: "Children": [ +// CHECK: { +// CHECK: "Name": "staticData", +// CHECK: "NodeType": "StaticVariable", +// CHECK: "Type": { +// CHECK: "Name": "uint" +// CHECK: } +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: } diff --git a/tools/clang/tools/CMakeLists.txt b/tools/clang/tools/CMakeLists.txt index 9991de0308..b54efd7f45 100644 --- a/tools/clang/tools/CMakeLists.txt +++ b/tools/clang/tools/CMakeLists.txt @@ -4,6 +4,8 @@ add_subdirectory(driver) # add_subdirectory(clang-fuzzer) # HLSL Change # add_subdirectory(c-index-test) # HLSL Change +add_subdirectory(dxcreflectioncontainer) # HLSL Change +add_subdirectory(dxcreflection) # HLSL Change add_subdirectory(libclang) if(0 AND CLANG_ENABLE_ARCMT) # HLSL Change @@ -32,6 +34,7 @@ add_subdirectory(dxa) add_subdirectory(dxopt) add_subdirectory(dxl) add_subdirectory(dxr) +add_subdirectory(dxreflector) add_subdirectory(dxv) # These targets can currently only be built on Windows. diff --git a/tools/clang/tools/dxcompiler/dxcapi.cpp b/tools/clang/tools/dxcompiler/dxcapi.cpp index d4e85bc35c..e298ed8494 100644 --- a/tools/clang/tools/dxcompiler/dxcapi.cpp +++ b/tools/clang/tools/dxcompiler/dxcapi.cpp @@ -21,6 +21,7 @@ #include "dxc/config.h" #include "dxc/dxcisense.h" #include "dxc/dxctools.h" +#include "dxc/dxcreflect.h" #ifdef _WIN32 #include "dxcetw.h" #endif @@ -33,6 +34,7 @@ HRESULT CreateDxcIntelliSense(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcCompilerArgs(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcUtils(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcRewriter(REFIID riid, _Out_ LPVOID *ppv); +HRESULT CreateDxcReflector(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcValidator(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcAssembler(REFIID riid, _Out_ LPVOID *ppv); HRESULT CreateDxcOptimizer(REFIID riid, _Out_ LPVOID *ppv); @@ -92,6 +94,8 @@ static HRESULT ThreadMallocDxcCreateInstance(REFCLSID rclsid, REFIID riid, hr = CreateDxcPdbUtils(riid, ppv); } else if (IsEqualCLSID(rclsid, CLSID_DxcRewriter)) { hr = CreateDxcRewriter(riid, ppv); + } else if (IsEqualCLSID(rclsid, CLSID_DxcReflector)) { + hr = CreateDxcReflector(riid, ppv); } else if (IsEqualCLSID(rclsid, CLSID_DxcLinker)) { hr = CreateDxcLinker(riid, ppv); } diff --git a/tools/clang/tools/dxcreflection/CMakeLists.txt b/tools/clang/tools/dxcreflection/CMakeLists.txt new file mode 100644 index 0000000000..f9bc1ea44d --- /dev/null +++ b/tools/clang/tools/dxcreflection/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (C) Microsoft Corporation. All rights reserved. +# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. + +set(LIBRARIES + clangFrontend + clangAST + clangBasic + clangLex + ) + +add_clang_library(dxcreflection STATIC + dxcreflector.cpp + dxcreflection_from_ast.cpp) + +target_link_libraries(dxcreflection PRIVATE ${LIBRARIES} dxcreflectioncontainer) + +if(MSVC) + target_compile_options(dxcreflection PRIVATE /W4 /WX) +else() + target_compile_options(dxcreflection PRIVATE -Wall -Wextra -Werror -Wno-pedantic) +endif() diff --git a/tools/clang/tools/dxcreflection/dxcreflection_from_ast.cpp b/tools/clang/tools/dxcreflection/dxcreflection_from_ast.cpp new file mode 100644 index 0000000000..23c00a874d --- /dev/null +++ b/tools/clang/tools/dxcreflection/dxcreflection_from_ast.cpp @@ -0,0 +1,2437 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxreflection_from_ast.cpp // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Handles walking the AST and turning it into a reflection object. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/HlslTypes.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" + +#include "dxc/DxcReflection/DxcReflectionContainer.h" + +using namespace clang; + +namespace hlsl { + +// DxilInterpolationMode.cpp but a little bit cleaned up +static D3D_INTERPOLATION_MODE GetInterpolationMode(const Decl *decl) { + + if (!decl) // Return type + return D3D_INTERPOLATION_UNDEFINED; + + bool bNoInterpolation = decl->hasAttr(); + bool bLinear = decl->hasAttr(); + bool bNoperspective = decl->hasAttr(); + bool bCentroid = decl->hasAttr(); + bool bSample = decl->hasAttr(); + + uint8_t mask = uint8_t(bNoInterpolation) << 4; + mask |= uint8_t(bLinear) << 3; + mask |= uint8_t(bNoperspective) << 2; + mask |= uint8_t(bCentroid) << 1; + mask |= uint8_t(bSample); + + if (mask > 16) + return D3D_INTERPOLATION_UNDEFINED; + + static constexpr const D3D_INTERPOLATION_MODE modes[] = { + D3D_INTERPOLATION_UNDEFINED, + D3D_INTERPOLATION_LINEAR_SAMPLE, + D3D_INTERPOLATION_LINEAR_CENTROID, + D3D_INTERPOLATION_LINEAR_SAMPLE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, + D3D_INTERPOLATION_LINEAR, + D3D_INTERPOLATION_LINEAR_SAMPLE, + D3D_INTERPOLATION_LINEAR_CENTROID, + D3D_INTERPOLATION_LINEAR_SAMPLE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, + D3D_INTERPOLATION_CONSTANT}; + + return modes[mask]; +} + +[[nodiscard]] static ReflectionError +PushNextNodeId(uint32_t &NodeId, ReflectionData &Refl, const SourceManager &SM, + const LangOptions &LangOpts, const std::string &UnqualifiedName, + const Decl *DeclSelf, D3D12_HLSL_NODE_TYPE Type, + uint32_t ParentNodeId, uint32_t LocalId, + const SourceRange *Range = nullptr, + std::unordered_map *FwdDecls = nullptr) { + + if (Refl.Nodes.size() >= (1u << 24)) + return HLSL_REFL_ERR("Nodes overflow"); + + if (LocalId >= (1u << 24)) + return HLSL_REFL_ERR("LocalId overflow"); + + bool isFwdDeclare = false; + bool canHaveFwdDeclare = false; + const Decl *fwdDeclare = nullptr; + + if (DeclSelf) { + + if (const FunctionDecl *func = dyn_cast(DeclSelf)) { + isFwdDeclare = !func->doesThisDeclarationHaveABody(); + fwdDeclare = func->getCanonicalDecl(); + canHaveFwdDeclare = true; + } + + else if (const EnumDecl *enm = dyn_cast(DeclSelf)) { + isFwdDeclare = !enm->isCompleteDefinition(); + fwdDeclare = enm->getCanonicalDecl(); + canHaveFwdDeclare = true; + } + + else if (const RecordDecl *rec = dyn_cast(DeclSelf)) { + + isFwdDeclare = !rec->isThisDeclarationADefinition(); + fwdDeclare = rec->getCanonicalDecl(); + canHaveFwdDeclare = true; + + if (isFwdDeclare && rec->isImplicit()) { // Inner ghost node + NodeId = uint32_t(-1); + return ReflectionErrorSuccess; + } + } + } + + //There is a forward declare, but we haven't seen it before. + //This happens for example if we have a fwd func declare in a struct, but define it in global namespace. + //(only) -reflect-function will hide this struct from us, but will still find a function in the global scope. + //This fixes that problem. + + if (!isFwdDeclare && fwdDeclare && fwdDeclare != DeclSelf && + FwdDecls->find(fwdDeclare) == FwdDecls->end()) { + NodeId = uint32_t(-1); + return ReflectionErrorSuccess; + } + + uint32_t nodeId = Refl.Nodes.size(); + + uint16_t annotationStart = uint16_t(Refl.Annotations.size()); + uint8_t annotationCount = 0; + + uint16_t semanticId = uint16_t(-1); + + if (DeclSelf) { + for (const Attr *attr : DeclSelf->attrs()) { + if (const AnnotateAttr *annotate = dyn_cast(attr)) { + + if (Refl.Annotations.size() >= (1u << 16)) + return HLSL_REFL_ERR("Out of annotations"); + + Refl.Annotations.push_back({}); + + uint32_t stringId; + + if (ReflectionError err = Refl.RegisterString( + stringId, annotate->getAnnotation().str(), true)) + return err; + + if (ReflectionError err = ReflectionAnnotation::Initialize( + Refl.Annotations.back(), stringId, false)) + return err; + + if (annotationCount >= uint8_t(-1)) + return HLSL_REFL_ERR("Annotation count out of bounds"); + + ++annotationCount; + + } else if (const HLSLShaderAttr *shaderAttr = + dyn_cast(attr)) { + + if (Refl.Annotations.size() >= (1u << 16)) + return HLSL_REFL_ERR("Out of annotations"); + + Refl.Annotations.push_back({}); + + uint32_t stringId; + + if (ReflectionError err = Refl.RegisterString( + stringId, "shader(\"" + shaderAttr->getStage().str() + "\")", + true)) + return err; + + if (ReflectionError err = ReflectionAnnotation::Initialize( + Refl.Annotations.back(), stringId, true)) + return err; + + if (annotationCount >= uint8_t(-1)) + return HLSL_REFL_ERR("Annotation count out of bounds"); + + ++annotationCount; + } + + // TODO: Other types of attrs + } + + if (const ValueDecl *valDecl = dyn_cast(DeclSelf)) { + + const ArrayRef &UA = + valDecl->getUnusualAnnotations(); + + for (auto It = UA.begin(), E = UA.end(); It != E; ++It) + if ((*It)->getKind() == hlsl::UnusualAnnotation::UA_SemanticDecl) { + + uint32_t semanticId32; + + if (ReflectionError err = Refl.RegisterString( + semanticId32, + cast(*It)->SemanticName.str(), true)) + return err; + + semanticId = uint16_t(semanticId32); + break; + } + } + } + + D3D_INTERPOLATION_MODE interpolationMode = GetInterpolationMode(DeclSelf); + + uint32_t currId = uint32_t(Refl.Nodes.size()); + + if (canHaveFwdDeclare) { + + assert(FwdDecls && "Fwd decl requires FwdDecls map to be present"); + + // Multiple fwd declare, ignore + if (isFwdDeclare && FwdDecls->find(fwdDeclare) != FwdDecls->end()) { + NodeId = uint32_t(-1); + return ReflectionErrorSuccess; + } + + if (isFwdDeclare) + (*FwdDecls)[fwdDeclare] = currId; + } + + Refl.Nodes.push_back({}); + if (ReflectionError err = ReflectionNode::Initialize( + Refl.Nodes.back(), Type, isFwdDeclare, LocalId, annotationStart, 0, + ParentNodeId, annotationCount, semanticId, interpolationMode)) + return err; + + if (Refl.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) { + + uint16_t sourceLineCount = 0; + uint32_t sourceLineStart = 0; + uint32_t sourceColumnStart = 0; + uint32_t sourceColumnEnd = 0; + + uint16_t sourceId = uint16_t(-1); + + SourceRange range = DeclSelf ? DeclSelf->getSourceRange() + : (Range ? *Range : SourceRange()); + + SourceLocation start = range.getBegin(); + SourceLocation end = range.getEnd(); + + if (start.isValid() && end.isValid()) { + + PresumedLoc presumed = SM.getPresumedLoc(start); + + SourceLocation realEnd = SM.getFileLoc(end); + SourceLocation endOfToken = + Lexer::getLocForEndOfToken(realEnd, 0, SM, LangOpts); + PresumedLoc presumedEnd = SM.getPresumedLoc(endOfToken); + + if (presumed.isValid() && presumedEnd.isValid()) { + + uint32_t startLine = presumed.getLine(); + uint32_t startCol = presumed.getColumn(); + uint32_t endLine = presumedEnd.getLine(); + uint32_t endCol = presumedEnd.getColumn(); + + std::string fileName = presumed.getFilename(); + + if (fileName != presumedEnd.getFilename()) + return HLSL_REFL_ERR("End and start are not in the same file"); + + auto it = Refl.StringToSourceId.find(fileName); + uint32_t i; + + if (it == Refl.StringToSourceId.end()) { + + i = uint32_t(Refl.Sources.size()); + uint32_t stringId; + + if (ReflectionError err = + Refl.RegisterString(stringId, fileName, false)) + return err; + + Refl.Sources.push_back(stringId); + Refl.StringToSourceId[fileName] = i; + } + + else { + i = it->second; + } + + if (i >= 65535) + return HLSL_REFL_ERR("Source file count is limited to 16-bit"); + + if ((endLine - startLine) >= 65535) + return HLSL_REFL_ERR("Source line count is limited to 16-bit"); + + if (startLine >= 1048576) + return HLSL_REFL_ERR("Source line start is limited to 20-bit"); + + if (startCol >= (1u << 22)) + return HLSL_REFL_ERR("Column start is limited to 22-bit"); + + if (endCol >= (1u << 22)) + return HLSL_REFL_ERR("Column end is limited to 22-bit"); + + sourceLineCount = uint16_t(endLine - startLine + 1); + sourceLineStart = startLine; + sourceColumnStart = startCol; + sourceColumnEnd = endCol; + sourceId = uint16_t(i); + } + } + + uint32_t nameId; + + if (ReflectionError err = + Refl.RegisterString(nameId, UnqualifiedName, false)) + return err; + + Refl.NodeSymbols.push_back({}); + + if (ReflectionError err = ReflectionNodeSymbol::Initialize( + Refl.NodeSymbols.back(), nameId, sourceId, sourceLineCount, + sourceLineStart, sourceColumnStart, sourceColumnEnd)) + return err; + } + + // Link + + if (DeclSelf && fwdDeclare != DeclSelf && fwdDeclare && !isFwdDeclare) { + assert(FwdDecls && + "Referencing fwd decl requires FwdDecls map to be present"); + uint32_t fwd = (*FwdDecls)[fwdDeclare]; + + if (ReflectionError err = + Refl.Nodes[fwd].ResolveFwdDeclare(fwd, Refl.Nodes[currId], currId)) + return err; + } + + uint32_t parentParent = ParentNodeId; + + while (parentParent != 0) { + + ReflectionNode &parent = Refl.Nodes[parentParent]; + + if (ReflectionError err = parent.IncreaseChildCount()) + return err; + + parentParent = parent.GetParentId(); + } + + if (ReflectionError err = Refl.Nodes[0].IncreaseChildCount()) + return err; + + NodeId = nodeId; + return ReflectionErrorSuccess; +} + +struct DxcRegisterTypeInfo { + D3D_SHADER_INPUT_TYPE RegisterType; + D3D_SHADER_INPUT_FLAGS RegisterFlags; + D3D_SRV_DIMENSION TextureDimension; + D3D_RESOURCE_RETURN_TYPE TextureValue; +}; + +static DxcRegisterTypeInfo +GetTextureRegisterInfo(ASTContext &ASTCtx, std::string TypeName, bool IsWrite, + const CXXRecordDecl *RecordDecl) { + + DxcRegisterTypeInfo type = {}; + type.RegisterType = IsWrite ? D3D_SIT_UAV_RWTYPED : D3D_SIT_TEXTURE; + + // Parse return type and dimensions + + const ClassTemplateSpecializationDecl *textureTemplate = + dyn_cast(RecordDecl); + + assert(textureTemplate && "Expected texture template"); + + const ArrayRef &textureParams = + textureTemplate->getTemplateArgs().asArray(); + + bool shouldBeTexture2DMS = textureParams.size() == 2; + + if (shouldBeTexture2DMS) + assert(textureParams[0].getKind() == TemplateArgument::Type && + textureParams[1].getKind() == TemplateArgument::Integral && + "Expected template args"); + + else + assert(textureParams.size() == 1 && + textureParams[0].getKind() == TemplateArgument::Type && + "Expected template args"); + + QualType valueType = textureParams[0].getAsType(); + QualType desugared = valueType.getDesugaredType(ASTCtx); + + uint32_t dimensions; + + if (isa(desugared)) + dimensions = 1; + + else { + + const RecordType *RT = desugared->getAs(); + assert(RT && "Expected record type"); + + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + assert(RT && "Expected record decl"); + + const ClassTemplateSpecializationDecl *vectorType = + dyn_cast(RD); + + assert(vectorType && + "Expected vector type as template inside of texture template"); + + const ArrayRef &vectorParams = + vectorType->getTemplateArgs().asArray(); + + assert(vectorParams.size() == 2 && + vectorParams[0].getKind() == TemplateArgument::Type && + vectorParams[1].getKind() == TemplateArgument::Integral && + "Expected vector to be vector"); + + valueType = vectorParams[0].getAsType(); + desugared = valueType.getDesugaredType(ASTCtx); + + dimensions = vectorParams[1].getAsIntegral().getZExtValue(); + } + + if (desugared->isFloatingType()) { + type.TextureValue = desugared->isSpecificBuiltinType(BuiltinType::Double) + ? D3D_RETURN_TYPE_DOUBLE + : D3D_RETURN_TYPE_FLOAT; + } else if (desugared->isIntegerType()) { + const auto &semantics = ASTCtx.getTypeInfo(desugared); + if (semantics.Width == 64) { + type.TextureValue = D3D_RETURN_TYPE_MIXED; + } else { + type.TextureValue = desugared->isUnsignedIntegerType() + ? D3D_RETURN_TYPE_UINT + : D3D_RETURN_TYPE_SINT; + } + } + + else { + type.TextureValue = D3D_RETURN_TYPE_MIXED; + } + + switch (dimensions) { + case 2: + type.RegisterFlags = (D3D_SHADER_INPUT_FLAGS)D3D_SIF_TEXTURE_COMPONENT_0; + break; + case 3: + type.RegisterFlags = (D3D_SHADER_INPUT_FLAGS)D3D_SIF_TEXTURE_COMPONENT_1; + break; + case 4: + type.RegisterFlags = (D3D_SHADER_INPUT_FLAGS)D3D_SIF_TEXTURE_COMPONENTS; + break; + } + + // Parse type + + if (TypeName == "Buffer") { + assert(!shouldBeTexture2DMS && "Buffer expected but got Buffer"); + type.TextureDimension = D3D_SRV_DIMENSION_BUFFER; + return type; + } + + bool isFeedback = false; + + if (TypeName.size() > 8 && TypeName.substr(0, 8) == "Feedback") { + isFeedback = true; + TypeName = TypeName.substr(8); + type.RegisterType = D3D_SIT_UAV_FEEDBACKTEXTURE; + } + + bool isArray = false; + + if (TypeName.size() > 5 && TypeName.substr(TypeName.size() - 5) == "Array") { + isArray = true; + TypeName = TypeName.substr(0, TypeName.size() - 5); + } + + if (TypeName == "Texture2D") + type.TextureDimension = D3D_SRV_DIMENSION_TEXTURE2D; + + else if (TypeName == "TextureCube") + type.TextureDimension = D3D_SRV_DIMENSION_TEXTURECUBE; + + else if (TypeName == "Texture3D") + type.TextureDimension = D3D_SRV_DIMENSION_TEXTURE3D; + + else if (TypeName == "Texture1D") + type.TextureDimension = D3D_SRV_DIMENSION_TEXTURE1D; + + else if (TypeName == "Texture2DMS") + type.TextureDimension = D3D_SRV_DIMENSION_TEXTURE2DMS; + + assert((shouldBeTexture2DMS == + (type.TextureDimension == D3D_SRV_DIMENSION_TEXTURE2DMS)) && + "Texture2DMS used with Texture2D syntax or reverse"); + + if (isArray) // Arrays are always 1 behind the regular type + type.TextureDimension = (D3D_SRV_DIMENSION)(type.TextureDimension + 1); + + return type; +} + +static DxcRegisterTypeInfo GetRegisterTypeInfo(ASTContext &ASTCtx, + QualType Type) { + + QualType realType = Type.getDesugaredType(ASTCtx); + const RecordType *RT = realType->getAs(); + assert(RT && "GetRegisterTypeInfo() type is not a RecordType"); + + const CXXRecordDecl *recordDecl = RT->getAsCXXRecordDecl(); + assert(recordDecl && "GetRegisterTypeInfo() type is not a CXXRecordDecl"); + + std::string typeName = recordDecl->getNameAsString(); + + if (typeName.size() >= 17 && typeName.substr(0, 17) == "RasterizerOrdered") + typeName = typeName.substr(17); + + if (typeName == "SamplerState" || typeName == "SamplerComparisonState") { + return {D3D_SIT_SAMPLER, typeName == "SamplerComparisonState" + ? D3D_SIF_COMPARISON_SAMPLER + : (D3D_SHADER_INPUT_FLAGS)0}; + } + + DxcRegisterTypeInfo info = {}; + + if (typeName == "AppendStructuredBuffer") { + info.RegisterType = D3D_SIT_UAV_APPEND_STRUCTURED; + return info; + } + + if (typeName == "ConsumeStructuredBuffer") { + info.RegisterType = D3D_SIT_UAV_CONSUME_STRUCTURED; + return info; + } + + if (typeName == "RaytracingAccelerationStructure") { + info.RegisterType = D3D_SIT_RTACCELERATIONSTRUCTURE; + return info; + } + + if (typeName == "TextureBuffer") { + info.RegisterType = D3D_SIT_TBUFFER; + return info; + } + + if (typeName == "ConstantBuffer") { + info.RegisterType = D3D_SIT_CBUFFER; + return info; + } + + bool isWrite = + typeName.size() > 2 && typeName[0] == 'R' && typeName[1] == 'W'; + + if (isWrite) + typeName = typeName.substr(2); + + if (typeName == "StructuredBuffer") { + info.RegisterType = isWrite ? D3D_SIT_UAV_RWSTRUCTURED : D3D_SIT_STRUCTURED; + return info; + } + + if (typeName == "ByteAddressBuffer") { + info.RegisterType = + isWrite ? D3D_SIT_UAV_RWBYTEADDRESS : D3D_SIT_BYTEADDRESS; + return info; + } + + return GetTextureRegisterInfo(ASTCtx, typeName, isWrite, recordDecl); +} + +// Collect array sizes in the logical order (inner dims first, then outer). +// Example: +// F32[4][3] -> {4, 3} +// typedef T = F32[4][3]; +// T[2] -> {4, 3, 2} +[[nodiscard]] static ReflectionError +CollectUnderlyingArraySizes(QualType &T, std::vector &Out, + uint64_t &FlatSize) { + + T = T.getNonReferenceType(); + + std::vector local; + + while (const ConstantArrayType *arr = dyn_cast(T)) { + + uint64_t siz = arr->getSize().getZExtValue(); + FlatSize *= siz; + + if ((FlatSize >> 32) || (siz >> 32)) + return HLSL_REFL_ERR("Can't calculate flat array size: out of bits"); + + local.push_back(uint32_t(siz)); + T = arr->getElementType().getNonReferenceType(); + } + + if (const TypedefType *td = dyn_cast(T)) { + + T = td->getDecl()->getUnderlyingType().getNonReferenceType(); + + if (T->isArrayType()) + if (ReflectionError err = CollectUnderlyingArraySizes(T, Out, FlatSize)) + return err; + } + + if (const TemplateSpecializationType *ts = + dyn_cast(T)) { + QualType desugared = ts->desugar().getNonReferenceType(); + if (desugared != T) { + T = desugared; + if (ReflectionError err = CollectUnderlyingArraySizes(T, Out, FlatSize)) + return err; + } + } + + Out.insert(Out.end(), local.begin(), local.end()); + return ReflectionErrorSuccess; +} + +[[nodiscard]] ReflectionError +GenerateTypeInfo(uint32_t &TypeId, ASTContext &ASTCtx, ReflectionData &Refl, + QualType Original, bool DefaultRowMaj) { + + // Unwrap array + // There's the following issue: + // Let's say the underlying type is F32x4[4] but the sugared name is F32x4x4, + // then we want to maintain sugared name + array info (of sugar) for + // reflection but for low level type info, we would want to know float4[4] + + uint64_t arraySizeUnderlying = 1; + std::vector arrayElemUnderlying; + + QualType underlying = Original; + if (ReflectionError err = CollectUnderlyingArraySizes( + underlying, arrayElemUnderlying, arraySizeUnderlying)) + return err; + + uint32_t arraySizeDisplay = 1; + std::vector arrayElemDisplay; + QualType display = Original.getNonReferenceType(); + + while (const ConstantArrayType *arr = dyn_cast(display)) { + uint32_t current = arr->getSize().getZExtValue(); + arrayElemDisplay.push_back(current); + arraySizeDisplay *= arr->getSize().getZExtValue(); + display = arr->getElementType().getNonReferenceType(); + } + + // Unwrap enum in underlying to still treat it as a uint/int/etc. + + if (const EnumType *enumTy = dyn_cast(underlying)) { + + const EnumDecl *decl = enumTy->getDecl(); + + if (decl && !decl->getIntegerType().isNull()) + underlying = + decl->getIntegerType().getNonReferenceType().getCanonicalType(); + + else + underlying = ASTCtx.IntTy; + } + + // Name; Omit struct, class and const keywords + + PrintingPolicy policy(ASTCtx.getLangOpts()); + policy.SuppressScope = false; + policy.AnonymousTagLocations = false; + policy.SuppressTagKeyword = true; + + display = display.getUnqualifiedType(); + std::string displayName = display.getAsString(policy); + + std::string underlyingName = + underlying.getUnqualifiedType().getAsString(policy); + + // Prune template instantiation from type name for builtin types (ex. vector & + // matrix) But only if it's not a sugared type: + // typedef ConstantBuffer MyTest; + // In this case, MyTest will still be seen as a ConstantBuffer but the + // typeName is MyTest. + + static const std::unordered_map + lookup = std::unordered_map{ + {{"vector", D3D_SHADER_VARIABLE_TYPE(-1)}, + {"matrix", D3D_SHADER_VARIABLE_TYPE(-2)}, + {"Texture1D", D3D_SVT_TEXTURE1D}, + {"Texture2D", D3D_SVT_TEXTURE2D}, + {"RWTexture1D", D3D_SVT_RWTEXTURE1D}, + {"RWTexture2D", D3D_SVT_RWTEXTURE2D}, + {"Texture2DMS", D3D_SVT_TEXTURE2DMS}, + {"Texture3D", D3D_SVT_TEXTURE3D}, + {"RWTexture3D", D3D_SVT_RWTEXTURE3D}, + {"TextureCube", D3D_SVT_TEXTURECUBE}, + {"Texture1DArray", D3D_SVT_TEXTURE1DARRAY}, + {"Texture2DArray", D3D_SVT_TEXTURE2DARRAY}, + {"RWTexture1DArray", D3D_SVT_RWTEXTURE1DARRAY}, + {"RWTexture2DArray", D3D_SVT_RWTEXTURE2DARRAY}, + {"Texture2DMSArray", D3D_SVT_TEXTURE2DMSARRAY}, + {"TextureCubeArray", D3D_SVT_TEXTURECUBEARRAY}, + {"SamplerState", D3D_SVT_SAMPLER}, + {"ByteAddressBuffer", D3D_SVT_BYTEADDRESS_BUFFER}, + {"RWByteAddressBuffer", D3D_SVT_RWBYTEADDRESS_BUFFER}, + {"StructuredBuffer", D3D_SVT_STRUCTURED_BUFFER}, + {"RWStructuredBuffer", D3D_SVT_RWSTRUCTURED_BUFFER}, + {"AppendStructuredBuffer", D3D_SVT_APPEND_STRUCTURED_BUFFER}, + {"ConsumeStructuredBuffer", D3D_SVT_CONSUME_STRUCTURED_BUFFER}, + {"RWBuffer", D3D_SVT_RWBUFFER}, + {"Buffer", D3D_SVT_BUFFER}, + {"ConstantBuffer", D3D_SVT_CBUFFER}}}; + + if (const TemplateSpecializationType *spec = + dyn_cast(display.getTypePtr())) { + + const TemplateDecl *td = spec->getTemplateName().getAsTemplateDecl(); + + if (td) { + + auto it = lookup.find(td->getName()); + + if (it != lookup.end()) { + + if (it->second >= 0) + displayName = underlyingName = it->first; + } + } + } + + bool hasSymbols = Refl.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + // Two arrays; for display and for underlying + + uint32_t arrayIdUnderlying; + + if (ReflectionError err = Refl.PushArray( + arrayIdUnderlying, arraySizeUnderlying, arrayElemUnderlying)) + return err; + + ReflectionArrayOrElements elementsOrArrayIdUnderlying(arrayIdUnderlying, + arraySizeUnderlying); + + uint32_t arrayIdDisplay; + if (ReflectionError err = + Refl.PushArray(arrayIdDisplay, arraySizeDisplay, arrayElemDisplay)) + return err; + + ReflectionArrayOrElements elementsOrArrayIdDisplay(arrayIdDisplay, + arraySizeDisplay); + + // Unwrap vector and matrix + // And base type + + D3D_SHADER_VARIABLE_CLASS cls = D3D_SVC_STRUCT; + + if (const RecordType *RT = underlying->getAs()) { + + const RecordDecl *RD = RT->getDecl(); + + if (RD->getTagKind() == TTK_Interface) + cls = D3D_SVC_INTERFACE_CLASS; + } + + uint8_t rows = 0, columns = 0; + + uint32_t membersCount = 0; + uint32_t membersOffset = 0; + + uint32_t baseType = uint32_t(-1); + std::vector interfaces; + + D3D_SHADER_VARIABLE_TYPE type = D3D_SVT_VOID; + + if (const RecordType *record = underlying->getAs()) { + + bool standardType = false; + + RecordDecl *recordDecl = record->getDecl(); + + QualType innerType; + std::string innerTypeName; //$Element or T depending on type + + if (const ClassTemplateSpecializationDecl *templateClass = + dyn_cast(recordDecl)) { + + std::string name = templateClass->getIdentifier()->getName(); + + const ArrayRef ¶ms = + templateClass->getTemplateArgs().asArray(); + + auto it = lookup.find(name); + + if (it != lookup.end()) { + + D3D_SHADER_VARIABLE_TYPE svt = it->second; + + if (svt == -1) { // Reserved as 'vector' + + rows = 1; + + assert(params.size() == 2 && + params[0].getKind() == TemplateArgument::Type && + params[1].getKind() == TemplateArgument::Integral && + "Expected vector to be vector"); + + underlying = params[0].getAsType(); + columns = params[1].getAsIntegral().getSExtValue(); + cls = D3D_SVC_VECTOR; + standardType = true; + } + + else if (svt == -2) { // Reserved as 'matrix' + + assert(params.size() == 3 && + params[0].getKind() == TemplateArgument::Type && + params[1].getKind() == TemplateArgument::Integral && + params[2].getKind() == TemplateArgument::Integral && + "Expected matrix to be matrix"); + + underlying = params[0].getAsType(); + columns = params[1].getAsIntegral().getSExtValue(); + rows = params[2].getAsIntegral().getSExtValue(); + + bool isRowMajor = DefaultRowMaj; + + HasHLSLMatOrientation(Original, &isRowMajor); + + if (!isRowMajor) + std::swap(rows, columns); + + cls = isRowMajor ? D3D_SVC_MATRIX_ROWS : D3D_SVC_MATRIX_COLUMNS; + standardType = true; + } + + else { + + type = svt; + cls = D3D_SVC_OBJECT; + underlyingName = name; + + innerTypeName = "$Element"; + + const TemplateSpecializationType *templateDesc = + display->getAs(); + + // Case 1: T = StructuredBuffer then underlying has a type, but + // sugared doesn't. Loses syntax sugar, but will still be correct. + + bool useUnderlying = !templateDesc; + + // Case 2: TextureCube = TextureCube + + if (templateDesc && displayName == underlyingName && + !templateDesc->getNumArgs()) + useUnderlying = true; + + if (useUnderlying) { + + assert(params.size() && + "Expected a TemplateSpecializationType with > 0 args"); + + innerType = params[0].getAsType(); + + if (svt == D3D_SVT_RWBUFFER || svt == D3D_SVT_BUFFER || + svt == D3D_SVT_CBUFFER) + innerTypeName = + innerType.getUnqualifiedType().getAsString(policy); + + } else { + + assert(templateDesc && + "Expected a valid TemplateSpecializationType"); + assert(templateDesc->getNumArgs() && + "Expected a TemplateSpecializationType with > 0 args"); + + innerType = templateDesc->getArg(0).getAsType(); + + if (svt == D3D_SVT_RWBUFFER || svt == D3D_SVT_BUFFER || + svt == D3D_SVT_CBUFFER) + innerTypeName = + innerType.getUnqualifiedType().getAsString(policy); + } + } + } + } + + else { + + std::string name = recordDecl->getName(); + + auto it = lookup.find(name); + + if (it != lookup.end()) { + type = it->second; + cls = D3D_SVC_OBJECT; + } + } + + // Buffer types have a member to allow inspection of the types + + if (innerTypeName.size()) { + + uint32_t nameId = uint32_t(-1); + + if (hasSymbols) + if (ReflectionError err = + Refl.RegisterString(nameId, innerTypeName, false)) + return err; + + uint32_t typeId; + + if (ReflectionError err = + GenerateTypeInfo(typeId, ASTCtx, Refl, innerType, DefaultRowMaj)) + return err; + + membersOffset = uint32_t(Refl.MemberTypeIds.size()); + membersCount = 1; + + Refl.MemberTypeIds.push_back(typeId); + + if (hasSymbols) + Refl.MemberNameIds.push_back(nameId); + } + + // Fill members + + if (!standardType && recordDecl->isCompleteDefinition() && + cls != D3D_SVC_OBJECT) { + + // Base types + + if (CXXRecordDecl *cxxRecordDecl = dyn_cast(recordDecl)) + if (cxxRecordDecl->getNumBases()) { + for (auto &I : cxxRecordDecl->bases()) { + + QualType qualType = I.getType(); + CXXRecordDecl *BaseDecl = + cast(qualType->castAs()->getDecl()); + + if (BaseDecl->isInterface()) { + + uint32_t interfaceId; + + if (ReflectionError err = GenerateTypeInfo( + interfaceId, ASTCtx, Refl, qualType, DefaultRowMaj)) + return err; + + interfaces.push_back(interfaceId); + continue; + } + + assert(baseType == uint32_t(-1) && + "Multiple base types isn't supported in HLSL"); + + if (ReflectionError err = GenerateTypeInfo(baseType, ASTCtx, Refl, + qualType, DefaultRowMaj)) + return err; + } + } + + // Inner types + + // Reserve member names and types + + for (Decl *decl : recordDecl->decls()) { + + FieldDecl *fieldDecl = dyn_cast(decl); + + if (!fieldDecl) + continue; + + if (!membersCount) + membersOffset = uint32_t(Refl.MemberTypeIds.size()); + + std::string name = fieldDecl->getName(); + + uint32_t nameId = uint32_t(-1); + + if (hasSymbols) { + + if (ReflectionError err = Refl.RegisterString(nameId, name, false)) + return err; + + Refl.MemberNameIds.push_back(nameId); + } + + ++membersCount; + } + + if (membersCount) { + + Refl.MemberTypeIds.resize(Refl.MemberTypeIds.size() + membersCount); + + if (Refl.MemberTypeIds.size() >= uint32_t(1u << 24)) + return HLSL_REFL_ERR("Members out of bounds"); + } + + // Initialize member types (because it causes recursion) + + membersCount = 0; + + for (Decl *decl : recordDecl->decls()) { + + FieldDecl *fieldDecl = dyn_cast(decl); + + if (!fieldDecl) + continue; + + uint32_t memberTypeId; + if (ReflectionError err = + GenerateTypeInfo(memberTypeId, ASTCtx, Refl, + fieldDecl->getType(), DefaultRowMaj)) + return err; + + Refl.MemberTypeIds[membersOffset + membersCount] = memberTypeId; + + ++membersCount; + } + } + } + + // Type name + + if (const BuiltinType *bt = dyn_cast(underlying)) { + + if (!rows) + rows = columns = 1; + + if (cls == D3D_SVC_STRUCT) + cls = D3D_SVC_SCALAR; + + switch (bt->getKind()) { + + case BuiltinType::Void: + type = D3D_SVT_VOID; + break; + + case BuiltinType::Min10Float: + type = D3D_SVT_MIN10FLOAT; + underlyingName = "min10float"; + break; + + case BuiltinType::Min16Float: + type = D3D_SVT_MIN16FLOAT; + underlyingName = "min16float"; + break; + + case BuiltinType::HalfFloat: + case BuiltinType::Half: + type = D3D_SVT_FLOAT16; + underlyingName = "float16_t"; // TODO: half or float16_t? + break; + + case BuiltinType::Short: + type = D3D_SVT_INT16; + underlyingName = "int16_t"; + break; + + case BuiltinType::Min12Int: + type = D3D_SVT_MIN12INT; + underlyingName = "min12int"; + break; + + case BuiltinType::Min16Int: + type = D3D_SVT_MIN16INT; + underlyingName = "min16int"; + break; + + case BuiltinType::Min16UInt: + type = D3D_SVT_MIN16UINT; + underlyingName = "min16uint"; + break; + + case BuiltinType::UShort: + type = D3D_SVT_UINT16; + underlyingName = "uint16_t"; + break; + + case BuiltinType::Float: + type = D3D_SVT_FLOAT; + underlyingName = "float"; + break; + + case BuiltinType::Int: + type = D3D_SVT_INT; + underlyingName = "int"; + break; + + case BuiltinType::UInt: + type = D3D_SVT_UINT; + underlyingName = "uint"; + break; + + case BuiltinType::Bool: + type = D3D_SVT_BOOL; + underlyingName = "bool"; + break; + + case BuiltinType::Double: + type = D3D_SVT_DOUBLE; + underlyingName = "double"; + break; + + case BuiltinType::ULongLong: + type = D3D_SVT_UINT64; + underlyingName = "uint64_t"; + break; + + case BuiltinType::LongLong: + type = D3D_SVT_INT64; + underlyingName = "int64_t"; + break; + + default: + return HLSL_REFL_ERR("Invalid builtin type"); + } + } + + // Turn into proper fully qualified name (e.g. turn vector into + // float4) + + switch (cls) { + + case D3D_SVC_MATRIX_ROWS: + case D3D_SVC_VECTOR: + + underlyingName += std::to_string(columns); + + if (cls == D3D_SVC_MATRIX_ROWS) + underlyingName += "x" + std::to_string(rows); + + break; + + case D3D_SVC_MATRIX_COLUMNS: + underlyingName += std::to_string(rows) + "x" + std::to_string(columns); + break; + } + + // Insert + + if (Refl.Types.size() >= uint32_t(-1)) + return HLSL_REFL_ERR("Type id out of bounds"); + + if (interfaces.size() >= uint8_t(-1)) + return HLSL_REFL_ERR("Only allowing 256 interfaces"); + + uint32_t interfaceOffset = 0; + uint8_t interfaceCount = 0; + if (ReflectionError err = + Refl.RegisterTypeList(interfaces, interfaceOffset, interfaceCount)) + return err; + + ReflectionVariableType hlslType; + if (ReflectionError err = ReflectionVariableType::Initialize( + hlslType, baseType, elementsOrArrayIdUnderlying, cls, type, rows, + columns, membersCount, membersOffset, interfaceOffset, + interfaceCount)) + return err; + + uint32_t displayNameId = uint32_t(-1); + uint32_t underlyingNameId = uint32_t(-1); + + if (hasSymbols) { + + if (ReflectionError err = + Refl.RegisterString(displayNameId, displayName, false)) + return err; + + if (ReflectionError err = + Refl.RegisterString(underlyingNameId, underlyingName, false)) + return err; + } + + ReflectionVariableTypeSymbol typeSymbol(elementsOrArrayIdDisplay, + displayNameId, underlyingNameId); + + uint32_t i = 0; + uint32_t j = uint32_t(Refl.Types.size()); + + for (; i < j; ++i) + if (Refl.Types[i] == hlslType && + (!hasSymbols || Refl.TypeSymbols[i] == typeSymbol)) + break; + + if (i == j) { + + if (hasSymbols) + Refl.TypeSymbols.push_back(typeSymbol); + + Refl.Types.push_back(hlslType); + } + + TypeId = i; + return ReflectionErrorSuccess; +} + +[[nodiscard]] static ReflectionError FillReflectionRegisterAt( + const DeclContext &Ctx, ASTContext &ASTCtx, const SourceManager &SM, + DiagnosticsEngine &Diag, QualType Type, uint32_t ArraySizeFlat, + ValueDecl *ValDesc, const std::vector &ArraySize, + ReflectionData &Refl, uint32_t AutoBindingSpace, uint32_t ParentNodeId, + bool DefaultRowMaj) { + + DxcRegisterTypeInfo inputType = GetRegisterTypeInfo(ASTCtx, Type); + + uint32_t nodeId; + if (ReflectionError err = PushNextNodeId( + nodeId, Refl, SM, ASTCtx.getLangOpts(), ValDesc->getName(), ValDesc, + D3D12_HLSL_NODE_TYPE_REGISTER, ParentNodeId, + uint32_t(Refl.Registers.size()))) + return err; + + uint32_t arrayId; + + if (ReflectionError err = Refl.PushArray(arrayId, ArraySizeFlat, ArraySize)) + return err; + + uint32_t bufferId = 0; + D3D_CBUFFER_TYPE bufferType = + ReflectionData::GetBufferType(inputType.RegisterType); + + if (bufferType != D3D_CT_INTERFACE_POINTERS) { + bufferId = uint32_t(Refl.Buffers.size()); + Refl.Buffers.push_back({bufferType, nodeId}); + } + + ReflectionShaderResource regD3D12; + + if (ReflectionError err = ReflectionShaderResource::Initialize( + regD3D12, inputType.RegisterType, ArraySizeFlat, + uint32_t(inputType.RegisterFlags), inputType.TextureValue, + inputType.TextureDimension, nodeId, arrayId, bufferId)) + return err; + + Refl.Registers.push_back(regD3D12); + + bool isListType = true; + + switch (inputType.RegisterType) { + + case D3D_SIT_CBUFFER: + case D3D_SIT_TBUFFER: + isListType = false; + [[fallthrough]]; + + case D3D_SIT_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED: + case D3D_SIT_UAV_APPEND_STRUCTURED: + case D3D_SIT_UAV_CONSUME_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: { + + const TemplateSpecializationType *templateDesc = + Type->getAs(); + + assert(templateDesc->getNumArgs() == 1 && + templateDesc->getArg(0).getKind() == TemplateArgument::Type && + "Expected Type"); + + QualType innerType = templateDesc->getArg(0).getAsType(); + + // The name of the inner struct is $Element if 'array', otherwise equal to + // register name + + uint32_t typeId; + + if (ReflectionError err = + GenerateTypeInfo(typeId, ASTCtx, Refl, innerType, DefaultRowMaj)) + return err; + + SourceRange sourceRange = ValDesc->getSourceRange(); + + if (ReflectionError err = PushNextNodeId( + nodeId, Refl, SM, ASTCtx.getLangOpts(), + isListType ? "$Element" : ValDesc->getName(), nullptr, + D3D12_HLSL_NODE_TYPE_VARIABLE, nodeId, typeId, &sourceRange)) + return err; + + break; + } + } + + return ReflectionErrorSuccess; +} + +template +[[nodiscard]] ReflectionError +RecurseBuffer(ASTContext &ASTCtx, const SourceManager &SM, ReflectionData &Refl, + const T &Decls, bool DefaultRowMaj, uint32_t ParentId) { + + for (Decl *decl : Decls) { + + ValueDecl *valDecl = dyn_cast(decl); + assert(valDecl && "Decl was expected to be a ValueDecl but wasn't"); + QualType original = valDecl->getType(); + + const std::string &name = valDecl->getName(); + + uint32_t typeId; + if (ReflectionError err = + GenerateTypeInfo(typeId, ASTCtx, Refl, original, DefaultRowMaj)) + return err; + + uint32_t nodeId; + + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), name, decl, + D3D12_HLSL_NODE_TYPE_VARIABLE, ParentId, typeId)) + return err; + + // Handle struct recursion + + if (RecordDecl *recordDecl = dyn_cast(decl)) { + + if (!recordDecl->isCompleteDefinition()) + continue; + + if (ReflectionError err = RecurseBuffer( + ASTCtx, SM, Refl, recordDecl->fields(), DefaultRowMaj, nodeId)) + return err; + } + } + + return ReflectionErrorSuccess; +} + +[[nodiscard]] ReflectionError +RegisterBuffer(uint32_t &bufferId, ASTContext &ASTCtx, ReflectionData &Refl, + const SourceManager &SM, DeclContext *Buffer, uint32_t NodeId, + D3D_CBUFFER_TYPE Type, bool DefaultRowMaj) { + + if (Refl.Buffers.size() >= uint32_t(-1)) + return HLSL_REFL_ERR("Buffer id out of bounds"); + + bufferId = uint32_t(Refl.Buffers.size()); + + if (ReflectionError err = RecurseBuffer(ASTCtx, SM, Refl, Buffer->decls(), + DefaultRowMaj, NodeId)) + return err; + + Refl.Buffers.push_back({Type, NodeId}); + + return ReflectionErrorSuccess; +} + +[[nodiscard]] static ReflectionError +AddFunctionParameter(ASTContext &ASTCtx, QualType Type, Decl *Decl, + ReflectionData &Refl, const SourceManager &SM, + uint32_t ParentNodeId, bool DefaultRowMaj) { + + uint32_t typeId; + + if (ReflectionError err = + GenerateTypeInfo(typeId, ASTCtx, Refl, Type, DefaultRowMaj)) + return err; + + uint32_t nodeId; + + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), + Decl && dyn_cast(Decl) + ? dyn_cast(Decl)->getName() + : "", + Decl, D3D12_HLSL_NODE_TYPE_PARAMETER, ParentNodeId, + uint32_t(Refl.Parameters.size()))) + return err; + + D3D_PARAMETER_FLAGS flags = D3D_PF_NONE; + + if (Decl) { + + if (Decl->hasAttr()) + flags = D3D_PARAMETER_FLAGS(flags | D3D_PF_IN); + + if (Decl->hasAttr()) + flags = D3D_PARAMETER_FLAGS(flags | D3D_PF_OUT); + + if (Decl->hasAttr()) + flags = D3D_PARAMETER_FLAGS(flags | D3D_PF_IN | D3D_PF_OUT); + } + + Refl.Parameters.push_back( + ReflectionFunctionParameter{typeId, nodeId, uint8_t(flags)}); + + return ReflectionErrorSuccess; +} + +[[nodiscard]] static ReflectionError RecursiveReflectBody( + Stmt *Statement, ASTContext &ASTCtx, DiagnosticsEngine &Diags, + const SourceManager &SM, ReflectionData &Refl, uint32_t AutoBindingSpace, + uint32_t Depth, D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls, + const LangOptions &LangOpts, bool SkipNextCompound = false); + +[[nodiscard]] static ReflectionError GenerateStatement( + ASTContext &ASTCtx, DiagnosticsEngine &Diags, const SourceManager &SM, + ReflectionData &Refl, uint32_t AutoBindingSpace, uint32_t Depth, + D3D12_HLSL_REFLECTION_FEATURE Features, uint32_t ParentNodeId, + bool DefaultRowMaj, std::unordered_map &FwdDecls, + const LangOptions &LangOpts, D3D12_HLSL_NODE_TYPE Type, + const VarDecl *VarDecl, Stmt *Body, Stmt *Init, Stmt *Self, + bool IfAndHasElse = false) { + + uint32_t loc = uint32_t(Refl.Statements.size()); + + const SourceRange &sourceRange = Self->getSourceRange(); + + uint32_t nodeId; + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, LangOpts, "", nullptr, Type, + ParentNodeId, loc, &sourceRange, &FwdDecls)) + return err; + + Refl.Statements.push_back(ReflectionScopeStmt()); + + if (VarDecl) { + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, VarDecl->getType(), DefaultRowMaj)) + return err; + + const SourceRange &sourceRange = VarDecl->getSourceRange(); + + uint32_t nextNodeId; + if (ReflectionError err = + PushNextNodeId(nextNodeId, Refl, SM, LangOpts, VarDecl->getName(), + VarDecl, D3D12_HLSL_NODE_TYPE_VARIABLE, nodeId, + typeId, &sourceRange, &FwdDecls)) + return err; + } + + uint32_t start = uint32_t(Refl.Nodes.size()); + + if (ReflectionError err = RecursiveReflectBody( + Init, ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, Features, + nodeId, DefaultRowMaj, FwdDecls, LangOpts, true)) + return err; + + if (ReflectionError err = ReflectionScopeStmt::Initialize( + Refl.Statements[loc], nodeId, uint32_t(Refl.Nodes.size() - start), + VarDecl, IfAndHasElse)) + return err; + + if (ReflectionError err = RecursiveReflectBody( + Body, ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, Features, + nodeId, DefaultRowMaj, FwdDecls, LangOpts, true)) + return err; + + return ReflectionErrorSuccess; +} + +static D3D12_HLSL_ENUM_TYPE GetEnumTypeFromQualType(ASTContext &ASTCtx, + QualType desugared) { + + const auto &semantics = ASTCtx.getTypeInfo(desugared); + + switch (semantics.Width) { + + default: + case 32: + return desugared->isUnsignedIntegerType() ? D3D12_HLSL_ENUM_TYPE_UINT + : D3D12_HLSL_ENUM_TYPE_INT; + + case 16: + return desugared->isUnsignedIntegerType() ? D3D12_HLSL_ENUM_TYPE_UINT16_T + : D3D12_HLSL_ENUM_TYPE_INT16_T; + + case 64: + return desugared->isUnsignedIntegerType() ? D3D12_HLSL_ENUM_TYPE_UINT64_T + : D3D12_HLSL_ENUM_TYPE_INT64_T; + } + + assert(false && "QualType of invalid type passed"); + return D3D12_HLSL_ENUM_TYPE_INT; +} + +struct RecursiveStmtReflector : public StmtVisitor { + + ASTContext &ASTCtx; + DiagnosticsEngine &Diags; + const SourceManager &SM; + ReflectionData &Refl; + uint32_t AutoBindingSpace; + uint32_t Depth; + D3D12_HLSL_REFLECTION_FEATURE Features; + uint32_t ParentNodeId; + bool DefaultRowMaj; + std::unordered_map &FwdDecls; + const LangOptions &LangOpts; + bool SkipNextCompound; + + ReflectionError LastError = ReflectionErrorSuccess; + + RecursiveStmtReflector(ASTContext &ASTCtx, DiagnosticsEngine &Diags, + const SourceManager &SM, ReflectionData &Refl, + uint32_t AutoBindingSpace, uint32_t Depth, + D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls, + const LangOptions &LangOpts, bool SkipNextCompound) + : ASTCtx(ASTCtx), Diags(Diags), SM(SM), Refl(Refl), + AutoBindingSpace(AutoBindingSpace), Depth(Depth), Features(Features), + ParentNodeId(ParentNodeId), DefaultRowMaj(DefaultRowMaj), + FwdDecls(FwdDecls), LangOpts(LangOpts), + SkipNextCompound(SkipNextCompound) {} + + [[nodiscard]] ReflectionError TraverseStmt(Stmt *S) { + + if (LastError) + return LastError; + + if (!S) + return ReflectionErrorSuccess; + + while (AttributedStmt *AS = dyn_cast(S)) + S = AS->getSubStmt(); + + Visit(S); + return LastError; + } + + void VisitStmt(const Stmt *S) {} + + void VisitIfStmt(IfStmt *If) { + + if (LastError) + return; + + uint32_t loc = uint32_t(Refl.IfSwitchStatements.size()); + + const SourceRange &sourceRange = If->getSourceRange(); + + uint32_t nodeId; + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, LangOpts, "", nullptr, + D3D12_HLSL_NODE_TYPE_IF_ROOT, ParentNodeId, loc, + &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + Refl.IfSwitchStatements.push_back(ReflectionIfSwitchStmt()); + + std::vector branches; + branches.reserve(2); + branches.push_back(If); + + Stmt *child = If->getElse(); + + while (child) { + + branches.push_back(child); + + if (IfStmt *ifChild = dyn_cast(child)) + child = ifChild->getElse(); + + else + break; + } + + bool hasElse = branches.size() > 1 && !isa(branches.back()); + uint64_t counter = 0; + + for (Stmt *child : branches) { + + uint32_t loc = uint32_t(Refl.BranchStatements.size()); + Refl.BranchStatements.push_back(ReflectionBranchStmt()); + + const SourceRange &sourceRange = child->getSourceRange(); + + D3D12_HLSL_NODE_TYPE nodeType = + !counter ? D3D12_HLSL_NODE_TYPE_IF_FIRST + : (hasElse && counter + 1 == branches.size() + ? D3D12_HLSL_NODE_TYPE_ELSE + : D3D12_HLSL_NODE_TYPE_ELSE_IF); + ++counter; + + uint32_t childId; + if (ReflectionError err = + PushNextNodeId(childId, Refl, SM, LangOpts, "", nullptr, nodeType, + nodeId, loc, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + IfStmt *branch = dyn_cast_or_null(child); + + VarDecl *cond = branch ? branch->getConditionVariable() : nullptr; + + if (cond) { + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, cond->getType(), DefaultRowMaj)) { + LastError = err; + return; + } + + const SourceRange &sourceRange = cond->getSourceRange(); + + uint32_t nextNodeId; + if (ReflectionError err = + PushNextNodeId(nextNodeId, Refl, SM, LangOpts, cond->getName(), + cond, D3D12_HLSL_NODE_TYPE_VARIABLE, childId, + typeId, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + } + + if (ReflectionError err = ReflectionBranchStmt::Initialize( + Refl.BranchStatements[loc], childId, cond, true, + D3D12_HLSL_ENUM_TYPE_UINT, uint64_t(-1))) { + LastError = err; + return; + } + + uint32_t parentSelf = ParentNodeId; + ParentNodeId = childId; + + Stmt *realChild = branch ? branch->getThen() : child; + auto firstIt = realChild->child_begin(); + auto it = firstIt; + + if (it != realChild->child_end()) { + + ++it; + + if (it == realChild->child_end() && isa(*firstIt)) { + + it = firstIt->child_begin(); + + for (; it != firstIt->child_end(); ++it) + if (ReflectionError err = TraverseStmt(*it)) { + LastError = err; + return; + } + } + + else { + it = firstIt; + for (; it != realChild->child_end(); ++it) + if (ReflectionError err = TraverseStmt(*it)) { + LastError = err; + return; + } + } + } + + ParentNodeId = parentSelf; + } + + if (ReflectionError err = ReflectionIfSwitchStmt::Initialize( + Refl.IfSwitchStatements[loc], nodeId, false, hasElse)) { + LastError = err; + return; + } + } + + void VisitForStmt(ForStmt *For) { + + if (LastError) + return; + + LastError = GenerateStatement( + ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, Features, + ParentNodeId, DefaultRowMaj, FwdDecls, LangOpts, + D3D12_HLSL_NODE_TYPE_FOR, For->getConditionVariable(), For->getBody(), + For->getInit(), For); + } + + void VisitWhileStmt(WhileStmt *While) { + + if (LastError) + return; + + LastError = GenerateStatement( + ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, Features, + ParentNodeId, DefaultRowMaj, FwdDecls, LangOpts, + D3D12_HLSL_NODE_TYPE_WHILE, While->getConditionVariable(), + While->getBody(), nullptr, While); + } + + void VisitDoStmt(DoStmt *Do) { + + if (LastError) + return; + + const SourceRange &sourceRange = Do->getSourceRange(); + + uint32_t scopeNode; + if (ReflectionError err = PushNextNodeId( + scopeNode, Refl, SM, LangOpts, "", nullptr, D3D12_HLSL_NODE_TYPE_DO, + ParentNodeId, 0, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + LastError = RecursiveReflectBody( + Do->getBody(), ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, + Features, scopeNode, DefaultRowMaj, FwdDecls, LangOpts, true); + } + + void VisitSwitchStmt(SwitchStmt *Switch) { + + if (LastError) + return; + + uint32_t loc = uint32_t(Refl.IfSwitchStatements.size()); + + const SourceRange &sourceRange = Switch->getSourceRange(); + + uint32_t nodeId; + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, LangOpts, "", nullptr, + D3D12_HLSL_NODE_TYPE_SWITCH, ParentNodeId, loc, + &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + Refl.IfSwitchStatements.push_back(ReflectionIfSwitchStmt()); + + VarDecl *cond = Switch->getConditionVariable(); + + if (cond) { + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, cond->getType(), DefaultRowMaj)) { + LastError = err; + return; + } + + const SourceRange &sourceRange = cond->getSourceRange(); + + uint32_t nextNodeId; + if (ReflectionError err = + PushNextNodeId(nextNodeId, Refl, SM, LangOpts, cond->getName(), + cond, D3D12_HLSL_NODE_TYPE_VARIABLE, nodeId, + typeId, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + } + + Stmt *body = Switch->getBody(); + assert(body && "SwitchStmt has no body"); + + bool hasDefault = false; + + for (Stmt *child : body->children()) { + + SwitchCase *switchCase = nullptr; + uint64_t caseValue = uint64_t(-1); + D3D12_HLSL_ENUM_TYPE valueType = D3D12_HLSL_ENUM_TYPE_INT; + D3D12_HLSL_NODE_TYPE nodeType = D3D12_HLSL_NODE_TYPE_INVALID; + + bool isComplexCase = true; + + if (CaseStmt *caseStmt = dyn_cast(child)) { + + switchCase = caseStmt; + + llvm::APSInt result; + + if (caseStmt->getLHS()->isIntegerConstantExpr(result, ASTCtx)) { + caseValue = result.getZExtValue(); + + QualType desugared = caseStmt->getLHS()->getType(); + valueType = GetEnumTypeFromQualType(ASTCtx, desugared); + isComplexCase = false; + } + + else + caseValue = uint64_t(-1); + + nodeType = D3D12_HLSL_NODE_TYPE_CASE; + + } else if (DefaultStmt *defaultStmt = + dyn_cast(child)) { + switchCase = defaultStmt; + hasDefault = true; + nodeType = D3D12_HLSL_NODE_TYPE_DEFAULT; + } + + if (!switchCase) + continue; + + uint32_t loc = uint32_t(Refl.BranchStatements.size()); + + const SourceRange &sourceRange = switchCase->getSourceRange(); + + uint32_t childId; + if (ReflectionError err = + PushNextNodeId(childId, Refl, SM, LangOpts, "", nullptr, nodeType, + nodeId, loc, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + Refl.BranchStatements.push_back(ReflectionBranchStmt()); + if (ReflectionError err = ReflectionBranchStmt::Initialize( + Refl.BranchStatements.back(), childId, false, isComplexCase, + valueType, caseValue)) { + LastError = err; + return; + } + + uint32_t parentSelf = ParentNodeId; + ParentNodeId = childId; + + auto realChild = switchCase->getSubStmt(); + + auto firstIt = realChild->child_begin(); + auto it = firstIt; + + if (it != realChild->child_end()) { + + ++it; + + if (it == realChild->child_end() && isa(*firstIt)) { + for (Stmt *childChild : firstIt->children()) + if (ReflectionError err = TraverseStmt(childChild)) { + LastError = err; + return; + } + } + + else + for (Stmt *childChild : realChild->children()) + if (ReflectionError err = TraverseStmt(childChild)) { + LastError = err; + return; + } + } + + ParentNodeId = parentSelf; + } + + if (ReflectionError err = ReflectionIfSwitchStmt::Initialize( + Refl.IfSwitchStatements[loc], nodeId, cond, hasDefault)) { + LastError = err; + return; + } + } + + void VisitCompoundStmt(CompoundStmt *C) { + + if (LastError) + return; + + const SourceRange &sourceRange = C->getSourceRange(); + + uint32_t scopeNode = ParentNodeId; + + if (!SkipNextCompound) + if (ReflectionError err = + PushNextNodeId(scopeNode, Refl, SM, LangOpts, "", nullptr, + D3D12_HLSL_NODE_TYPE_SCOPE, ParentNodeId, 0, + &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + + for (Stmt *child : C->body()) + if (ReflectionError err = RecursiveReflectBody( + child, ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth + 1, + Features, scopeNode, DefaultRowMaj, FwdDecls, LangOpts)) { + LastError = err; + return; + } + } + + void VisitDeclStmt(DeclStmt *DS) { + + if (LastError) + return; + + for (Decl *D : DS->decls()) { + if (VarDecl *varDecl = dyn_cast(D)) { + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, varDecl->getType(), DefaultRowMaj)) { + LastError = err; + return; + } + + const SourceRange &sourceRange = varDecl->getSourceRange(); + + uint32_t nodeId; + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, LangOpts, varDecl->getName(), + varDecl, D3D12_HLSL_NODE_TYPE_VARIABLE, + ParentNodeId, typeId, &sourceRange, &FwdDecls)) { + LastError = err; + return; + } + } + } + } +}; + +[[nodiscard]] static ReflectionError +RecursiveReflectBody(Stmt *Statement, ASTContext &ASTCtx, + DiagnosticsEngine &Diags, const SourceManager &SM, + ReflectionData &Refl, uint32_t AutoBindingSpace, + uint32_t Depth, D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls, + const LangOptions &LangOpts, bool SkipNextCompound) { + RecursiveStmtReflector Reflector(ASTCtx, Diags, SM, Refl, AutoBindingSpace, + Depth, Features, ParentNodeId, DefaultRowMaj, + FwdDecls, LangOpts, SkipNextCompound); + return Reflector.TraverseStmt(Statement); +} + +[[nodiscard]] static ReflectionError +RecursiveReflectHLSL(const DeclContext &Ctx, ASTContext &ASTCtx, + DiagnosticsEngine &Diags, const SourceManager &SM, + ReflectionData &Refl, uint32_t AutoBindingSpace, + uint32_t Depth, D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls); + +class RecursiveReflector : public DeclVisitor { + + const DeclContext &Ctx; + ASTContext &ASTCtx; + const SourceManager &SM; + DiagnosticsEngine &Diags; + ReflectionData &Refl; + uint32_t AutoBindingSpace; + uint32_t Depth; + D3D12_HLSL_REFLECTION_FEATURE Features; + uint32_t ParentNodeId; + bool DefaultRowMaj; + std::unordered_map &FwdDecls; + + ReflectionError LastError = ReflectionErrorSuccess; + + [[nodiscard]] ReflectionError PushVariable(ValueDecl *VD, + D3D12_HLSL_NODE_TYPE NodeType) { + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo(typeId, ASTCtx, Refl, + VD->getType(), DefaultRowMaj)) + return err; + + uint32_t nodeId; + return PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), VD->getName(), + VD, NodeType, ParentNodeId, typeId); + } + +public: + RecursiveReflector(const DeclContext &Ctx, ASTContext &ASTCtx, + const SourceManager &SM, DiagnosticsEngine &Diags, + ReflectionData &Refl, uint32_t AutoBindingSpace, + uint32_t Depth, D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls) + : Ctx(Ctx), ASTCtx(ASTCtx), SM(SM), Diags(Diags), Refl(Refl), + AutoBindingSpace(AutoBindingSpace), Depth(Depth), Features(Features), + ParentNodeId(ParentNodeId), DefaultRowMaj(DefaultRowMaj), + FwdDecls(FwdDecls) {} + + [[nodiscard]] ReflectionError TraverseDeclContext() { + + if (LastError) + return LastError; + + for (Decl *it : Ctx.decls()) { + + SourceLocation Loc = it->getLocation(); + if (Loc.isInvalid() || + SM.isInSystemHeader(Loc)) // TODO: We might want to include these for + // a more complete picture. + continue; + + Visit(it); + + if (LastError) + return LastError; + } + + return ReflectionErrorSuccess; + } + + void VisitDecl(Decl *D) {} + + void VisitHLSLBufferDecl(HLSLBufferDecl *CB) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_BASICS)) + return; + + if (Depth != 0) + return; + + uint32_t nodeId; + + if (ReflectionError err = + PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), + CB->getName(), CB, D3D12_HLSL_NODE_TYPE_REGISTER, + ParentNodeId, uint32_t(Refl.Registers.size()))) { + LastError = err; + return; + } + + uint32_t bufferId; + + if (ReflectionError err = + RegisterBuffer(bufferId, ASTCtx, Refl, SM, CB, nodeId, + D3D_CT_CBUFFER, DefaultRowMaj)) { + LastError = err; + return; + } + + ReflectionShaderResource regD3D12; + + if (ReflectionError err = ReflectionShaderResource::Initialize( + regD3D12, D3D_SIT_CBUFFER, 1, uint32_t(D3D_SIF_USERPACKED), + D3D_RESOURCE_RETURN_TYPE(0), D3D_SRV_DIMENSION_UNKNOWN, nodeId, + uint32_t(-1), bufferId)) { + LastError = err; + return; + } + + Refl.Registers.push_back(regD3D12); + } + + void VisitFunctionDecl(FunctionDecl *FD) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_FUNCTIONS)) + return; + + if (FD->isImplicit()) // Skip ctors, etc. + return; + + const FunctionDecl *definition = nullptr; + + uint32_t nodeId; + if (ReflectionError err = PushNextNodeId( + nodeId, Refl, SM, ASTCtx.getLangOpts(), FD->getName(), FD, + D3D12_HLSL_NODE_TYPE_FUNCTION, ParentNodeId, + uint32_t(Refl.Functions.size()), nullptr, &FwdDecls)) { + LastError = err; + return; + } + + if (nodeId == uint32_t(-1)) // Duplicate fwd definition + return; + + bool hasDefinition = FD->hasBody(definition); + ReflectionFunction func; + + if (ReflectionError err = ReflectionFunction::Initialize( + func, nodeId, FD->getNumParams(), + !FD->getReturnType().getTypePtr()->isVoidType(), hasDefinition)) { + LastError = err; + return; + } + + for (uint32_t i = 0; i < func.GetNumParameters(); ++i) + if (ReflectionError err = AddFunctionParameter( + ASTCtx, FD->getParamDecl(i)->getType(), FD->getParamDecl(i), Refl, + SM, nodeId, DefaultRowMaj)) { + LastError = err; + return; + } + + if (func.HasReturn()) + if (ReflectionError err = + AddFunctionParameter(ASTCtx, FD->getReturnType(), nullptr, Refl, + SM, nodeId, DefaultRowMaj)) { + LastError = err; + return; + } + + Refl.Functions.push_back(std::move(func)); + + if (hasDefinition && (Features & D3D12_HLSL_REFLECTION_FEATURE_SCOPES)) { + + Stmt *stmt = FD->getBody(); + + for (Stmt *subStmt : stmt->children()) { + + if (!subStmt) + continue; + + if (ReflectionError err = RecursiveReflectBody( + subStmt, ASTCtx, Diags, SM, Refl, AutoBindingSpace, Depth, + Features, nodeId, DefaultRowMaj, FwdDecls, + ASTCtx.getLangOpts())) { + LastError = err; + return; + } + } + } + } + + void VisitEnumDecl(EnumDecl *ED) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + uint32_t nodeId; + + if (ReflectionError err = PushNextNodeId( + nodeId, Refl, SM, ASTCtx.getLangOpts(), ED->getName(), ED, + D3D12_HLSL_NODE_TYPE_ENUM, ParentNodeId, + uint32_t(Refl.Enums.size()), nullptr, &FwdDecls)) { + LastError = err; + return; + } + + if (nodeId == uint32_t(-1)) // Duplicate fwd definition + return; + + for (EnumConstantDecl *enumValue : ED->enumerators()) { + + uint32_t childNodeId; + + if (ReflectionError err = PushNextNodeId( + childNodeId, Refl, SM, ASTCtx.getLangOpts(), enumValue->getName(), + enumValue, D3D12_HLSL_NODE_TYPE_ENUM_VALUE, nodeId, + uint32_t(Refl.EnumValues.size()))) { + LastError = err; + return; + } + + Refl.EnumValues.push_back( + {enumValue->getInitVal().getSExtValue(), childNodeId}); + } + + if (Refl.EnumValues.size() >= uint32_t(1 << 30)) { + LastError = HLSL_REFL_ERR("Enum values overflow"); + return; + } + + QualType enumType = ED->getIntegerType(); + QualType desugared = enumType.getDesugaredType(ASTCtx); + + D3D12_HLSL_ENUM_TYPE type = GetEnumTypeFromQualType(ASTCtx, desugared); + + Refl.Enums.push_back({nodeId, type}); + } + + void VisitTypedefDecl(TypedefDecl *TD) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, TD->getUnderlyingType(), DefaultRowMaj)) { + LastError = err; + return; + } + + uint32_t nodeId; + LastError = + PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), TD->getName(), + TD, D3D12_HLSL_NODE_TYPE_TYPEDEF, ParentNodeId, typeId); + } + + void VisitTypeAliasDecl(TypeAliasDecl *TAD) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + uint32_t typeId; + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, TAD->getUnderlyingType(), DefaultRowMaj)) { + LastError = err; + return; + } + + uint32_t nodeId; + LastError = + PushNextNodeId(nodeId, Refl, SM, ASTCtx.getLangOpts(), TAD->getName(), + TAD, D3D12_HLSL_NODE_TYPE_USING, ParentNodeId, typeId); + } + + void VisitFieldDecl(FieldDecl *FD) { + + if (LastError) + return; + + LastError = PushVariable(FD, D3D12_HLSL_NODE_TYPE_VARIABLE); + } + + void VisitValueDecl(ValueDecl *VD) { + + if (LastError) + return; + + if (isa(VD)) // Skip parameters, already handled explicitly + return; + + VarDecl *varDecl = dyn_cast(VD); + + if (varDecl && varDecl->hasAttr()) { + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + LastError = PushVariable(VD, D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE); + return; + } + + if (varDecl && varDecl->getStorageClass() == StorageClass::SC_Static) { + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + LastError = PushVariable(VD, D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE); + return; + } + + uint32_t arraySize = 1; + QualType type = VD->getType(); + std::vector arrayElem; + + while (const ConstantArrayType *arr = dyn_cast(type)) { + uint32_t current = arr->getSize().getZExtValue(); + arrayElem.push_back(current); + arraySize *= arr->getSize().getZExtValue(); + type = arr->getElementType(); + } + + if (!IsHLSLResourceType(type)) { + + // Handle $Globals or regular variables + + if (varDecl && + (Depth == 0 || Features & D3D12_HLSL_REFLECTION_FEATURE_SCOPES)) { + + LastError = PushVariable(VD, D3D12_HLSL_NODE_TYPE_VARIABLE); + } + + return; + } + + if (Depth != 0 || !(Features & D3D12_HLSL_REFLECTION_FEATURE_BASICS)) + return; + + LastError = FillReflectionRegisterAt( + Ctx, ASTCtx, SM, Diags, type, arraySize, VD, arrayElem, Refl, + AutoBindingSpace, ParentNodeId, DefaultRowMaj); + } + + void VisitRecordDecl(RecordDecl *RD) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + bool isDefinition = RD->isThisDeclarationADefinition(); + + D3D12_HLSL_NODE_TYPE type = D3D12_HLSL_NODE_TYPE_RESERVED; + + switch (RD->getTagKind()) { + + case TTK_Struct: + type = D3D12_HLSL_NODE_TYPE_STRUCT; + break; + + case TTK_Union: + type = D3D12_HLSL_NODE_TYPE_UNION; + break; + + case TTK_Interface: + type = D3D12_HLSL_NODE_TYPE_INTERFACE; + break; + } + + if (type != D3D12_HLSL_NODE_TYPE_RESERVED) { + + uint32_t typeId = 0; + + if (isDefinition) + if (ReflectionError err = GenerateTypeInfo( + typeId, ASTCtx, Refl, RD->getASTContext().getRecordType(RD), + DefaultRowMaj)) { + LastError = err; + return; + } + + uint32_t self; + if (ReflectionError err = PushNextNodeId( + self, Refl, SM, ASTCtx.getLangOpts(), RD->getName(), RD, type, + ParentNodeId, typeId, nullptr, &FwdDecls)) { + LastError = err; + return; + } + + if (self == uint32_t(-1)) // Duplicate fwd definition + return; + + if (isDefinition) + LastError = RecursiveReflectHLSL(*RD, ASTCtx, Diags, SM, Refl, + AutoBindingSpace, Depth + 1, Features, + self, DefaultRowMaj, FwdDecls); + } + } + + void VisitNamespaceDecl(NamespaceDecl *ND) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_NAMESPACES)) + return; + + uint32_t nodeId; + if (ReflectionError err = PushNextNodeId( + nodeId, Refl, SM, ASTCtx.getLangOpts(), ND->getName(), ND, + D3D12_HLSL_NODE_TYPE_NAMESPACE, ParentNodeId, 0)) { + LastError = err; + return; + } + + LastError = RecursiveReflectHLSL(*ND, ASTCtx, Diags, SM, Refl, + AutoBindingSpace, Depth + 1, Features, + nodeId, DefaultRowMaj, FwdDecls); + } + + /*void VisitTypeAliasDecl(TypeAliasDecl *TAD) { + + if (LastError) + return; + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES)) + return; + + // TODO: Implement. TAD->print(pfStream, printingPolicy); + }*/ +}; + +[[nodiscard]] static ReflectionError +RecursiveReflectHLSL(const DeclContext &Ctx, ASTContext &ASTCtx, + DiagnosticsEngine &Diags, const SourceManager &SM, + ReflectionData &Refl, uint32_t AutoBindingSpace, + uint32_t Depth, D3D12_HLSL_REFLECTION_FEATURE Features, + uint32_t ParentNodeId, bool DefaultRowMaj, + std::unordered_map &FwdDecls) { + + RecursiveReflector Reflector(Ctx, ASTCtx, SM, Diags, Refl, AutoBindingSpace, + Depth, Features, ParentNodeId, DefaultRowMaj, + FwdDecls); + return Reflector.TraverseDeclContext(); +} + +[[nodiscard]] ReflectionError +HLSLReflectionDataFromAST(ReflectionData &Result, CompilerInstance &Compiler, + TranslationUnitDecl &Ctx, uint32_t AutoBindingSpace, + D3D12_HLSL_REFLECTION_FEATURE Features, + bool DefaultRowMaj) { + + DiagnosticsEngine &Diags = Ctx.getParentASTContext().getDiagnostics(); + const SourceManager &SM = Compiler.getSourceManager(); + + Result = {}; + Result.Features = Features; + + if (Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) { + Result.Strings.push_back(""); + Result.StringsToId[""] = 0; + Result.NodeSymbols.push_back({}); + + if (ReflectionError err = ReflectionNodeSymbol::Initialize( + Result.NodeSymbols[0], 0, uint16_t(-1), 0, 0, 0, 0)) { + llvm::errs() << "HLSLReflectionDataFromAST: Failed to add root symbol: " + << err; + Result = {}; + return err; + } + } + + Result.Nodes.push_back({}); + if (ReflectionError err = ReflectionNode::Initialize( + Result.Nodes[0], D3D12_HLSL_NODE_TYPE_NAMESPACE, false, 0, 0, 0, + 0xFFFF, 0, uint16_t(-1), D3D_INTERPOLATION_UNDEFINED)) { + llvm::errs() << "HLSLReflectionDataFromAST: Failed to add root node: " + << err; + Result = {}; + return err; + } + + std::unordered_map fwdDecls; + + if (ReflectionError err = RecursiveReflectHLSL( + Ctx, Compiler.getASTContext(), Diags, SM, Result, AutoBindingSpace, 0, + Features, 0, DefaultRowMaj, fwdDecls)) { + llvm::errs() << "HLSLReflectionDataFromAST: Failed: " << err; + Result = {}; + return err; + } + + return ReflectionErrorSuccess; +} + +} // namespace hlsl diff --git a/tools/clang/tools/dxcreflection/dxcreflector.cpp b/tools/clang/tools/dxcreflection/dxcreflector.cpp new file mode 100644 index 0000000000..6cabaf3dc0 --- /dev/null +++ b/tools/clang/tools/dxcreflection/dxcreflector.cpp @@ -0,0 +1,1849 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxcreflector.cpp // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/HlslTypes.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Lex/HLSLMacroExpander.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/SemaHLSL.h" +#include "llvm/Support/Host.h" + +#include "dxc/Support/FileIOHelper.h" +#include "dxc/Support/Global.h" +#include "dxc/Support/Unicode.h" +#include "dxc/Support/WinIncludes.h" +#include "dxc/Support/microcom.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MSFileSystem.h" + +#include "dxc/Support/DxcLangExtensionsHelper.h" +#include "dxc/Support/HLSLOptions.h" +#include "dxc/Support/dxcapi.impl.h" +#include "dxc/Support/dxcfilesystem.h" +#include "dxc/dxcapi.internal.h" + +#include "dxc/DxcReflection/DxcReflectionContainer.h" +#include "dxc/dxcreflect.h" + +#if _WIN32 +extern "C" const IID IID_IHLSLReflectionData = { + 0x7016f834, + 0xae85, + 0x4c86, + {0xa4, 0x73, 0x8c, 0x2c, 0x98, 0x1d, 0xd3, 0x70}}; +#endif + +using namespace llvm; +using namespace clang; +using namespace hlsl; + +namespace hlsl { + +[[nodiscard]] ReflectionError HLSLReflectionDataFromAST( + ReflectionData &Result, clang::CompilerInstance &Compiler, + clang::TranslationUnitDecl &Ctx, uint32_t AutoBindingSpace, + D3D12_HLSL_REFLECTION_FEATURE Features, bool DefaultRowMaj); +} + +struct ASTHelper { + CompilerInstance compiler; + TranslationUnitDecl *tu; + ParsedSemanticDefineList semanticMacros; + ParsedSemanticDefineList userMacros; + bool bHasErrors; +}; + +// We can't return nullptr instead, since that doesn't match old behavior... + +class CHLSLInvalidSRType final : public ID3D12ShaderReflectionType { + + STDMETHOD(GetDesc)(D3D12_SHADER_TYPE_DESC *pDesc) override { return E_FAIL; } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByIndex) + (UINT Index) override; + + STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByName) + (LPCSTR Name) override; + + STDMETHOD_(LPCSTR, GetMemberTypeName)(UINT Index) override { + return "$Invalid"; + } + + STDMETHOD(IsEqual)(ID3D12ShaderReflectionType *pType) override { + return E_FAIL; + } + STDMETHOD_(ID3D12ShaderReflectionType *, GetSubType)() override; + STDMETHOD_(ID3D12ShaderReflectionType *, GetBaseClass)() override; + STDMETHOD_(UINT, GetNumInterfaces)() override { return 0; } + STDMETHOD_(ID3D12ShaderReflectionType *, GetInterfaceByIndex) + (UINT uIndex) override; + + STDMETHOD(IsOfType)(ID3D12ShaderReflectionType *pType) override { + return E_FAIL; + } + + STDMETHOD(ImplementsInterface)(ID3D12ShaderReflectionType *pBase) override { + return E_FAIL; + } +}; +static CHLSLInvalidSRType g_InvalidSRType; + +ID3D12ShaderReflectionType *CHLSLInvalidSRType::GetMemberTypeByIndex(UINT) { + return &g_InvalidSRType; +} +ID3D12ShaderReflectionType *CHLSLInvalidSRType::GetMemberTypeByName(LPCSTR) { + return &g_InvalidSRType; +} +ID3D12ShaderReflectionType *CHLSLInvalidSRType::GetSubType() { + return &g_InvalidSRType; +} +ID3D12ShaderReflectionType *CHLSLInvalidSRType::GetBaseClass() { + return &g_InvalidSRType; +} +ID3D12ShaderReflectionType *CHLSLInvalidSRType::GetInterfaceByIndex(UINT) { + return &g_InvalidSRType; +} + +class CHLSLInvalidSRVariable final : public ID3D12ShaderReflectionVariable { + + STDMETHOD(GetDesc)(D3D12_SHADER_VARIABLE_DESC *pDesc) override { + return E_FAIL; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetType)() override { + return &g_InvalidSRType; + } + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetBuffer)() override; + + STDMETHOD_(UINT, GetInterfaceSlot)(UINT uIndex) override { return UINT_MAX; } +}; +static CHLSLInvalidSRVariable g_InvalidSRVariable; + +class CHLSLInvalidSRConstantBuffer final + : public ID3D12ShaderReflectionConstantBuffer { + + STDMETHOD(GetDesc)(D3D12_SHADER_BUFFER_DESC *pDesc) override { + return E_FAIL; + } + + STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByIndex) + (UINT Index) override { return &g_InvalidSRVariable; } + + STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName) + (LPCSTR Name) override { return &g_InvalidSRVariable; } +}; +static CHLSLInvalidSRConstantBuffer g_InvalidSRConstantBuffer; + +ID3D12ShaderReflectionConstantBuffer *CHLSLInvalidSRVariable::GetBuffer() { + return &g_InvalidSRConstantBuffer; +} + +class CHLSLReflectionConstantBuffer; + +class CHLSLReflectionType final : public ID3D12ShaderReflectionType1 { + friend class CHLSLReflectionConstantBuffer; + +protected: + std::string m_NameUnderlying; + std::string m_NameDisplay; + std::vector m_MemberNames; + std::unordered_map m_NameToMemberId; + std::vector m_MemberTypes; + CHLSLReflectionType *m_pBaseClass; + std::vector m_Interfaces; + + const ReflectionData *m_Data; + uint32_t m_TypeId; + uint32_t m_ElementsUnderlying; + uint32_t m_ElementsDisplay; + D3D12_ARRAY_DESC m_ArrayDescUnderlying; + D3D12_ARRAY_DESC m_ArrayDescDisplay; + + void InitializeArray(const ReflectionData &Data, D3D12_ARRAY_DESC &desc, + uint32_t &elements, + const ReflectionArrayOrElements &arrElem) { + + if (arrElem.IsArray()) { + + elements = arrElem.Is1DArray() ? arrElem.Get1DElements() : 1; + + if (arrElem.IsMultiDimensionalArray()) { + + const ReflectionArray &arr = + Data.Arrays[arrElem.GetMultiDimensionalArrayId()]; + + desc.ArrayDims = arr.ArrayElem(); + + for (uint32_t i = 0; i < arr.ArrayElem(); ++i) { + uint32_t len = Data.ArraySizes[arr.ArrayStart() + i]; + elements *= len; + desc.ArrayLengths[i] = len; + } + } + + else { + desc.ArrayDims = 1; + desc.ArrayLengths[0] = arrElem.Get1DElements(); + } + } + } + +public: + STDMETHOD(IsEqual)(ID3D12ShaderReflectionType *pType) override { + return (this == pType) ? S_OK : S_FALSE; + } + + STDMETHOD(IsOfType)(ID3D12ShaderReflectionType *pType) override { + + if (this == pType) + return S_OK; + + if (m_pBaseClass) + return m_pBaseClass->IsOfType(pType); + + return S_FALSE; + } + + STDMETHOD(GetArrayDesc)(THIS_ _Out_ D3D12_ARRAY_DESC *pArrayDesc) override { + + if (!pArrayDesc) + return E_POINTER; + + *pArrayDesc = m_ArrayDescUnderlying; + return S_OK; + } + + STDMETHOD(GetDisplayArrayDesc) + (THIS_ _Out_ D3D12_ARRAY_DESC *pArrayDesc) override { + + if (!pArrayDesc) + return E_POINTER; + + *pArrayDesc = m_ArrayDescDisplay; + return S_OK; + } + + HRESULT Initialize( + const ReflectionData &Data, uint32_t TypeId, + std::vector &Types /* Only access < TypeId*/) { + + m_TypeId = TypeId; + m_ElementsUnderlying = 0; + m_ElementsDisplay = 0; + m_Data = &Data; + + const ReflectionVariableType &type = Data.Types[TypeId]; + + ZeroMemoryToOut(&m_ArrayDescUnderlying); + ZeroMemoryToOut(&m_ArrayDescDisplay); + + InitializeArray(Data, m_ArrayDescUnderlying, m_ElementsUnderlying, + type.GetUnderlyingArray()); + + bool hasNames = Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (hasNames) { + ReflectionVariableTypeSymbol sym = Data.TypeSymbols[TypeId]; + m_NameUnderlying = Data.Strings[sym.UnderlyingNameId]; + m_NameDisplay = Data.Strings[sym.DisplayNameId]; + InitializeArray(Data, m_ArrayDescDisplay, m_ElementsDisplay, + sym.DisplayArray); + } + + uint32_t memberCount = type.GetMemberCount(); + + m_MemberNames.resize(memberCount); + m_MemberTypes.resize(memberCount); + m_NameToMemberId.clear(); + + for (uint32_t i = 0; i < memberCount; ++i) { + + uint32_t memberId = type.GetMemberStart() + i; + + m_MemberTypes[i] = &Types[Data.MemberTypeIds[memberId]]; + + if (hasNames) { + + const std::string &name = Data.Strings[Data.MemberNameIds[memberId]]; + + m_MemberNames[i] = name; + m_NameToMemberId[name] = i; + } + } + + if (type.GetBaseClass() != uint32_t(-1)) + m_pBaseClass = &Types[type.GetBaseClass()]; + + uint32_t interfaceCount = type.GetInterfaceCount(); + + m_Interfaces.resize(interfaceCount); + + for (uint32_t i = 0; i < interfaceCount; ++i) + m_Interfaces[i] = &Types[Data.TypeList[type.GetInterfaceStart() + i]]; + + return S_OK; + } + + STDMETHOD(GetDesc)(D3D12_SHADER_TYPE_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + const ReflectionVariableType &type = m_Data->Types[m_TypeId]; + + *pDesc = D3D12_SHADER_TYPE_DESC{ + + type.GetClass(), + type.GetType(), + type.GetRows(), + type.GetColumns(), + + m_ElementsUnderlying, + uint32_t(m_MemberTypes.size()), + 0, // TODO: Offset if we have one + m_NameUnderlying.c_str()}; + + return S_OK; + } + + STDMETHOD(GetDesc1)(D3D12_SHADER_TYPE_DESC1 *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + GetDesc(&pDesc->Desc); + pDesc->DisplayName = m_NameDisplay.c_str(); + pDesc->DisplayElements = m_ElementsDisplay; + + return S_OK; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByIndex) + (UINT Index) override { + + if (Index >= m_MemberTypes.size()) + return &g_InvalidSRType; + + return m_MemberTypes[Index]; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByName) + (LPCSTR Name) override { + + if (!Name) + return &g_InvalidSRType; + + auto it = m_NameToMemberId.find(Name); + return it == m_NameToMemberId.end() + ? (ID3D12ShaderReflectionType *)&g_InvalidSRType + : m_MemberTypes[it->second]; + } + + STDMETHOD_(LPCSTR, GetMemberTypeName)(UINT Index) override { + + if (Index >= m_MemberTypes.size()) + return nullptr; + + return m_MemberNames[Index].c_str(); + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetSubType)() override { + return nullptr; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetBaseClass)() override { + return m_pBaseClass; + } + + STDMETHOD_(UINT, GetNumInterfaces)() override { + return uint32_t(m_Interfaces.size()); + } + + STDMETHOD(ImplementsInterface)(ID3D12ShaderReflectionType *pBase) override { + + for (CHLSLReflectionType *interf : m_Interfaces) + if (pBase == interf) + return S_OK; + + return S_FALSE; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetInterfaceByIndex) + (UINT uIndex) override { + + if (uIndex >= m_Interfaces.size()) + return nullptr; + + return m_Interfaces[uIndex]; + } +}; + +class CHLSLFunctionParameter final : public ID3D12FunctionParameterReflection { + +protected: + const ReflectionData *m_Data = nullptr; + uint32_t m_NodeId = 0; + +public: + CHLSLFunctionParameter() = default; + + void Initialize(const ReflectionData &Data, uint32_t NodeId) { + m_Data = &Data; + m_NodeId = NodeId; + } + + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_PARAMETER_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + const ReflectionNode &node = m_Data->Nodes[m_NodeId]; + + LPCSTR semanticName = + node.GetSemanticId() == uint32_t(-1) + ? "" + : m_Data->StringsNonDebug[node.GetSemanticId()].c_str(); + + LPCSTR name = + m_Data->Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? m_Data->Strings[m_Data->NodeSymbols[m_NodeId].GetNameId()].c_str() + : ""; + + const ReflectionFunctionParameter ¶m = + m_Data->Parameters[node.GetLocalId()]; + const ReflectionVariableType &type = m_Data->Types[param.TypeId]; + + *pDesc = D3D12_PARAMETER_DESC{name, + semanticName, + type.GetType(), + type.GetClass(), + type.GetRows(), + type.GetColumns(), + node.GetInterpolationMode(), + D3D_PARAMETER_FLAGS(param.Flags)}; + + return S_OK; + } +}; + +class CHLSLReflectionVariable final : public ID3D12ShaderReflectionVariable { +protected: + CHLSLReflectionType *m_pType; + CHLSLReflectionConstantBuffer *m_pBuffer; + std::string m_Name; + +public: + void Initialize(CHLSLReflectionConstantBuffer *pBuffer, + CHLSLReflectionType *pType, std::string &&Name) { + m_pBuffer = pBuffer; + m_pType = pType; + m_Name = Name; + } + + LPCSTR GetName() const { return m_Name.c_str(); } + + STDMETHOD(GetDesc)(D3D12_SHADER_VARIABLE_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + *pDesc = D3D12_SHADER_VARIABLE_DESC{ + GetName(), + 0, // TODO: offset and size next time + 0, D3D_SVF_USED, NULL, uint32_t(-1), 0, uint32_t(-1), 0}; + + return S_OK; + } + + STDMETHOD_(ID3D12ShaderReflectionType *, GetType) + () override { return m_pType; } + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetBuffer)() override; + + STDMETHOD_(UINT, GetInterfaceSlot)(UINT uArrayIndex) override { + return UINT_MAX; + } +}; + +class CHLSLReflectionConstantBuffer final + : public ID3D12ShaderReflectionConstantBuffer { +protected: + const ReflectionData *m_Data; + uint32_t m_ChildCount; + D3D_CBUFFER_TYPE m_BufferType; + std::vector m_Variables; + std::unordered_map m_VariablesByName; + + // For StructuredBuffer arrays, Name will have [0] appended for each dimension + // to match fxc behavior. + std::string m_ReflectionName; + +public: + CHLSLReflectionConstantBuffer() = default; + CHLSLReflectionConstantBuffer(CHLSLReflectionConstantBuffer &&other) { + m_BufferType = other.m_BufferType; + m_Data = other.m_Data; + m_ChildCount = other.m_ChildCount; + std::swap(m_ReflectionName, other.m_ReflectionName); + std::swap(m_Variables, other.m_Variables); + std::swap(m_VariablesByName, other.m_VariablesByName); + } + + void Initialize(const ReflectionData &Data, uint32_t NodeId, + const std::unordered_map> + &ChildrenNonRecursive, + CHLSLReflectionConstantBuffer *ConstantBuffer, + std::vector &Types) { + + if (NodeId >= Data.Nodes.size()) + return; + + const ReflectionNode &node = Data.Nodes[NodeId]; + + if (node.GetNodeType() != D3D12_HLSL_NODE_TYPE_REGISTER) + return; + + const std::vector &children = ChildrenNonRecursive.at(NodeId); + const ReflectionShaderResource ® = Data.Registers[node.GetLocalId()]; + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) { + + m_ReflectionName = Data.Strings[Data.NodeSymbols[NodeId].GetNameId()]; + + bool isCBuffer = reg.GetType() == D3D_SIT_CBUFFER; + + if (m_ReflectionName.size() && !isCBuffer) { + + uint32_t arrayDims = reg.GetArrayId() != uint32_t(-1) + ? Data.Arrays[reg.GetArrayId()].ArrayElem() + : (reg.GetBindCount() > 1 ? 1 : 0); + + for (unsigned i = 0; i < arrayDims; ++i) + m_ReflectionName += "[0]"; + } + } + + else + m_ReflectionName.clear(); + + m_Data = &Data; + m_ChildCount = uint32_t(children.size()); + m_BufferType = m_Data->Buffers[reg.GetBufferId()].Type; + + m_VariablesByName.clear(); + m_Variables.resize(children.size()); + + for (uint32_t i = 0; i < m_ChildCount; ++i) { + + uint32_t childId = children[i]; + + std::string name; + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + name = Data.Strings[Data.NodeSymbols[childId].GetNameId()]; + + uint32_t typeId = Data.Nodes[childId].GetLocalId(); + + m_Variables[i].Initialize(ConstantBuffer, &Types[typeId], + std::move(name)); + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + m_VariablesByName[m_Variables[i].GetName()] = i; + } + } + + //$Globals (only if the global scope contains any VARIABLE node) + void InitializeGlobals(const ReflectionData &Data, + const std::vector &Globals, + CHLSLReflectionConstantBuffer *ConstantBuffer, + std::vector &Types) { + + m_ReflectionName = "$Globals"; + + m_Data = &Data; + m_ChildCount = uint32_t(Globals.size()); + m_BufferType = D3D_CT_CBUFFER; + + m_VariablesByName.clear(); + m_Variables.resize(Globals.size()); + + for (uint32_t i = 0; i < m_ChildCount; ++i) { + + uint32_t childId = Globals[i]; + + std::string name; + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + name = Data.Strings[Data.NodeSymbols[childId].GetNameId()]; + + uint32_t typeId = Data.Nodes[childId].GetLocalId(); + + m_Variables[i].Initialize(ConstantBuffer, &Types[typeId], + std::move(name)); + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + m_VariablesByName[m_Variables[i].GetName()] = i; + } + } + + LPCSTR GetName() const { return m_ReflectionName.c_str(); } + + STDMETHOD(GetDesc)(D3D12_SHADER_BUFFER_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + *pDesc = D3D12_SHADER_BUFFER_DESC{ + GetName(), m_BufferType, m_ChildCount, + 0 // TODO: Size when we have it + }; + + return S_OK; + } + + STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByIndex) + (UINT Index) override { + + if (Index >= m_Variables.size()) + return &g_InvalidSRVariable; + + return &m_Variables[Index]; + } + + STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName) + (LPCSTR Name) override { + + if (NULL == Name) + return &g_InvalidSRVariable; + + auto it = m_VariablesByName.find(Name); + + if (it == m_VariablesByName.end()) + return &g_InvalidSRVariable; + + return &m_Variables[it->second]; + } +}; + +ID3D12ShaderReflectionConstantBuffer *CHLSLReflectionVariable::GetBuffer() { + return m_pBuffer; +} + +struct HLSLReflectionData : public IHLSLReflectionData { + + ReflectionData Data{}; + + std::atomic m_refCount; + + std::vector ChildCountsNonRecursive; + std::unordered_map> ChildrenNonRecursive; + + std::vector ConstantBuffers; + std::unordered_map NameToConstantBuffers; + + std::vector Types; + + enum class FwdDeclType { STRUCT, UNION, ENUM, FUNCTION, INTERFACE, COUNT }; + + std::vector NonFwdIds[int(FwdDeclType::COUNT)]; + + std::unordered_map + NameToNonFwdIds[int(FwdDeclType::COUNT)]; + + std::vector NodeToParameterId; + std::vector FunctionParameters; + + HLSLReflectionData() : m_refCount(1) {} + virtual ~HLSLReflectionData() = default; + + // TODO: This function needs another look definitely + void Finalize() { + + Data.GenerateNameLookupTable(); + + ChildCountsNonRecursive.resize(Data.Nodes.size()); + ChildrenNonRecursive.clear(); + + bool hasSymbols = Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + std::vector globalVars; + + NodeToParameterId.resize(Data.Nodes.size()); + + std::vector functionParameters; + functionParameters.reserve(Data.Nodes.size() / 4); + + for (uint32_t i = 0; i < uint32_t(Data.Nodes.size()); ++i) { + + const ReflectionNode &node = Data.Nodes[i]; + + if (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_VARIABLE && + !node.GetParentId()) + globalVars.push_back(i); + + if (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_PARAMETER) { + NodeToParameterId[i] = uint32_t(functionParameters.size()); + functionParameters.push_back(i); + } + + // Filter out backward/fwd declarations for structs, unions, interfaces, + // functions, enums + + if (node.IsFwdDeclare()) { + ChildCountsNonRecursive[i] = uint32_t(ChildrenNonRecursive[i].size()); + continue; + } + + FwdDeclType type = FwdDeclType::COUNT; + + switch (node.GetNodeType()) { + + case D3D12_HLSL_NODE_TYPE_STRUCT: + type = FwdDeclType::STRUCT; + break; + + case D3D12_HLSL_NODE_TYPE_UNION: + type = FwdDeclType::UNION; + break; + + case D3D12_HLSL_NODE_TYPE_INTERFACE: + type = FwdDeclType::INTERFACE; + break; + + case D3D12_HLSL_NODE_TYPE_FUNCTION: + type = FwdDeclType::FUNCTION; + break; + + case D3D12_HLSL_NODE_TYPE_ENUM: + type = FwdDeclType::ENUM; + break; + } + + if (type != FwdDeclType::COUNT) { + + uint32_t typeId = node.GetLocalId(); + + NonFwdIds[int(type)].push_back(typeId); + + if (hasSymbols) + NameToNonFwdIds[int(type)][Data.NodeIdToFullyResolved[i]] = typeId; + } + + for (uint32_t j = 0; j < node.GetChildCount(); ++j) { + + const ReflectionNode &nodej = Data.Nodes[i + 1 + j]; + + // Filter out definitions that were previously fwd declared + // And resolve fwd declarations + + if (nodej.IsFwdDeclare() && nodej.IsFwdBckDefined()) + ChildrenNonRecursive[i].push_back(nodej.GetFwdBck()); + + if (!nodej.IsFwdBckDefined()) + ChildrenNonRecursive[i].push_back(i + 1 + j); + + j += nodej.GetChildCount(); + } + + ChildCountsNonRecursive[i] = uint32_t(ChildrenNonRecursive[i].size()); + } + + NameToConstantBuffers.clear(); + ConstantBuffers.resize(Data.Buffers.size() + !globalVars.empty()); + Types.resize(Data.Types.size()); + + for (uint32_t i = 0; i < (uint32_t)Data.Types.size(); ++i) + Types[i].Initialize(Data, i, Types); + + FunctionParameters.resize(functionParameters.size()); + + for (uint32_t i = 0; i < uint32_t(functionParameters.size()); ++i) + FunctionParameters[i].Initialize(Data, functionParameters[i]); + + for (uint32_t i = 0; i < (uint32_t)Data.Buffers.size(); ++i) { + + ConstantBuffers[i].Initialize(Data, Data.Buffers[i].NodeId, + ChildrenNonRecursive, &ConstantBuffers[i], + Types); + + if (hasSymbols) + NameToConstantBuffers[ConstantBuffers[i].GetName()] = i; + } + + if (globalVars.size()) + ConstantBuffers[Data.Buffers.size()].InitializeGlobals( + Data, globalVars, &ConstantBuffers[Data.Buffers.size()], Types); + } + + HLSLReflectionData(ReflectionData &&moved) = delete; + HLSLReflectionData &operator=(HLSLReflectionData &&moved) = delete; + + // IUnknown + + STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override { + if (!ppvObject) + return E_POINTER; + + if (riid == IID_IHLSLReflectionData) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + *ppvObject = nullptr; + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)() override { return ++m_refCount; } + + STDMETHOD_(ULONG, Release)() override { + ULONG count = --m_refCount; + if (!count) + delete this; + return count; + } + + // Conversion of IReflection structs to D3D12_HLSL standardized structs + + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_HLSL_REFLECTION_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + *pDesc = {Data.Features, + uint32_t(Data.Buffers.size()), + uint32_t(Data.Registers.size()), + uint32_t(NonFwdIds[int(FwdDeclType::FUNCTION)].size()), + uint32_t(NonFwdIds[int(FwdDeclType::ENUM)].size()), + uint32_t(Data.Nodes.size()), + uint32_t(Data.Types.size()), + uint32_t(NonFwdIds[int(FwdDeclType::STRUCT)].size()), + uint32_t(NonFwdIds[int(FwdDeclType::UNION)].size()), + uint32_t(NonFwdIds[int(FwdDeclType::INTERFACE)].size())}; + + return S_OK; + } + + STDMETHOD(GetResourceBindingDesc) + (THIS_ _In_ UINT ResourceIndex, + _Out_ D3D12_SHADER_INPUT_BIND_DESC1 *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + if (ResourceIndex >= Data.Registers.size()) + return E_INVALIDARG; + + const ReflectionShaderResource ® = Data.Registers[ResourceIndex]; + + LPCSTR name = + Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? Data.Strings[Data.NodeSymbols[reg.GetNodeId()].GetNameId()] + .c_str() + : ""; + + if (reg.GetBindCount() > 1) { + + if (reg.GetArrayId() != uint32_t(-1)) { + + const ReflectionArray &arr = Data.Arrays[reg.GetArrayId()]; + + pDesc->ArrayInfo.ArrayDims = arr.ArrayElem(); + + for (uint32_t i = 0; i < pDesc->ArrayInfo.ArrayDims; ++i) + pDesc->ArrayInfo.ArrayLengths[i] = + Data.ArraySizes[arr.ArrayStart() + i]; + } + + else { + pDesc->ArrayInfo.ArrayDims = 1; + pDesc->ArrayInfo.ArrayLengths[0] = reg.GetBindCount(); + } + } + + pDesc->Desc = D3D12_SHADER_INPUT_BIND_DESC{ + name, reg.GetType(), + uint32_t(-1), // Invalid bindPoint, depending on backend we might + // want to change it + reg.GetBindCount(), + + reg.GetFlags(), reg.GetReturnType(), reg.GetDimension(), + uint32_t(-1), // Also no valid data depending on backend + uint32_t(-1), // Invalid space (see bindPoint ^) + reg.GetNodeId()}; + + return S_OK; + } + + STDMETHOD(GetEnumDesc) + (THIS_ _In_ UINT EnumIndex, _Out_ D3D12_HLSL_ENUM_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + if (EnumIndex >= NonFwdIds[int(FwdDeclType::ENUM)].size()) + return E_INVALIDARG; + + const ReflectionEnumeration &enm = + Data.Enums[NonFwdIds[int(FwdDeclType::ENUM)][EnumIndex]]; + + LPCSTR name = + Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? Data.Strings[Data.NodeSymbols[enm.NodeId].GetNameId()].c_str() + : ""; + + *pDesc = D3D12_HLSL_ENUM_DESC{ + name, uint32_t(Data.Nodes[enm.NodeId].GetChildCount()), enm.Type, enm.NodeId}; + + return S_OK; + } + + STDMETHOD(GetEnumValueByIndex) + (THIS_ _In_ UINT EnumIndex, _In_ UINT ValueIndex, + _Out_ D3D12_HLSL_ENUM_VALUE *pValueDesc) override { + + IFR(ZeroMemoryToOut(pValueDesc)); + + if (EnumIndex >= NonFwdIds[int(FwdDeclType::ENUM)].size()) + return E_INVALIDARG; + + const ReflectionEnumeration &enm = + Data.Enums[NonFwdIds[int(FwdDeclType::ENUM)][EnumIndex]]; + const ReflectionNode &parent = Data.Nodes[enm.NodeId]; + + if (ValueIndex >= parent.GetChildCount()) + return E_INVALIDARG; + + LPCSTR name = + Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? Data.Strings[Data.NodeSymbols[enm.NodeId].GetNameId()].c_str() + : ""; + + const ReflectionNode &node = Data.Nodes[enm.NodeId + 1 + ValueIndex]; + + *pValueDesc = D3D12_HLSL_ENUM_VALUE{ + name, Data.EnumValues[node.GetLocalId()].Value, enm.NodeId}; + + return S_OK; + } + + STDMETHOD(GetAnnotationByIndex) + (THIS_ _In_ UINT NodeId, _In_ UINT Index, + _Out_ D3D12_HLSL_ANNOTATION *pAnnotation) override { + + IFR(ZeroMemoryToOut(pAnnotation)); + + if (NodeId >= Data.Nodes.size()) + return E_INVALIDARG; + + const ReflectionNode &node = Data.Nodes[NodeId]; + + if (Index >= node.GetAnnotationCount()) + return E_INVALIDARG; + + const ReflectionAnnotation &annotation = + Data.Annotations[node.GetAnnotationStart() + Index]; + + *pAnnotation = D3D12_HLSL_ANNOTATION{ + Data.StringsNonDebug[annotation.GetStringNonDebug()].c_str(), + annotation.GetIsBuiltin()}; + + return S_OK; + } + + STDMETHOD(GetFunctionDesc) + (THIS_ _In_ UINT FunctionIndex, + THIS_ _Out_ D3D12_HLSL_FUNCTION_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + if (FunctionIndex >= NonFwdIds[int(FwdDeclType::FUNCTION)].size()) + return E_INVALIDARG; + + const ReflectionFunction &func = + Data.Functions[NonFwdIds[int(FwdDeclType::FUNCTION)][FunctionIndex]]; + + LPCSTR name = + Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? Data.Strings[Data.NodeSymbols[func.GetNodeId()].GetNameId()] + .c_str() + : ""; + + *pDesc = D3D12_HLSL_FUNCTION_DESC{name, func.GetNumParameters(), + func.HasReturn(), func.GetNodeId()}; + + return S_OK; + } + + STDMETHOD(GetNodeDesc) + (THIS_ _In_ UINT NodeId, _Out_ D3D12_HLSL_NODE *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + if (NodeId >= Data.Nodes.size()) + return E_INVALIDARG; + + LPCSTR name = + Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO + ? Data.Strings[Data.NodeSymbols[NodeId].GetNameId()].c_str() + : ""; + + const ReflectionNode &node = Data.Nodes[NodeId]; + + uint32_t localId = node.GetLocalId(); + uint32_t parentId = node.GetParentId(); + + // Real local id is at definition + + if (node.IsFwdDeclare()) { + if (node.IsFwdBckDefined()) + localId = Data.Nodes[node.GetFwdBck()].GetLocalId(); + } + + // Real parent is at declaration + + else if (node.IsFwdBckDefined()) + parentId = Data.Nodes[node.GetFwdBck()].GetParentId(); + + LPCSTR semantic = ""; + + if (node.GetSemanticId() != uint32_t(-1)) + semantic = Data.StringsNonDebug[node.GetSemanticId()].c_str(); + + *pDesc = D3D12_HLSL_NODE{name, + semantic, + node.GetNodeType(), + localId, + ChildCountsNonRecursive[NodeId], + parentId, + node.GetAnnotationCount(), + node.IsFwdBckDefined() ? node.GetFwdBck() + : uint32_t(-1), + node.IsFwdDeclare(), + node.GetInterpolationMode()}; + + return S_OK; + } + + STDMETHOD(GetChildNode) + (THIS_ _In_ UINT NodeId, THIS_ _In_ UINT ChildId, + _Out_ UINT *pChildNodeId) override { + + IFR(ZeroMemoryToOut(pChildNodeId)); + + if (NodeId >= Data.Nodes.size()) + return E_INVALIDARG; + + auto it = ChildrenNonRecursive.find(NodeId); + + if (it == ChildrenNonRecursive.end() || ChildId >= it->second.size()) + return E_INVALIDARG; + + *pChildNodeId = it->second[ChildId]; + return S_OK; + } + + STDMETHOD(GetChildDesc) + (THIS_ _In_ UINT NodeId, THIS_ _In_ UINT ChildId, + _Out_ D3D12_HLSL_NODE *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + uint32_t childNodeId; + IFR(GetChildNode(NodeId, ChildId, &childNodeId)); + + return GetNodeDesc(childNodeId, pDesc); + } + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex) + (THIS_ _In_ UINT Index) override { + + if (Index >= ConstantBuffers.size()) + return &g_InvalidSRConstantBuffer; + + return &ConstantBuffers[Index]; + } + + STDMETHOD(GetTypeByIndex) + (THIS_ _In_ UINT Index, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (Index >= Types.size()) + return E_INVALIDARG; + + *ppType = &Types[Index]; + return S_OK; + } + + // Use D3D_RETURN_PARAMETER_INDEX to get description of the return value. + STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter) + (THIS_ _In_ UINT FunctionIndex, THIS_ _In_ INT ParameterIndex) override { + + if (FunctionIndex >= Data.Functions.size()) + return nullptr; + + const ReflectionFunction &func = Data.Functions[FunctionIndex]; + + if (ParameterIndex == D3D_RETURN_PARAMETER_INDEX) { + + if (!func.HasReturn()) + return nullptr; + + uint32_t parameterId = + NodeToParameterId[func.GetNodeId() + 1 + func.GetNumParameters()]; + + return &FunctionParameters[parameterId]; + } + + if (uint32_t(ParameterIndex) >= func.GetNumParameters()) + return nullptr; + + uint32_t parameterId = + NodeToParameterId[func.GetNodeId() + 1 + ParameterIndex]; + return &FunctionParameters[parameterId]; + } + + STDMETHOD(GetStructTypeByIndex) + (THIS_ _In_ UINT Index, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (Index >= NonFwdIds[int(FwdDeclType::STRUCT)].size()) + return E_INVALIDARG; + + *ppType = &Types[NonFwdIds[int(FwdDeclType::STRUCT)][Index]]; + return S_OK; + } + + STDMETHOD(GetUnionTypeByIndex) + (THIS_ _In_ UINT Index, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (Index >= NonFwdIds[int(FwdDeclType::UNION)].size()) + return E_INVALIDARG; + + *ppType = &Types[NonFwdIds[int(FwdDeclType::UNION)][Index]]; + return S_OK; + } + + STDMETHOD(GetInterfaceTypeByIndex) + (THIS_ _In_ UINT Index, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (Index >= NonFwdIds[int(FwdDeclType::INTERFACE)].size()) + return E_INVALIDARG; + + *ppType = &Types[NonFwdIds[int(FwdDeclType::INTERFACE)][Index]]; + return S_OK; + } + + STDMETHOD(GetNodeSymbolDesc) + (THIS_ _In_ UINT NodeId, _Out_ D3D12_HLSL_NODE_SYMBOL *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + if (!(Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO)) + return E_UNEXPECTED; + + if (NodeId >= Data.Nodes.size()) + return E_INVALIDARG; + + const ReflectionNodeSymbol &nodeSymbol = Data.NodeSymbols[NodeId]; + + *pDesc = D3D12_HLSL_NODE_SYMBOL{ + Data.Strings[Data.Sources[nodeSymbol.GetFileSourceId()]].c_str(), + nodeSymbol.GetSourceLineStart(), nodeSymbol.GetSourceLineCount(), + nodeSymbol.GetSourceColumnStart(), nodeSymbol.GetSourceColumnEnd()}; + + return S_OK; + } + + // Helper for conversion between symbol names + + STDMETHOD(GetNodeByName) + (THIS_ _In_ LPCSTR Name, _Out_ UINT *pNodeId) override { + + if (!Name || !pNodeId) + return E_POINTER; + + *pNodeId = (UINT)-1; + + auto it = Data.FullyResolvedToNodeId.find(Name); + + if (it == Data.FullyResolvedToNodeId.end()) + return E_INVALIDARG; + + *pNodeId = it->second; + return S_OK; + } + + STDMETHOD(GetNodeDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_NODE *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + return GetNodeDesc(nodeId, pDesc); + } + + STDMETHOD(GetNodeSymbolDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_NODE_SYMBOL *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + return GetNodeSymbolDesc(nodeId, pDesc); + } + + STDMETHOD(GetResourceBindingDescByName) + (THIS_ _In_ LPCSTR Name, + _Out_ D3D12_SHADER_INPUT_BIND_DESC1 *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + const ReflectionNode &node = Data.Nodes[nodeId]; + + if (node.GetNodeType() != D3D12_HLSL_NODE_TYPE_REGISTER) + return E_INVALIDARG; + + return GetResourceBindingDesc(node.GetLocalId(), pDesc); + } + + STDMETHOD(GetEnumDescByName) + (THIS_ _In_ LPCSTR Name, _Out_ D3D12_HLSL_ENUM_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + const ReflectionNode &node = Data.Nodes[nodeId]; + + if (node.IsFwdDeclare()) + return E_UNEXPECTED; + + if (node.GetNodeType() != D3D12_HLSL_NODE_TYPE_ENUM) + return E_INVALIDARG; + + return GetEnumDesc(node.GetLocalId(), pDesc); + } + + STDMETHOD(GetEnumValueByNameAndIndex) + (THIS_ _In_ LPCSTR Name, _In_ UINT ValueIndex, + _Out_ D3D12_HLSL_ENUM_VALUE *pValueDesc) override { + + IFR(ZeroMemoryToOut(pValueDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + const ReflectionNode &node = Data.Nodes[nodeId]; + + if (node.IsFwdDeclare()) + return E_UNEXPECTED; + + if (node.GetNodeType() != D3D12_HLSL_NODE_TYPE_ENUM) + return E_INVALIDARG; + + return GetEnumValueByIndex(node.GetLocalId(), ValueIndex, pValueDesc); + } + + STDMETHOD(GetAnnotationByIndexAndName) + (THIS_ _In_ LPCSTR Name, _In_ UINT Index, + _Out_ D3D12_HLSL_ANNOTATION *pAnnotation) override { + + IFR(ZeroMemoryToOut(pAnnotation)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + return GetAnnotationByIndex(nodeId, Index, pAnnotation); + } + + STDMETHOD(GetFunctionDescByName) + (THIS_ _In_ LPCSTR Name, + THIS_ _Out_ D3D12_HLSL_FUNCTION_DESC *pDesc) override { + + IFR(ZeroMemoryToOut(pDesc)); + + UINT nodeId; + IFR(GetNodeByName(Name, &nodeId)); + + const ReflectionNode &node = Data.Nodes[nodeId]; + + if (node.GetNodeType() != D3D12_HLSL_NODE_TYPE_FUNCTION) + return E_INVALIDARG; + + return GetFunctionDesc(node.GetLocalId(), pDesc); + } + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName) + (THIS_ _In_ LPCSTR Name) override { + + if (!Name) + return &g_InvalidSRConstantBuffer; + + auto it = NameToConstantBuffers.find(Name); + + if (it == NameToConstantBuffers.end()) + return &g_InvalidSRConstantBuffer; + + return &ConstantBuffers[it->second]; + } + + STDMETHOD(GetStructTypeByName) + (THIS_ _In_ LPCSTR Name, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (!Name) + return E_POINTER; + + if (!(Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO)) + return E_INVALIDARG; + + auto it = NameToNonFwdIds[int(FwdDeclType::STRUCT)].find(Name); + + if (it == NameToNonFwdIds[int(FwdDeclType::STRUCT)].end()) + return E_INVALIDARG; + + *ppType = &Types[it->second]; + return S_OK; + } + + STDMETHOD(GetUnionTypeByName) + (THIS_ _In_ LPCSTR Name, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (!Name) + return E_POINTER; + + if (!(Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO)) + return E_INVALIDARG; + + auto it = NameToNonFwdIds[int(FwdDeclType::UNION)].find(Name); + + if (it == NameToNonFwdIds[int(FwdDeclType::UNION)].end()) + return E_INVALIDARG; + + *ppType = &Types[it->second]; + return S_OK; + } + + STDMETHOD(GetInterfaceTypeByName) + (THIS_ _In_ LPCSTR Name, + _Outptr_ ID3D12ShaderReflectionType **ppType) override { + + IFR(ZeroMemoryToOut(ppType)); + + if (!Name) + return E_POINTER; + + if (!(Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO)) + return E_INVALIDARG; + + auto it = NameToNonFwdIds[int(FwdDeclType::INTERFACE)].find(Name); + + if (it == NameToNonFwdIds[int(FwdDeclType::INTERFACE)].end()) + return E_INVALIDARG; + + *ppType = &Types[it->second]; + return S_OK; + } +}; + +namespace { + +std::string DefinesToString(DxcDefine *pDefines, UINT32 defineCount) { + std::string defineStr; + for (UINT32 i = 0; i < defineCount; i++) { + CW2A utf8Name(pDefines[i].Name); + CW2A utf8Value(pDefines[i].Value); + defineStr += "#define "; + defineStr += utf8Name; + defineStr += " "; + defineStr += utf8Value ? utf8Value.m_psz : "1"; + defineStr += "\n"; + } + + return defineStr; +} + +bool IsAbsoluteOrCurDirRelative(const llvm::Twine &T) { + if (llvm::sys::path::is_absolute(T)) { + return true; + } + if (T.isSingleStringRef()) { + StringRef r = T.getSingleStringRef(); + if (r.size() < 2) + return false; + const char *pData = r.data(); + return pData[0] == '.' && (pData[1] == '\\' || pData[1] == '/'); + } + DXASSERT(false, "twine kind not supported"); + return false; +} + +void SetupCompilerCommon(CompilerInstance &compiler, + DxcLangExtensionsHelper *helper, LPCSTR pMainFile, + TextDiagnosticPrinter *diagPrinter, + ASTUnit::RemappedFile *rewrite, + hlsl::options::DxcOpts &opts) { + // Setup a compiler instance. + std::shared_ptr targetOptions(new TargetOptions); + targetOptions->Triple = llvm::sys::getDefaultTargetTriple(); + compiler.HlslLangExtensions = helper; + compiler.createDiagnostics(diagPrinter, false); + compiler.createFileManager(); + compiler.createSourceManager(compiler.getFileManager()); + compiler.setTarget( + TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions)); + // Not use builtin includes. + compiler.getHeaderSearchOpts().UseBuiltinIncludes = false; + + if (opts.WarningAsError) + compiler.getDiagnostics().setWarningsAsErrors(true); + compiler.getLangOpts().HLSLVersion = opts.HLSLVersion; + compiler.getLangOpts().PreserveUnknownAnnotations = true; + compiler.getLangOpts().UseMinPrecision = !opts.Enable16BitTypes; + compiler.getDiagnostics().setIgnoreAllWarnings(!opts.OutputWarnings); + compiler.getCodeGenOpts().MainFileName = pMainFile; + + compiler.getLangOpts().HLSLProfile = compiler.getCodeGenOpts().HLSLProfile = + opts.TargetProfile; + + PreprocessorOptions &PPOpts = compiler.getPreprocessorOpts(); + if (rewrite != nullptr) { + if (llvm::MemoryBuffer *pMemBuf = rewrite->second) { + compiler.getPreprocessorOpts().addRemappedFile(StringRef(pMainFile), + pMemBuf); + } + + PPOpts.RemappedFilesKeepOriginalName = true; + } + + // Pick additional arguments. + clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts(); + HSOpts.UseBuiltinIncludes = 0; + // Consider: should we force-include '.' if the source file is relative? + for (const llvm::opt::Arg *A : opts.Args.filtered(options::OPT_I)) { + const bool IsFrameworkFalse = false; + const bool IgnoreSysRoot = true; + if (IsAbsoluteOrCurDirRelative(A->getValue())) { + HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, + IgnoreSysRoot); + } else { + std::string s("./"); + s += A->getValue(); + HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot); + } + } +} + +void SetupCompiler(CompilerInstance &compiler, DxcLangExtensionsHelper *helper, + LPCSTR pMainFile, TextDiagnosticPrinter *diagPrinter, + ASTUnit::RemappedFile *rewrite, hlsl::options::DxcOpts &opts, + LPCSTR pDefines, dxcutil::DxcArgsFileSystem *msfPtr) { + + SetupCompilerCommon(compiler, helper, pMainFile, diagPrinter, rewrite, opts); + + if (msfPtr) { + msfPtr->SetupForCompilerInstance(compiler); + } + + compiler.createPreprocessor(TU_Complete); + + if (pDefines) { + std::string newDefines = compiler.getPreprocessor().getPredefines(); + newDefines += pDefines; + compiler.getPreprocessor().setPredefines(newDefines); + } + + if (opts.Defines.size()) { + + std::string defines = + DefinesToString(opts.Defines.DefineVector.data(), opts.Defines.size()); + + compiler.getPreprocessor().setPredefines( + compiler.getPreprocessor().getPredefines() + defines); + } + + compiler.createASTContext(); + compiler.setASTConsumer(std::unique_ptr(new SemaConsumer())); + compiler.createSema(TU_Complete, nullptr); + + const FileEntry *mainFileEntry = + compiler.getFileManager().getFile(StringRef(pMainFile)); + if (mainFileEntry == nullptr) { + throw ::hlsl::Exception(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + } + compiler.getSourceManager().setMainFileID( + compiler.getSourceManager().createFileID(mainFileEntry, SourceLocation(), + SrcMgr::C_User)); +} + +HRESULT GenerateAST(DxcLangExtensionsHelper *pExtHelper, LPCSTR pFileName, + ASTUnit::RemappedFile *pRemap, DxcDefine *pDefines, + UINT32 defineCount, ASTHelper &astHelper, + hlsl::options::DxcOpts &opts, + dxcutil::DxcArgsFileSystem *msfPtr, raw_ostream &w) { + // Setup a compiler instance. + CompilerInstance &compiler = astHelper.compiler; + + std::unique_ptr diagPrinter = + llvm::make_unique(w, + &compiler.getDiagnosticOpts()); + std::string definesStr = DefinesToString(pDefines, defineCount); + + SetupCompiler(compiler, pExtHelper, pFileName, diagPrinter.get(), pRemap, + opts, defineCount > 0 ? definesStr.c_str() : nullptr, msfPtr); + + // Parse the source file. + compiler.getDiagnosticClient().BeginSourceFile(compiler.getLangOpts(), + &compiler.getPreprocessor()); + + ParseAST(compiler.getSema(), false, opts.RWOpt.SkipFunctionBody); + + ASTContext &C = compiler.getASTContext(); + TranslationUnitDecl *tu = C.getTranslationUnitDecl(); + astHelper.tu = tu; + + if (compiler.getDiagnosticClient().getNumErrors() > 0) { + astHelper.bHasErrors = true; + w.flush(); + return E_FAIL; + } + astHelper.bHasErrors = false; + return S_OK; +} + +HRESULT GetFromSource(DxcLangExtensionsHelper *pHelper, LPCSTR pFileName, + ASTUnit::RemappedFile *pRemap, + hlsl::options::DxcOpts &opts, DxcDefine *pDefines, + UINT32 defineCount, std::string &warnings, + std::string &result, dxcutil::DxcArgsFileSystem *msfPtr, + ReflectionData &reflection) { + + raw_string_ostream o(result); + raw_string_ostream w(warnings); + + ASTHelper astHelper; + + HRESULT hr = GenerateAST(pHelper, pFileName, pRemap, pDefines, defineCount, + astHelper, opts, msfPtr, w); + + if (FAILED(hr)) + return hr; + + if (astHelper.bHasErrors) + return E_FAIL; + + D3D12_HLSL_REFLECTION_FEATURE reflectMask = + D3D12_HLSL_REFLECTION_FEATURE_NONE; + + if (opts.ReflOpt.Basics) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_BASICS; + + if (opts.ReflOpt.Functions) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_FUNCTIONS; + + if (opts.ReflOpt.Namespaces) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_NAMESPACES; + + if (opts.ReflOpt.UserTypes) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES; + + if (opts.ReflOpt.Scopes) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_SCOPES; + + if (!reflectMask) + reflectMask = D3D12_HLSL_REFLECTION_FEATURE_ALL; + + if (!opts.ReflOpt.DisableSymbols) + reflectMask |= D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + ReflectionData refl; + + if (ReflectionError err = HLSLReflectionDataFromAST( + refl, astHelper.compiler, *astHelper.tu, opts.AutoBindingSpace, + reflectMask, opts.DefaultRowMajor)) { + fprintf(stderr, "HLSLReflectionDataFromAST failed %s\n", + err.toString().c_str()); + return E_FAIL; + } + + // Debug: Verify deserialization, otherwise print error. + +#ifndef NDEBUG + + std::vector bytes; + refl.Dump(bytes); + + ReflectionData deserialized; + + if (ReflectionError err = deserialized.Deserialize(bytes, true)) { + fprintf(stderr, "Deserialize failed %s\n", err.toString().c_str()); + return E_FAIL; + } + + if (!(deserialized == refl)) { + fprintf(stderr, "Dump or Deserialize doesn't match\n"); + return E_FAIL; + } + + // Test stripping symbols + + if (!opts.ReflOpt.DisableSymbols) { + + deserialized.StripSymbols(); + deserialized.Dump(bytes); + + ReflectionData deserialized2; + + if (ReflectionError err = deserialized2.Deserialize(bytes, true)) { + fprintf(stderr, "Deserialize failed %s\n", err.toString().c_str()); + return E_FAIL; + } + + if (!(deserialized2 == deserialized)) { + fprintf(stderr, "Dump or Deserialize doesn't match\n"); + return E_FAIL; + } + } + +#endif + + reflection = std::move(refl); + + // Flush and return results. + o.flush(); + w.flush(); + + return S_OK; +} + +HRESULT ReadOptsAndValidate(hlsl::options::MainArgs &mainArgs, + hlsl::options::DxcOpts &opts, + IDxcResult **ppResult) { + const llvm::opt::OptTable *table = ::options::getHlslOptTable(); + + CComPtr pOutputStream; + IFT(CreateMemoryStream(GetGlobalHeapMalloc(), &pOutputStream)); + raw_stream_ostream outStream(pOutputStream); + + if (0 != hlsl::options::ReadDxcOpts(table, + hlsl::options::HlslFlags::ReflectOption, + mainArgs, opts, outStream)) { + CComPtr pErrorBlob; + IFT(pOutputStream->QueryInterface(&pErrorBlob)); + outStream.flush(); + IFT(DxcResult::Create( + E_INVALIDARG, DXC_OUT_NONE, + {DxcOutputObject::ErrorOutput(opts.DefaultTextCodePage, + (LPCSTR)pErrorBlob->GetBufferPointer(), + pErrorBlob->GetBufferSize())}, + ppResult)); + return S_OK; + } + return S_OK; +} +} // namespace + +class DxcReflector : public IHLSLReflector, public IDxcLangExtensions3 { +private: + DXC_MICROCOM_TM_REF_FIELDS() + DxcLangExtensionsHelper m_langExtensionsHelper; + +public: + DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL() + DXC_MICROCOM_TM_CTOR(DxcReflector) + DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper) + + virtual ~DxcReflector() = default; + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, + void **ppvObject) override { + return DoBasicQueryInterface( + this, iid, ppvObject); + } + + HRESULT STDMETHODCALLTYPE FromSource( + IDxcBlobEncoding *pSource, + // Optional file name for pSource. Used in errors and include handlers. + LPCWSTR pSourceName, + // Compiler arguments + LPCWSTR *pArguments, UINT32 argCount, + // Defines + DxcDefine *pDefines, UINT32 defineCount, + // user-provided interface to handle #include directives (optional) + IDxcIncludeHandler *pIncludeHandler, IDxcResult **ppResult) override { + + if (pSource == nullptr || ppResult == nullptr || + (argCount > 0 && pArguments == nullptr) || + (defineCount > 0 && pDefines == nullptr)) + return E_POINTER; + + *ppResult = nullptr; + + DxcThreadMalloc TM(m_pMalloc); + + CComPtr utf8Source; + IFR(hlsl::DxcGetBlobAsUtf8(pSource, m_pMalloc, &utf8Source)); + + CW2A utf8SourceName(pSourceName); + LPCSTR fName = utf8SourceName.m_psz; + + try { + dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem( + utf8Source, pSourceName, pIncludeHandler); + std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr); + ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get()); + IFTLLVM(pts.error_code()); + + hlsl::options::MainArgs mainArgs(argCount, pArguments, 0); + + hlsl::options::DxcOpts opts; + + IFR(ReadOptsAndValidate(mainArgs, opts, ppResult)); + HRESULT hr; + if (*ppResult && SUCCEEDED((*ppResult)->GetStatus(&hr)) && FAILED(hr)) { + // Looks odd, but this call succeeded enough to allocate a result + return S_OK; + } + + StringRef Data(utf8Source->GetStringPointer(), + utf8Source->GetStringLength()); + std::unique_ptr pBuffer( + llvm::MemoryBuffer::getMemBufferCopy(Data, fName)); + std::unique_ptr pRemap( + new ASTUnit::RemappedFile(fName, pBuffer.release())); + + ReflectionData reflection; + + std::string errors; + std::string rewrite; + HRESULT status = GetFromSource(&m_langExtensionsHelper, fName, + pRemap.get(), opts, pDefines, defineCount, + errors, rewrite, msfPtr, reflection); + + std::vector Bytes; + + if (SUCCEEDED(status)) + reflection.Dump(Bytes); + + return DxcResult::Create( + status, DXC_OUT_OBJECT, + {DxcOutputObject::ObjectOutput(Bytes.data(), Bytes.size()), + DxcOutputObject::ErrorOutput(opts.DefaultTextCodePage, + errors.c_str())}, + ppResult); + } + CATCH_CPP_RETURN_HRESULT(); + } + + HRESULT STDMETHODCALLTYPE + FromBlob(IDxcBlob *data, IHLSLReflectionData **ppReflection) override { + + if (!data || !data->GetBufferSize() || !ppReflection) + return E_POINTER; + + std::vector bytes((const std::byte *)data->GetBufferPointer(), + (const std::byte *)data->GetBufferPointer() + + data->GetBufferSize()); + + HLSLReflectionData *reflectData = new HLSLReflectionData(); + *ppReflection = reflectData; + + try { + + if (ReflectionError err = reflectData->Data.Deserialize(bytes, true)) { + delete reflectData; + *ppReflection = nullptr; + fprintf(stderr, "Couldn't deserialize: %s\n", err.toString().c_str()); + return E_FAIL; + } + reflectData->Finalize(); + + return S_OK; + } catch (...) { + delete reflectData; + *ppReflection = nullptr; + return E_FAIL; + } + } + + HRESULT STDMETHODCALLTYPE ToBlob(IHLSLReflectionData *reflection, + IDxcBlob **ppResult) override { + + if (!reflection || !ppResult) + return E_POINTER; + + HLSLReflectionData *refl = dynamic_cast(reflection); + + if (!refl) + return E_UNEXPECTED; + + DxcThreadMalloc TM(m_pMalloc); + + std::vector bytes; + refl->Data.Dump(bytes); + + return DxcCreateBlobOnHeapCopy(bytes.data(), bytes.size(), ppResult); + } + + HRESULT STDMETHODCALLTYPE ToString(IHLSLReflectionData *reflection, + ReflectorFormatSettings Settings, + IDxcBlobEncoding **ppResult) override { + + if (!reflection || !ppResult) + return E_POINTER; + + HLSLReflectionData *refl = dynamic_cast(reflection); + + if (!refl) + return E_UNEXPECTED; + + DxcThreadMalloc TM(m_pMalloc); + std::string str = + refl->Data.ToJson(!Settings.PrintFileInfo, Settings.IsHumanReadable); + + return DxcCreateBlob(str.c_str(), str.size(), false, true, true, CP_UTF8, + DxcGetThreadMallocNoRef(), ppResult); + } +}; + +HRESULT CreateDxcReflector(REFIID riid, LPVOID *ppv) { + CComPtr isense = DxcReflector::Alloc(DxcGetThreadMallocNoRef()); + IFROOM(isense.p); + return isense.p->QueryInterface(riid, ppv); +} diff --git a/tools/clang/tools/dxcreflectioncontainer/CMakeLists.txt b/tools/clang/tools/dxcreflectioncontainer/CMakeLists.txt new file mode 100644 index 0000000000..474ee0ac02 --- /dev/null +++ b/tools/clang/tools/dxcreflectioncontainer/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (C) Microsoft Corporation. All rights reserved. +# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. + +add_clang_library(dxcreflectioncontainer STATIC DxcReflectionContainer.cpp DxcReflectionJson.cpp) + +if(MSVC) + target_compile_options(dxcreflectioncontainer PRIVATE /W4 /WX) +else() + target_compile_options(dxcreflectioncontainer PRIVATE -Wall -Wextra -Werror -Wno-pedantic) +endif() diff --git a/tools/clang/tools/dxcreflectioncontainer/DxcReflectionContainer.cpp b/tools/clang/tools/dxcreflectioncontainer/DxcReflectionContainer.cpp new file mode 100644 index 0000000000..5e07f10421 --- /dev/null +++ b/tools/clang/tools/dxcreflectioncontainer/DxcReflectionContainer.cpp @@ -0,0 +1,1366 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// DxcReflectionContainer.cpp // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include "dxc/DxcReflection/DxcReflectionContainer.h" +#include +#include + +#undef min +#undef max + +namespace hlsl { + +[[nodiscard]] ReflectionError +ReflectionData::RegisterString(uint32_t &StringId, const std::string &Name, + bool IsNonDebug) { + + if (Name.size() >= 32768) + return HLSL_REFL_ERR("Strings are limited to 32767"); + + if (IsNonDebug) { + + if (StringsNonDebug.size() >= uint32_t(-1)) + return HLSL_REFL_ERR("Strings overflow"); + + auto it = StringsToIdNonDebug.find(Name); + + if (it != StringsToIdNonDebug.end()) { + StringId = it->second; + return ReflectionErrorSuccess; + } + + uint32_t stringId = uint32_t(StringsNonDebug.size()); + + StringsNonDebug.push_back(Name); + StringsToIdNonDebug[Name] = stringId; + StringId = stringId; + return ReflectionErrorSuccess; + } + + if (Strings.size() >= uint32_t(-1)) + return HLSL_REFL_ERR("Strings overflow"); + + auto it = StringsToId.find(Name); + + if (it != StringsToId.end()) { + StringId = it->second; + return ReflectionErrorSuccess; + } + + uint32_t stringId = uint32_t(Strings.size()); + + Strings.push_back(Name); + StringsToId[Name] = stringId; + StringId = stringId; + return ReflectionErrorSuccess; +} + +[[nodiscard]] ReflectionError +ReflectionData::PushArray(uint32_t &ArrayId, uint32_t ArraySizeFlat, + const std::vector &ArraySize) { + + if (ArraySizeFlat <= 1 || ArraySize.size() <= 1) { + ArrayId = uint32_t(-1); + return ReflectionErrorSuccess; + } + + if (Arrays.size() >= uint32_t((1u << 31) - 1)) + return HLSL_REFL_ERR("Arrays would overflow"); + + uint32_t arrayId = uint32_t(Arrays.size()); + + uint32_t arrayCountStart = uint32_t(ArraySizes.size()); + uint32_t numArrayElements = std::min(size_t(32), ArraySize.size()); + + if (ArraySizes.size() + numArrayElements >= ((1u << 26) - 1)) + return HLSL_REFL_ERR("Array elements would overflow"); + + for (uint32_t i = 0; i < ArraySize.size() && i < 8; ++i) { + + uint32_t arraySize = ArraySize[i]; + + // Flatten rest of array to at least keep consistent array elements + if (i == 31) + for (uint32_t j = i + 1; j < ArraySize.size(); ++j) + arraySize *= ArraySize[j]; + + ArraySizes.push_back(arraySize); + } + + ReflectionArray arr; + + if (ReflectionError err = + ReflectionArray::Initialize(arr, numArrayElements, arrayCountStart)) + return err; + + for (uint32_t i = 0; i < Arrays.size(); ++i) + if (Arrays[i] == arr) { + ArrayId = i; + return ReflectionErrorSuccess; + } + + Arrays.push_back(arr); + ArrayId = arrayId; + return ReflectionErrorSuccess; +} + +[[nodiscard]] ReflectionError +ReflectionData::RegisterTypeList(const std::vector &TypeIds, + uint32_t &Offset, uint8_t &Len) { + + if (TypeIds.empty()) + return ReflectionErrorSuccess; + + if (TypeIds.size() >= uint8_t(-1)) + return HLSL_REFL_ERR("Only allowing 256 types in a type list"); + + uint32_t i = 0; + uint32_t j = uint32_t(TypeList.size()); + uint32_t k = 0; + + Offset = 0; + + for (; i < j; ++i) { + + if (k == TypeIds.size()) + break; + + if (TypeIds[k] != TypeList[i]) { + + if (k) + i = Offset; + + k = 0; + break; + } + + if (!k) + Offset = i; + + ++k; + } + + if (k != TypeIds.size()) { + + uint32_t oldSiz = uint32_t(TypeList.size()); + + if (oldSiz + TypeIds.size() >= (1u << 24)) + return HLSL_REFL_ERR("Only allowing 16Mi total interfaces"); + + TypeList.resize(oldSiz + TypeIds.size()); + + std::memcpy(TypeList.data() + oldSiz, TypeIds.data(), + TypeIds.size() * sizeof(uint32_t)); + + Offset = oldSiz; + } + + Len = uint8_t(TypeIds.size()); + return ReflectionErrorSuccess; +} + +struct HLSLReflectionDataHeader { + + uint32_t MagicNumber; + uint16_t Version; + uint16_t Sources; + + D3D12_HLSL_REFLECTION_FEATURE Features; + uint32_t StringsNonDebug; + + uint32_t Strings; + uint32_t Nodes; + + uint32_t Registers; + uint32_t Functions; + + uint32_t Enums; + uint32_t EnumValues; + + uint32_t Annotations; + uint32_t Arrays; + + uint32_t ArraySizes; + uint32_t Members; + + uint32_t Types; + uint32_t Buffers; + + uint32_t TypeListCount; + uint32_t Parameters; + + uint32_t Statements; + uint32_t IfSwitchStatements; + + uint32_t BranchStatements; + uint32_t Pad; +}; + +template +T &UnsafeCast(std::vector &Bytes, uint64_t Offset) { + return *(T *)(Bytes.data() + Offset); +} + +template +const T &UnsafeCast(const std::vector &Bytes, uint64_t Offset) { + return *(const T *)(Bytes.data() + Offset); +} + +template void SkipPadding(uint64_t &Offset) { + Offset = (Offset + alignof(T) - 1) / alignof(T) * alignof(T); +} + +template void Skip(uint64_t &Offset, const std::vector &Vec) { + Offset += Vec.size() * sizeof(T); +} + +template +void Advance(uint64_t &Offset, const std::vector &Vec) { + SkipPadding(Offset); + Skip(Offset, Vec); +} + +template <> +void Advance(uint64_t &Offset, + const std::vector &Vec) { + for (const std::string &str : Vec) { + Offset += str.size() >= 128 ? 2 : 1; + Offset += str.size(); + } +} + +template +void Advance(uint64_t &Offset, const std::vector &Vec, + const std::vector &Vec2, args... arg) { + Advance(Offset, Vec); + Advance(Offset, Vec2, arg...); +} + +template +void Append(std::vector &Bytes, uint64_t &Offset, + const std::vector &Vec) { + static_assert(std::is_pod_v, "Append only works on POD types"); + SkipPadding(Offset); + std::memcpy(&UnsafeCast(Bytes, Offset), Vec.data(), + Vec.size() * sizeof(T)); + Skip(Offset, Vec); +} + +template <> +void Append(std::vector &Bytes, uint64_t &Offset, + const std::vector &Vec) { + + for (const std::string &str : Vec) { + + if (str.size() >= 128) { + UnsafeCast(Bytes, Offset++) = + (uint8_t)(str.size() & 0x7F) | 0x80; + UnsafeCast(Bytes, Offset++) = (uint8_t)(str.size() >> 7); + } + + else + UnsafeCast(Bytes, Offset++) = (uint8_t)str.size(); + + std::memcpy(&UnsafeCast(Bytes, Offset), str.data(), str.size()); + Offset += str.size(); + } +} + +template +void Append(std::vector &Bytes, uint64_t &Offset, + const std::vector &Vec, const std::vector &Vec2, + args... arg) { + Append(Bytes, Offset, Vec); + Append(Bytes, Offset, Vec2, arg...); +} + +template >> +[[nodiscard]] ReflectionError Consume(const std::vector &Bytes, + uint64_t &Offset, T &t) { + + static_assert(std::is_pod_v, "Consume only works on POD types"); + + SkipPadding(Offset); + + if (Offset + sizeof(T) > Bytes.size()) + return HLSL_REFL_ERR("Couldn't consume; out of bounds!"); + + std::memcpy(&t, &UnsafeCast(Bytes, Offset), sizeof(T)); + Offset += sizeof(T); + + return ReflectionErrorSuccess; +} + +template +[[nodiscard]] ReflectionError Consume(const std::vector &Bytes, + uint64_t &Offset, T *target, + uint64_t Len) { + + static_assert(std::is_pod_v, "Consume only works on POD types"); + + SkipPadding(Offset); + + if (Offset + sizeof(T) * Len > Bytes.size()) + return HLSL_REFL_ERR("Couldn't consume; out of bounds!"); + + std::memcpy(target, &UnsafeCast(Bytes, Offset), sizeof(T) * Len); + Offset += sizeof(T) * Len; + + return ReflectionErrorSuccess; +} + +template +[[nodiscard]] ReflectionError Consume(const std::vector &Bytes, + uint64_t &Offset, std::vector &Vec, + uint64_t Len) { + Vec.resize(Len); + return Consume(Bytes, Offset, Vec.data(), Len); +} + +template <> +[[nodiscard]] ReflectionError +Consume(const std::vector &Bytes, uint64_t &Offset, + std::vector &Vec, uint64_t Len) { + Vec.resize(Len); + + for (uint64_t i = 0; i < Len; ++i) { + + if (Offset >= Bytes.size()) + return HLSL_REFL_ERR("Couldn't consume string len; out of bounds!"); + + uint16_t ourLen = uint8_t(Bytes.at(Offset++)); + + if (ourLen >> 7) { + + if (Offset >= Bytes.size()) + return HLSL_REFL_ERR("Couldn't consume string len; out of bounds!"); + + ourLen &= ~(1 << 7); + ourLen |= uint16_t(Bytes.at(Offset++)) << 7; + } + + if (Offset + ourLen > Bytes.size()) + return HLSL_REFL_ERR("Couldn't consume string len; out of bounds!"); + + Vec[i].resize(ourLen); + std::memcpy(Vec[i].data(), Bytes.data() + Offset, ourLen); + Offset += ourLen; + } + + return ReflectionErrorSuccess; +} + +template +[[nodiscard]] ReflectionError Consume(const std::vector &Bytes, + uint64_t &Offset, std::vector &Vec, + uint64_t Len, std::vector &Vec2, + uint64_t Len2, args &...arg) { + + if (ReflectionError err = Consume(Bytes, Offset, Vec, Len)) + return err; + + if (ReflectionError err = Consume(Bytes, Offset, Vec2, Len2, arg...)) + return err; + + return ReflectionErrorSuccess; +} + +static constexpr uint32_t ReflectionDataMagic = DXC_FOURCC('H', 'L', 'R', 'D'); +static constexpr uint16_t ReflectionDataVersion = 0; + +void ReflectionData::StripSymbols() { + Strings.clear(); + StringsToId.clear(); + Sources.clear(); + StringToSourceId.clear(); + FullyResolvedToNodeId.clear(); + NodeIdToFullyResolved.clear(); + FullyResolvedToMemberId.clear(); + NodeSymbols.clear(); + TypeSymbols.clear(); + MemberNameIds.clear(); + Features &= ~D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; +} + +void RecurseNameGenerationType(ReflectionData &Refl, uint32_t TypeId, + uint32_t LocalId, const std::string &Parent) { + + const ReflectionVariableType &type = Refl.Types[TypeId]; + + if (type.GetClass() == D3D_SVC_STRUCT) + for (uint32_t i = 0; i < type.GetMemberCount(); ++i) { + + uint32_t memberId = i + type.GetMemberStart(); + std::string memberName = + Parent + "." + Refl.Strings[Refl.MemberNameIds[memberId]]; + + Refl.FullyResolvedToMemberId[memberName] = memberId; + + RecurseNameGenerationType(Refl, Refl.MemberTypeIds[memberId], i, + memberName); + } +} + +uint32_t RecurseNameGeneration(ReflectionData &Refl, uint32_t NodeId, + uint32_t LocalId, const std::string &Parent, + bool IsDot) { + + ReflectionNode node = Refl.Nodes[NodeId]; + + if (node.IsFwdDeclare() && node.IsFwdBckDefined()) { + NodeId = node.GetFwdBck(); + node = Refl.Nodes[NodeId]; + } + + std::string self = Refl.Strings[Refl.NodeSymbols[NodeId].GetNameId()]; + + if (self.empty() && NodeId) + self = std::to_string(LocalId); + + self = Parent.empty() ? self : Parent + (IsDot ? "." : "::") + self; + Refl.FullyResolvedToNodeId[self] = NodeId; + Refl.NodeIdToFullyResolved[NodeId] = self; + + bool isDotChild = node.GetNodeType() == D3D12_HLSL_NODE_TYPE_REGISTER; + + bool isVar = node.GetNodeType() == D3D12_HLSL_NODE_TYPE_VARIABLE || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE; + + for (uint32_t i = 0, j = 0; i < node.GetChildCount(); ++i, ++j) + i += RecurseNameGeneration(Refl, NodeId + 1 + i, j, self, isDotChild); + + if (isVar) { + + uint32_t typeId = node.GetLocalId(); + const ReflectionVariableType &type = Refl.Types[typeId]; + + if (type.GetClass() == D3D_SVC_STRUCT) + for (uint32_t i = 0; i < type.GetMemberCount(); ++i) { + + uint32_t memberId = i + type.GetMemberStart(); + std::string memberName = + self + "." + Refl.Strings[Refl.MemberNameIds[memberId]]; + + Refl.FullyResolvedToMemberId[memberName] = memberId; + + RecurseNameGenerationType(Refl, Refl.MemberTypeIds[memberId], i, + memberName); + } + } + + return node.GetChildCount(); +} + +bool ReflectionData::GenerateNameLookupTable() { + + if (!(Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) || Nodes.empty()) + return false; + + NodeIdToFullyResolved.resize(Nodes.size()); + RecurseNameGeneration(*this, 0, 0, "", false); + return true; +} + +void ReflectionData::Dump(std::vector &Bytes) const { + + uint64_t toReserve = sizeof(HLSLReflectionDataHeader); + + Advance(toReserve, Strings, StringsNonDebug, Sources, Nodes, NodeSymbols, + Registers, Functions, Enums, EnumValues, Annotations, ArraySizes, + Arrays, MemberTypeIds, TypeList, MemberNameIds, Types, TypeSymbols, + Buffers, Parameters, Statements, IfSwitchStatements, + BranchStatements); + + Bytes.resize(toReserve); + + toReserve = 0; + + UnsafeCast(Bytes, toReserve) = { + ReflectionDataMagic, + ReflectionDataVersion, + uint16_t(Sources.size()), + Features, + uint32_t(StringsNonDebug.size()), + uint32_t(Strings.size()), + uint32_t(Nodes.size()), + uint32_t(Registers.size()), + uint32_t(Functions.size()), + uint32_t(Enums.size()), + uint32_t(EnumValues.size()), + uint32_t(Annotations.size()), + uint32_t(Arrays.size()), + uint32_t(ArraySizes.size()), + uint32_t(MemberTypeIds.size()), + uint32_t(Types.size()), + uint32_t(Buffers.size()), + uint32_t(TypeList.size()), + uint32_t(Parameters.size()), + uint32_t(Statements.size()), + uint32_t(IfSwitchStatements.size()), + uint32_t(BranchStatements.size())}; + + toReserve += sizeof(HLSLReflectionDataHeader); + + Append(Bytes, toReserve, Strings, StringsNonDebug, Sources, Nodes, + NodeSymbols, Registers, Functions, Enums, EnumValues, Annotations, + ArraySizes, Arrays, MemberTypeIds, TypeList, MemberNameIds, Types, + TypeSymbols, Buffers, Parameters, Statements, IfSwitchStatements, + BranchStatements); +} + +D3D_CBUFFER_TYPE ReflectionData::GetBufferType(uint8_t Type) { + + switch (Type) { + + case D3D_SIT_CBUFFER: + return D3D_CT_CBUFFER; + + case D3D_SIT_TBUFFER: + return D3D_CT_TBUFFER; + + case D3D_SIT_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED: + case D3D_SIT_UAV_APPEND_STRUCTURED: + case D3D_SIT_UAV_CONSUME_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: + return D3D_CT_RESOURCE_BIND_INFO; + + default: + return D3D_CT_INTERFACE_POINTERS; + } +} + +[[nodiscard]] ReflectionError +ReflectionData::Deserialize(const std::vector &Bytes, + bool MakeNameLookupTable) { + + *this = {}; + + uint64_t off = 0; + HLSLReflectionDataHeader header; + if (ReflectionError err = + Consume(Bytes, off, header)) + return err; + + if (header.MagicNumber != ReflectionDataMagic) + return HLSL_REFL_ERR("Invalid magic number"); + + if (header.Version != ReflectionDataVersion) + return HLSL_REFL_ERR("Unrecognized version number"); + + Features = header.Features; + + bool hasSymbolInfo = Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!hasSymbolInfo && (header.Sources || header.Strings)) + return HLSL_REFL_ERR("Sources are invalid without symbols"); + + uint32_t nodeSymbolCount = hasSymbolInfo ? header.Nodes : 0; + uint32_t memberSymbolCount = hasSymbolInfo ? header.Members : 0; + uint32_t typeSymbolCount = hasSymbolInfo ? header.Types : 0; + + if (ReflectionError err = Consume( + Bytes, off, Strings, header.Strings, StringsNonDebug, + header.StringsNonDebug, Sources, header.Sources, Nodes, header.Nodes, + NodeSymbols, nodeSymbolCount, Registers, header.Registers, Functions, + header.Functions, Enums, header.Enums, EnumValues, header.EnumValues, + Annotations, header.Annotations, ArraySizes, header.ArraySizes, + Arrays, header.Arrays, MemberTypeIds, header.Members, TypeList, + header.TypeListCount, MemberNameIds, memberSymbolCount, Types, + header.Types, TypeSymbols, typeSymbolCount, Buffers, header.Buffers, + Parameters, header.Parameters, Statements, header.Statements, + IfSwitchStatements, header.IfSwitchStatements, BranchStatements, + header.BranchStatements)) + return err; + + // Validation errors to prevent accessing invalid data + + if (off != Bytes.size()) + return HLSL_REFL_ERR("Reflection info had unrecognized data on the back"); + + for (uint32_t i = 0; i < header.Sources; ++i) + if (Sources[i] >= header.Strings) + return HLSL_REFL_ERR("Source path out of bounds", i); + + std::vector validateChildren; + + for (uint32_t i = 0; i < header.Nodes; ++i) { + + const ReflectionNode &node = Nodes[i]; + + if (hasSymbolInfo && (NodeSymbols[i].GetNameId() >= header.Strings || + (NodeSymbols[i].GetFileSourceId() != uint16_t(-1) && + NodeSymbols[i].GetFileSourceId() >= header.Sources))) + return HLSL_REFL_ERR("Node points to invalid name or file name", i); + + if (node.GetAnnotationStart() + node.GetAnnotationCount() > + header.Annotations || + node.GetNodeType() > D3D12_HLSL_NODE_TYPE_END || + (i && node.GetParentId() >= i) || + i + node.GetChildCount() > header.Nodes) + return HLSL_REFL_ERR("Node is invalid", i); + + if (node.GetSemanticId() != uint32_t(-1) && + node.GetSemanticId() >= header.StringsNonDebug) + return HLSL_REFL_ERR("Node points to invalid semantic id", i); + + if (node.GetInterpolationMode() < D3D_INTERPOLATION_UNDEFINED || + node.GetInterpolationMode() > + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE) + return HLSL_REFL_ERR("Node has invalid interpolation mode", i); + + uint32_t maxValue = 1; + bool allowFwdDeclare = false; + + switch (node.GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_REGISTER: + maxValue = header.Registers; + break; + + case D3D12_HLSL_NODE_TYPE_FUNCTION: + maxValue = header.Functions; + allowFwdDeclare = true; + break; + + case D3D12_HLSL_NODE_TYPE_ENUM: + maxValue = header.Enums; + allowFwdDeclare = true; + break; + case D3D12_HLSL_NODE_TYPE_ENUM_VALUE: + maxValue = header.EnumValues; + break; + + case D3D12_HLSL_NODE_TYPE_PARAMETER: + + maxValue = header.Parameters; + + if (Nodes[node.GetParentId()].GetNodeType() != + D3D12_HLSL_NODE_TYPE_FUNCTION) + return HLSL_REFL_ERR("Node is a parameter but parent isn't a function", + i); + + break; + + case D3D12_HLSL_NODE_TYPE_DEFAULT: + case D3D12_HLSL_NODE_TYPE_CASE: + + maxValue = header.BranchStatements; + + if (Nodes[node.GetParentId()].GetNodeType() != + D3D12_HLSL_NODE_TYPE_SWITCH) + return HLSL_REFL_ERR( + "Node is a default/case but doesn't belong to a switch", i); + break; + + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: + case D3D12_HLSL_NODE_TYPE_ELSE: + + maxValue = header.BranchStatements; + + if (Nodes[node.GetParentId()].GetNodeType() != + D3D12_HLSL_NODE_TYPE_IF_ROOT) + return HLSL_REFL_ERR( + "Node is a if/else if/else but doesn't belong to an if root node", + i); + + break; + + case D3D12_HLSL_NODE_TYPE_SCOPE: + case D3D12_HLSL_NODE_TYPE_DO: + case D3D12_HLSL_NODE_TYPE_IF_ROOT: + case D3D12_HLSL_NODE_TYPE_FOR: + case D3D12_HLSL_NODE_TYPE_WHILE: + case D3D12_HLSL_NODE_TYPE_SWITCH: + + maxValue = node.GetNodeType() != D3D12_HLSL_NODE_TYPE_SCOPE && + node.GetNodeType() != D3D12_HLSL_NODE_TYPE_DO + ? header.Statements + : 1; + + if (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_SWITCH || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_IF_ROOT) + maxValue = header.IfSwitchStatements; + + switch (Nodes[node.GetParentId()].GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_FUNCTION: + case D3D12_HLSL_NODE_TYPE_IF_ROOT: + case D3D12_HLSL_NODE_TYPE_SCOPE: + case D3D12_HLSL_NODE_TYPE_DO: + case D3D12_HLSL_NODE_TYPE_FOR: + case D3D12_HLSL_NODE_TYPE_WHILE: + case D3D12_HLSL_NODE_TYPE_SWITCH: + case D3D12_HLSL_NODE_TYPE_CASE: + case D3D12_HLSL_NODE_TYPE_DEFAULT: + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: + case D3D12_HLSL_NODE_TYPE_ELSE: + break; + + default: + return HLSL_REFL_ERR("Node is an stmt but " + "parent isn't of a similar " + "type or function", + i); + } + + break; + + case D3D12_HLSL_NODE_TYPE_USING: + case D3D12_HLSL_NODE_TYPE_TYPEDEF: + case D3D12_HLSL_NODE_TYPE_VARIABLE: + case D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE: + case D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE: + maxValue = header.Types; + break; + + case D3D12_HLSL_NODE_TYPE_STRUCT: + case D3D12_HLSL_NODE_TYPE_UNION: + case D3D12_HLSL_NODE_TYPE_INTERFACE: + allowFwdDeclare = true; + maxValue = node.IsFwdDeclare() ? 1 : header.Types; + break; + } + + switch (node.GetNodeType()) { + + case D3D12_HLSL_NODE_TYPE_USING: + case D3D12_HLSL_NODE_TYPE_TYPEDEF: + case D3D12_HLSL_NODE_TYPE_VARIABLE: + case D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE: + case D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE: + case D3D12_HLSL_NODE_TYPE_PARAMETER: + if (node.GetChildCount()) + return HLSL_REFL_ERR("Node is a parameter, typedef, variable or " + "static variable but also has children", + i); + break; + + case D3D12_HLSL_NODE_TYPE_IF_ROOT: + case D3D12_HLSL_NODE_TYPE_SCOPE: + case D3D12_HLSL_NODE_TYPE_DO: + case D3D12_HLSL_NODE_TYPE_FOR: + case D3D12_HLSL_NODE_TYPE_WHILE: + case D3D12_HLSL_NODE_TYPE_DEFAULT: + case D3D12_HLSL_NODE_TYPE_CASE: + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: + case D3D12_HLSL_NODE_TYPE_ELSE: + if (node.GetChildCount()) + validateChildren.push_back(i); + } + + if ((node.GetNodeType() == D3D12_HLSL_NODE_TYPE_REGISTER || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_VARIABLE) && + Nodes[node.GetParentId()].GetNodeType() == + D3D12_HLSL_NODE_TYPE_INTERFACE) + return HLSL_REFL_ERR("Node is interface but has registers or variables", + i); + + if (node.IsFwdDeclare() && !allowFwdDeclare) + return HLSL_REFL_ERR("Node is fwd declare but that's not permitted", i); + + if (node.GetLocalId() >= maxValue) + return HLSL_REFL_ERR("Node has invalid localId", i); + } + + for (uint32_t i = 0; i < header.Registers; ++i) { + + const ReflectionShaderResource ® = Registers[i]; + + if (reg.GetNodeId() >= header.Nodes || + Nodes[reg.GetNodeId()].GetNodeType() != D3D12_HLSL_NODE_TYPE_REGISTER || + Nodes[reg.GetNodeId()].GetLocalId() != i) + return HLSL_REFL_ERR("Register points to an invalid nodeId", i); + + if (reg.GetType() > D3D_SIT_UAV_FEEDBACKTEXTURE || + reg.GetReturnType() > D3D_RETURN_TYPE_CONTINUED || + reg.GetDimension() > D3D_SRV_DIMENSION_BUFFEREX || + !reg.GetBindCount() || + (reg.GetArrayId() != uint32_t(-1) && + reg.GetArrayId() >= header.Arrays) || + (reg.GetArrayId() != uint32_t(-1) && reg.GetBindCount() <= 1)) + return HLSL_REFL_ERR( + "Register invalid type, returnType, bindCount, array or dimension", + i); + + D3D_CBUFFER_TYPE bufferType = ReflectionData::GetBufferType(reg.GetType()); + + if (bufferType != D3D_CT_INTERFACE_POINTERS) { + + if (reg.GetBufferId() >= header.Buffers || + Buffers[reg.GetBufferId()].NodeId != reg.GetNodeId() || + Buffers[reg.GetBufferId()].Type != bufferType) + return HLSL_REFL_ERR("Register invalid buffer referenced by register", + i); + } + } + + for (uint32_t i = 0; i < header.Functions; ++i) { + + const ReflectionFunction &func = Functions[i]; + + if (func.GetNodeId() >= header.Nodes || + Nodes[func.GetNodeId()].GetNodeType() != + D3D12_HLSL_NODE_TYPE_FUNCTION || + Nodes[func.GetNodeId()].GetLocalId() != i) + return HLSL_REFL_ERR("Function points to an invalid nodeId", i); + + uint32_t paramCount = func.GetNumParameters() + func.HasReturn(); + + if (Nodes[func.GetNodeId()].GetChildCount() < paramCount) + return HLSL_REFL_ERR("Function is missing parameters and/or return", i); + + for (uint32_t j = 0; j < paramCount; ++j) + if (Nodes[func.GetNodeId() + 1 + j].GetParentId() != func.GetNodeId() || + Nodes[func.GetNodeId() + 1 + j].GetNodeType() != + D3D12_HLSL_NODE_TYPE_PARAMETER) + return HLSL_REFL_ERR( + "Function is missing valid parameters and/or return", i); + } + + for (uint32_t i = 0; i < header.Enums; ++i) { + + const ReflectionEnumeration &enm = Enums[i]; + + if (enm.NodeId >= header.Nodes || + Nodes[enm.NodeId].GetNodeType() != D3D12_HLSL_NODE_TYPE_ENUM || + Nodes[enm.NodeId].GetLocalId() != i) + return HLSL_REFL_ERR("Function points to an invalid nodeId", i); + + if (enm.Type < D3D12_HLSL_ENUM_TYPE_START || + enm.Type > D3D12_HLSL_ENUM_TYPE_END) + return HLSL_REFL_ERR("Enum has an invalid type", i); + + const ReflectionNode &node = Nodes[enm.NodeId]; + + if (!node.IsFwdDeclare() && !node.GetChildCount()) + return HLSL_REFL_ERR("Enum has no values!", i); + + for (uint32_t j = 0; j < node.GetChildCount(); ++j) { + + const ReflectionNode &child = Nodes[enm.NodeId + 1 + j]; + + if (child.GetChildCount() != 0 || + child.GetNodeType() != D3D12_HLSL_NODE_TYPE_ENUM_VALUE) + return HLSL_REFL_ERR("Enum has an invalid enum value", i); + } + } + + for (uint32_t i = 0; i < header.EnumValues; ++i) { + + const ReflectionEnumValue &enumVal = EnumValues[i]; + + if (enumVal.NodeId >= header.Nodes || + Nodes[enumVal.NodeId].GetNodeType() != + D3D12_HLSL_NODE_TYPE_ENUM_VALUE || + Nodes[enumVal.NodeId].GetLocalId() != i || + Nodes[Nodes[enumVal.NodeId].GetParentId()].GetNodeType() != + D3D12_HLSL_NODE_TYPE_ENUM) + return HLSL_REFL_ERR("Enum value points to an invalid nodeId", i); + + uint64_t maxVal = uint64_t(-1); + ReflectionNode &parent = Nodes[Nodes[enumVal.NodeId].GetParentId()]; + + switch (Enums[parent.GetLocalId()].Type) { + case D3D12_HLSL_ENUM_TYPE_UINT: + case D3D12_HLSL_ENUM_TYPE_INT: + maxVal = uint32_t(-1); + break; + + case D3D12_HLSL_ENUM_TYPE_UINT16_T: + case D3D12_HLSL_ENUM_TYPE_INT16_T: + maxVal = uint16_t(-1); + break; + } + + if (uint64_t(enumVal.Value) > maxVal) + return HLSL_REFL_ERR("Enum value is invalid", i); + } + + for (uint32_t i = 0; i < header.Arrays; ++i) { + + const ReflectionArray &arr = Arrays[i]; + + if (arr.ArrayElem() <= 1 || arr.ArrayElem() > 32 || + arr.ArrayStart() + arr.ArrayElem() > header.ArraySizes) + return HLSL_REFL_ERR("Array points to an invalid array element", i); + } + + for (uint32_t i = 0; i < header.Annotations; ++i) + if (Annotations[i].GetStringNonDebug() >= header.StringsNonDebug) + return HLSL_REFL_ERR("Annotation points to an invalid string", i); + + for (uint32_t i = 0; i < header.Buffers; ++i) { + + const ReflectionShaderBuffer &buf = Buffers[i]; + + if (buf.NodeId >= header.Nodes || + Nodes[buf.NodeId].GetNodeType() != D3D12_HLSL_NODE_TYPE_REGISTER || + Nodes[buf.NodeId].GetLocalId() >= header.Registers || + Registers[Nodes[buf.NodeId].GetLocalId()].GetBufferId() != i) + return HLSL_REFL_ERR("Buffer points to an invalid nodeId", i); + + const ReflectionNode &node = Nodes[buf.NodeId]; + + if (!node.GetChildCount()) + return HLSL_REFL_ERR("Buffer requires at least one Variable child", i); + + for (uint32_t j = 0; j < node.GetChildCount(); ++j) { + + const ReflectionNode &child = Nodes[buf.NodeId + 1 + j]; + + if (child.GetChildCount() != 0 || + child.GetNodeType() != D3D12_HLSL_NODE_TYPE_VARIABLE) + return HLSL_REFL_ERR("Buffer has to have only Variable child nodes", i); + } + } + + for (uint32_t i = 0; i < header.Members; ++i) { + + if (MemberTypeIds[i] >= header.Types) + return HLSL_REFL_ERR("Member points to an invalid type", i); + + if (hasSymbolInfo && MemberNameIds[i] >= header.Strings) + return HLSL_REFL_ERR("Member points to an invalid string", i); + } + + for (uint32_t i = 0; i < header.TypeListCount; ++i) + if (TypeList[i] >= header.Types) + return HLSL_REFL_ERR("Type list index points to an invalid type", i); + + for (uint32_t i = 0; i < header.Parameters; ++i) { + + const ReflectionFunctionParameter ¶m = Parameters[i]; + + if (param.NodeId >= header.Nodes || + Nodes[param.NodeId].GetNodeType() != D3D12_HLSL_NODE_TYPE_PARAMETER || + Nodes[param.NodeId].GetLocalId() != i || param.TypeId >= header.Types) + return HLSL_REFL_ERR("Parameter points to an invalid nodeId", i); + + if (param.Flags > 3) + return HLSL_REFL_ERR("Parameter has invalid data", i); + } + + for (uint32_t nodeId : validateChildren) { + + const ReflectionNode &node = Nodes[nodeId]; + + // If/Then/Scope children could only be + // struct/union/interface/if/variable/typedef/enum + + for (uint32_t j = 0; j < node.GetChildCount(); ++j) { + + const ReflectionNode &childNode = Nodes[nodeId + 1 + j]; + + switch (childNode.GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_VARIABLE: + case D3D12_HLSL_NODE_TYPE_IF_ROOT: + case D3D12_HLSL_NODE_TYPE_STRUCT: + case D3D12_HLSL_NODE_TYPE_UNION: + case D3D12_HLSL_NODE_TYPE_INTERFACE: + case D3D12_HLSL_NODE_TYPE_TYPEDEF: + case D3D12_HLSL_NODE_TYPE_USING: + case D3D12_HLSL_NODE_TYPE_ENUM: + case D3D12_HLSL_NODE_TYPE_SCOPE: + case D3D12_HLSL_NODE_TYPE_DO: + case D3D12_HLSL_NODE_TYPE_FOR: + case D3D12_HLSL_NODE_TYPE_WHILE: + case D3D12_HLSL_NODE_TYPE_SWITCH: + case D3D12_HLSL_NODE_TYPE_DEFAULT: + case D3D12_HLSL_NODE_TYPE_CASE: + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: + case D3D12_HLSL_NODE_TYPE_ELSE: + break; + default: + return HLSL_REFL_ERR( + "Node has if/then/scope with children of invalid type", nodeId); + } + + j += childNode.GetChildCount(); + } + } + + for (uint32_t i = 0; i < header.Statements; ++i) { + + const ReflectionScopeStmt &Stmt = Statements[i]; + + if (Stmt.GetNodeId() >= header.Nodes || + Nodes[Stmt.GetNodeId()].GetLocalId() != i) + return HLSL_REFL_ERR("Statement points to an invalid nodeId", i); + + bool condVar = Stmt.HasConditionVar(); + uint32_t minParamCount = Stmt.GetNodeCount() + condVar; + const ReflectionNode &node = Nodes[Stmt.GetNodeId()]; + + if (node.GetChildCount() < minParamCount) + return HLSL_REFL_ERR("Statement didn't have required child nodes", i); + + if (condVar && Nodes[Stmt.GetNodeId() + 1].GetNodeType() != + D3D12_HLSL_NODE_TYPE_VARIABLE) + return HLSL_REFL_ERR( + "Statement has condition variable but first child is not a variable", + i); + + switch (node.GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_WHILE: + case D3D12_HLSL_NODE_TYPE_FOR: + break; + default: + return HLSL_REFL_ERR("Statement has invalid node type", i); + } + } + + for (uint32_t i = 0; i < header.IfSwitchStatements; ++i) { + + const ReflectionIfSwitchStmt &Stmt = IfSwitchStatements[i]; + + if (Stmt.GetNodeId() >= header.Nodes || + Nodes[Stmt.GetNodeId()].GetLocalId() != i) + return HLSL_REFL_ERR("IfSwitchStmt points to an invalid nodeId", i); + + bool condVar = Stmt.HasConditionVar(); + uint32_t minParamCount = condVar + Stmt.HasElseOrDefault(); + const ReflectionNode &node = Nodes[Stmt.GetNodeId()]; + + if (node.GetChildCount() < minParamCount) + return HLSL_REFL_ERR("IfSwitchStmt didn't have required child nodes", i); + + if (condVar && node.GetNodeType() == D3D12_HLSL_NODE_TYPE_IF_ROOT) + return HLSL_REFL_ERR("If statement can't have a conditional node in root", + i); + + if (condVar && Nodes[Stmt.GetNodeId() + 1].GetNodeType() != + D3D12_HLSL_NODE_TYPE_VARIABLE) + return HLSL_REFL_ERR( + "Statement has condition variable but first child is not a variable", + i); + + switch (node.GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_IF_ROOT: + case D3D12_HLSL_NODE_TYPE_SWITCH: + break; + default: + return HLSL_REFL_ERR("IfSwitchStmt has invalid node type", i); + } + + bool isIf = node.GetNodeType() == D3D12_HLSL_NODE_TYPE_IF_ROOT; + + // Ensure there's only one default/else and the first is the IF_FIRST node. + + uint32_t nodeStart = Stmt.GetNodeId() + 1 + condVar; + uint32_t nodeEnd = Stmt.GetNodeId() + node.GetChildCount(); + bool hasSingleNode = + false; // Else or default where you're only allowed to have one + + for (uint32_t j = nodeStart, k = 0; j < nodeEnd; ++j, ++k) { + + const ReflectionNode &child = Nodes[j]; + + bool isSingleNode = + child.GetNodeType() == + (isIf ? D3D12_HLSL_NODE_TYPE_ELSE : D3D12_HLSL_NODE_TYPE_DEFAULT); + + if (isSingleNode) { + + if (hasSingleNode) + return HLSL_REFL_ERR("IfSwitchStmt already has default/else", i); + + if (isIf && !k) + return HLSL_REFL_ERR("IfSwitchStmt started with else", i); + + hasSingleNode = true; + } + + else { + + D3D12_HLSL_NODE_TYPE expected = + !isIf ? D3D12_HLSL_NODE_TYPE_CASE + : (!k ? D3D12_HLSL_NODE_TYPE_IF_FIRST + : D3D12_HLSL_NODE_TYPE_ELSE_IF); + + if (child.GetNodeType() != expected) + return HLSL_REFL_ERR("IfSwitchStmt has an invalid member", i); + } + + j += child.GetChildCount(); + } + } + + for (uint32_t i = 0; i < header.BranchStatements; ++i) { + + const ReflectionBranchStmt &Stmt = BranchStatements[i]; + + if (Stmt.GetNodeId() >= header.Nodes || + Nodes[Stmt.GetNodeId()].GetLocalId() != i) + return HLSL_REFL_ERR("BranchStatements points to an invalid nodeId", i); + + if (Stmt.GetValueType() < D3D12_HLSL_ENUM_TYPE_UINT || + Stmt.GetValueType() > D3D12_HLSL_ENUM_TYPE_INT16_T) + return HLSL_REFL_ERR("BranchStatement has an invalid value type", i); + + bool condVar = Stmt.HasConditionVar(); + uint32_t minParamCount = condVar; + const ReflectionNode &node = Nodes[Stmt.GetNodeId()]; + + if (node.GetChildCount() < minParamCount) + return HLSL_REFL_ERR("IfSwitchStmt didn't have required child nodes", i); + + if (condVar && (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_DEFAULT || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_CASE || + node.GetNodeType() == D3D12_HLSL_NODE_TYPE_ELSE)) + return HLSL_REFL_ERR( + "Default, case or else can't have a conditional node in root", i); + + if (condVar && Nodes[Stmt.GetNodeId() + 1].GetNodeType() != + D3D12_HLSL_NODE_TYPE_VARIABLE) + return HLSL_REFL_ERR( + "Statement has condition variable but first child is not a variable", + i); + + switch (node.GetNodeType()) { + case D3D12_HLSL_NODE_TYPE_CASE: + case D3D12_HLSL_NODE_TYPE_DEFAULT: + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: + case D3D12_HLSL_NODE_TYPE_ELSE: + break; + default: + return HLSL_REFL_ERR("IfSwitchStmt has invalid node type", i); + } + + if (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_CASE && + !Stmt.IsComplexCase()) { + + uint64_t maxVal = uint64_t(-1); + + switch (Stmt.GetValueType()) { + + case D3D12_HLSL_ENUM_TYPE_UINT: + case D3D12_HLSL_ENUM_TYPE_INT: + maxVal = uint32_t(-1); + break; + + case D3D12_HLSL_ENUM_TYPE_UINT16_T: + case D3D12_HLSL_ENUM_TYPE_INT16_T: + maxVal = uint16_t(-1); + break; + } + + if (Stmt.GetValue() > maxVal) + return HLSL_REFL_ERR("IfSwitchStmt is out of bounds for the value type", + i); + } + + else if (Stmt.GetValue() != uint64_t(-1)) + return HLSL_REFL_ERR("IfSwitchStmt should have -1 as value", i); + } + + for (uint32_t i = 0; i < header.Types; ++i) { + + const ReflectionVariableType &type = Types[i]; + + if (hasSymbolInfo && (TypeSymbols[i].DisplayNameId >= header.Strings || + TypeSymbols[i].UnderlyingNameId >= header.Strings)) + return HLSL_REFL_ERR("Type points to an invalid string", i); + + if (hasSymbolInfo && (TypeSymbols[i].DisplayArray.ElementsOrArrayId >> 31 && + (TypeSymbols[i].DisplayArray.ElementsOrArrayId << 1 >> + 1) >= header.Arrays)) + return HLSL_REFL_ERR("Type points to an invalid string", i); + + if ((type.GetBaseClass() != uint32_t(-1) && + type.GetBaseClass() >= header.Types) || + type.GetMemberStart() + type.GetMemberCount() > header.Members || + type.GetInterfaceStart() + type.GetInterfaceCount() > + header.TypeListCount || + (type.GetUnderlyingArray().ElementsOrArrayId >> 31 && + (type.GetUnderlyingArray().ElementsOrArrayId << 1 >> 1) >= + header.Arrays)) + return HLSL_REFL_ERR( + "Type points to an invalid string, array, base class or member", i); + + switch (type.GetClass()) { + + case D3D_SVC_SCALAR: + + if (type.GetColumns() != 1) + return HLSL_REFL_ERR("Type (scalar) should have columns == 1", i); + + [[fallthrough]]; + + case D3D_SVC_VECTOR: + + if (type.GetRows() != 1) + return HLSL_REFL_ERR("Type (scalar/vector) should have rows == 1", i); + + [[fallthrough]]; + + case D3D_SVC_MATRIX_ROWS: + case D3D_SVC_MATRIX_COLUMNS: + + if (!type.GetRows() || !type.GetColumns() || type.GetRows() > 128 || + type.GetColumns() > 128) + return HLSL_REFL_ERR( + "Type (scalar/vector/matrix) has invalid rows or columns", i); + + switch (type.GetType()) { + case D3D_SVT_BOOL: + case D3D_SVT_INT: + case D3D_SVT_FLOAT: + case D3D_SVT_MIN8FLOAT: + case D3D_SVT_MIN10FLOAT: + case D3D_SVT_MIN16FLOAT: + case D3D_SVT_MIN12INT: + case D3D_SVT_MIN16INT: + case D3D_SVT_MIN16UINT: + case D3D_SVT_INT16: + case D3D_SVT_UINT16: + case D3D_SVT_FLOAT16: + case D3D_SVT_INT64: + case D3D_SVT_UINT64: + case D3D_SVT_UINT: + case D3D_SVT_DOUBLE: + break; + + default: + return HLSL_REFL_ERR("Type (scalar/matrix/vector) is of invalid type", + i); + } + + break; + + case D3D_SVC_STRUCT: + [[fallthrough]]; + + case D3D_SVC_INTERFACE_CLASS: + + if (type.GetType()) + return HLSL_REFL_ERR("Type (struct) shouldn't have rows or columns", i); + + if (type.GetRows() || type.GetColumns()) + return HLSL_REFL_ERR("Type (struct) shouldn't have rows or columns", i); + + break; + + case D3D_SVC_OBJECT: + + switch (type.GetType()) { + + case D3D_SVT_STRING: + case D3D_SVT_TEXTURE1D: + case D3D_SVT_TEXTURE2D: + case D3D_SVT_TEXTURE3D: + case D3D_SVT_TEXTURECUBE: + case D3D_SVT_SAMPLER: + case D3D_SVT_BUFFER: + case D3D_SVT_CBUFFER: + case D3D_SVT_TBUFFER: + case D3D_SVT_TEXTURE1DARRAY: + case D3D_SVT_TEXTURE2DARRAY: + case D3D_SVT_TEXTURE2DMS: + case D3D_SVT_TEXTURE2DMSARRAY: + case D3D_SVT_TEXTURECUBEARRAY: + case D3D_SVT_RWTEXTURE1D: + case D3D_SVT_RWTEXTURE1DARRAY: + case D3D_SVT_RWTEXTURE2D: + case D3D_SVT_RWTEXTURE2DARRAY: + case D3D_SVT_RWTEXTURE3D: + case D3D_SVT_RWBUFFER: + case D3D_SVT_BYTEADDRESS_BUFFER: + case D3D_SVT_RWBYTEADDRESS_BUFFER: + case D3D_SVT_STRUCTURED_BUFFER: + case D3D_SVT_RWSTRUCTURED_BUFFER: + case D3D_SVT_APPEND_STRUCTURED_BUFFER: + case D3D_SVT_CONSUME_STRUCTURED_BUFFER: + break; + + default: + return HLSL_REFL_ERR("Type (object) is of invalid type", i); + } + + if (type.GetRows() || type.GetColumns()) + return HLSL_REFL_ERR("Type (object) shouldn't have rows or columns", i); + + break; + + default: + return HLSL_REFL_ERR("Type has an invalid class", i); + } + } + + // Validate fwd & backwards declares + + for (uint32_t i = 0; i < header.Nodes; ++i) { + + const ReflectionNode &node = Nodes[i]; + + if (node.IsFwdBckDefined()) { + + uint32_t fwdBack = node.GetFwdBck(); + + if (Nodes[fwdBack].GetNodeType() != node.GetNodeType()) + return HLSL_REFL_ERR("Node (fwd/bck declare) points to element that of " + "incompatible type", + i); + + if (hasSymbolInfo && + NodeSymbols[fwdBack].GetNameId() != NodeSymbols[i].GetNameId()) + return HLSL_REFL_ERR("Node (fwd/bck declare) have mismatching name", i); + + if (node.IsFwdDeclare()) { + + if (fwdBack <= i || fwdBack >= header.Nodes) + return HLSL_REFL_ERR("Node (fwd declare) points to invalid element", + i); + + if (Nodes[fwdBack].IsFwdDeclare()) + return HLSL_REFL_ERR( + "Node (fwd declare) points to element that is also a fwd declare", + i); + + uint32_t paramCount = 0; + + if (node.GetNodeType() == D3D12_HLSL_NODE_TYPE_FUNCTION) { + const ReflectionFunction &func = Functions[node.GetLocalId()]; + paramCount = func.GetNumParameters() + func.HasReturn(); + } + + if ((node.GetChildCount() != paramCount) || node.GetAnnotationCount()) + return HLSL_REFL_ERR( + "Node (fwd declare) points to element with invalid child count, " + "or annotationCount", + i); + } + + else { + + if (fwdBack >= i) + return HLSL_REFL_ERR("Node (bck declare) points to invalid element", + i); + + if (!Nodes[fwdBack].IsFwdDeclare()) + return HLSL_REFL_ERR( + "Node (bck declare) points to element that is not a fwd declare", + i); + } + } + } + + // Finalize + + if (MakeNameLookupTable) + GenerateNameLookupTable(); + + return ReflectionErrorSuccess; +} + +} // namespace hlsl diff --git a/tools/clang/tools/dxcreflectioncontainer/DxcReflectionJson.cpp b/tools/clang/tools/dxcreflectioncontainer/DxcReflectionJson.cpp new file mode 100644 index 0000000000..3bb66e8391 --- /dev/null +++ b/tools/clang/tools/dxcreflectioncontainer/DxcReflectionJson.cpp @@ -0,0 +1,1600 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// DxcReflectionJson.cpp // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include "dxc/DxcReflection/DxcReflectionContainer.h" +#include +#include + +namespace hlsl { + +struct JsonWriter { + + std::stringstream ss; + uint16_t indent = 0; + uint16_t countCommaStack = 0; + uint32_t needCommaStack[3] = {0, 0, 0}; + + void Indent() { ss << std::string(indent, '\t'); } + void NewLine() { ss << "\n"; } + + void StartCommaStack() { + ++countCommaStack; + assert(countCommaStack < 96 && "countCommaStack out of bounds"); + needCommaStack[countCommaStack / 32] &= ~(1u << (countCommaStack & 31)); + } + + void SetComma() { + needCommaStack[countCommaStack / 32] |= 1u << (countCommaStack & 31); + } + + void EndCommaStack() { + --countCommaStack; + SetComma(); + } + + bool NeedsComma() { + return (needCommaStack[countCommaStack / 32] >> (countCommaStack & 31)) & 1; + } + + void BeginObj() { + + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + + ss << "{\n"; + ++indent; + StartCommaStack(); + Indent(); + } + + void EndObj() { + ss << "\n"; + --indent; + Indent(); + ss << "}"; + EndCommaStack(); + } + + void BeginArray(const char *Name) { + + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + + if (Name) { + StartCommaStack(); + Key(Name); + --countCommaStack; + } + + ss << "[\n"; + ++indent; + StartCommaStack(); + Indent(); + } + + void EndArray() { + ss << "\n"; + --indent; + Indent(); + ss << "]"; + EndCommaStack(); + } + + void Key(const char *Key) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << "\"" << Escape(Key) << "\": "; + } + + void Value(std::string S) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << "\"" << Escape(S) << "\""; + SetComma(); + } + + void Value(const char *S) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << "\"" << S << "\""; + SetComma(); + } + + void ValueNull() { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << "null"; + SetComma(); + } + + void Value(uint64_t V) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << V; + SetComma(); + } + + void Value(int64_t V) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << V; + SetComma(); + } + + void Value(bool V) { + if (NeedsComma()) { + ss << ",\n"; + Indent(); + } + ss << (V ? "true" : "false"); + SetComma(); + } + + static std::string Escape(const std::string &In) { + std::string out; + out.reserve(In.size()); + for (char c : In) { + switch (c) { + case '\\': + out += "\\\\"; + break; + case '"': + out += "\\\""; + break; + case '\n': + out += "\\n"; + break; + case '\r': + out += "\\r"; + break; + case '\t': + out += "\\t"; + break; + default: + out += c; + break; + } + } + return out; + } + + std::string str() const { return ss.str(); } + + struct ObjectScope { + + JsonWriter &W; + bool NeedsEndCommaStack; + + ObjectScope(JsonWriter &W, const char *Name = nullptr) + : W(W), NeedsEndCommaStack(Name) { + + if (Name) { + W.Key(Name); + W.StartCommaStack(); + } + + W.BeginObj(); + } + + ~ObjectScope() { + W.EndObj(); + + if (NeedsEndCommaStack) + W.EndCommaStack(); + } + }; + + struct ArrayScope { + JsonWriter &W; + ArrayScope(JsonWriter &W, const char *Name = nullptr) : W(W) { + W.BeginArray(Name); + } + ~ArrayScope() { W.EndArray(); } + }; + + void Object(const char *Name, const std::function &Body) { + ObjectScope _(*this, Name); + Body(); + } + + void Array(const char *Name, const std::function &Body) { + ArrayScope _(*this, Name); + Body(); + } + + void StringField(const char *K, const std::string &V) { + Key(K); + StartCommaStack(); + Value(V); + EndCommaStack(); + } + + void UIntField(const char *K, uint64_t V) { + Key(K); + StartCommaStack(); + Value(V); + EndCommaStack(); + } + + void IntField(const char *K, int64_t V) { + Key(K); + StartCommaStack(); + Value(V); + EndCommaStack(); + } + + void BoolField(const char *K, bool V) { + Key(K); + StartCommaStack(); + Value(V); + EndCommaStack(); + } + + void NullField(const char *K) { + Key(K); + StartCommaStack(); + ValueNull(); + EndCommaStack(); + } +}; + +void PrintFeatures(D3D12_HLSL_REFLECTION_FEATURE Features, JsonWriter &Json) { + Json.Array("Features", [Features, &Json] { + if (Features & D3D12_HLSL_REFLECTION_FEATURE_BASICS) + Json.Value("Basics"); + if (Features & D3D12_HLSL_REFLECTION_FEATURE_FUNCTIONS) + Json.Value("Functions"); + if (Features & D3D12_HLSL_REFLECTION_FEATURE_NAMESPACES) + Json.Value("Namespaces"); + if (Features & D3D12_HLSL_REFLECTION_FEATURE_USER_TYPES) + Json.Value("UserTypes"); + if (Features & D3D12_HLSL_REFLECTION_FEATURE_SCOPES) + Json.Value("Scopes"); + if (Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + Json.Value("Symbols"); + }); +} + +static const char *NodeTypeToString(D3D12_HLSL_NODE_TYPE Type) { + + static const char *arr[] = {"Register", + "Function", + "Enum", + "EnumValue", + "Namespace", + "Variable", + "Typedef", + "Struct", + "Union", + "StaticVariable", + "Interface", + "Parameter", + "IfRoot", + "Scope", + "Do", + "Switch", + "While", + "For", + "GroupsharedVariable", + "Case", + "Default", + "Using", + "IfFirst", + "ElseIf", + "Else"}; + + return arr[uint32_t(Type)]; +} + +static const char *RegisterTypeToString(D3D_SHADER_INPUT_TYPE Type) { + + static const char *arr[] = {"cbuffer", + "tbuffer", + "Texture", + "SamplerState", + "RWTexture", + "StructuredBuffer", + "RWStructuredBuffer", + "ByteAddressBuffer", + "RWByteAddressBuffer", + "AppendStructuredBuffer", + "ConsumeStructuredBuffer", + "(Append/Consume)StructuredBuffer", + "RaytracingAccelerationStructure", + "FeedbackTexture"}; + + return arr[uint32_t(Type)]; +} + +static const char *DimensionTypeToString(D3D_SRV_DIMENSION Type) { + + static const char *arr[] = { + "Unknown", "Buffer", "Texture1D", "Texture1DArray", + "Texture2D", "Texture2DArray", "Texture2DMS", "Texture2DMSArray", + "Texture3D", "TextureCube", "TextureCubeArray", "BufferEx"}; + + return arr[uint32_t(Type)]; +} + +static const char *ReturnTypeToString(D3D_RESOURCE_RETURN_TYPE Type) { + + static const char *arr[] = {"unknown", "unorm", "snorm", "sint", "uint", + "float", "mixed", "double", "continued"}; + + return arr[uint32_t(Type)]; +} + +static std::string EnumTypeToString(D3D12_HLSL_ENUM_TYPE Type) { + + static const char *arr[] = { + "uint", "int", "uint64_t", "int64_t", "uint16_t", "int16_t", + }; + + return arr[Type]; +} + +static std::string BufferTypeToString(D3D_CBUFFER_TYPE Type) { + static const char *arr[] = {"cbuffer", "tbuffer", "undefined", "structured"}; + return arr[Type]; +} + +static std::string GetBuiltinTypeName(const ReflectionData &Refl, + const ReflectionVariableType &Type) { + + std::string type = ""; + + if (Type.GetClass() != D3D_SVC_STRUCT && + Type.GetClass() != D3D_SVC_INTERFACE_CLASS) { + + static const char *arr[] = {"void", + "bool", + "int", + "float", + "string", + NULL, + "Texture1D", + "Texture2D", + "Texture3D", + "TextureCube", + "SamplerState", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "uint", + "uint8_t", + NULL, + NULL, + NULL, + NULL, + "Buffer", + "ConstantBuffer", + NULL, + "Texture1DArray", + "Texture2DArray", + NULL, + NULL, + "Texture2DMS", + "Texture2DMSArray", + "TextureCubeArray", + NULL, + NULL, + NULL, + NULL, + "double", + "RWTexture1D", + "RWTexture1DArray", + "RWTexture2D", + "RWTexture2DArray", + "RWTexture3D", + "RWBuffer", + "ByteAddressBuffer", + "RWByteAddressBuffer", + "StructuredBuffer", + "RWStructuredBuffer", + "AppendStructuredBuffer", + "ConsumeStructuredBuffer", + "min8float", + "min10float", + "min16float", + "min12int", + "min16int", + "min16uint", + "int16_t", + "uint16_t", + "float16_t", + "int64_t", + "uint64_t"}; + + const char *ptr = arr[Type.GetType()]; + + if (ptr) + type = ptr; + } + + switch (Type.GetClass()) { + + case D3D_SVC_MATRIX_ROWS: + case D3D_SVC_VECTOR: + + type += std::to_string(Type.GetColumns()); + + if (Type.GetClass() == D3D_SVC_MATRIX_ROWS) + type += "x" + std::to_string(Type.GetRows()); + + break; + + case D3D_SVC_MATRIX_COLUMNS: + type += std::to_string(Type.GetRows()) + "x" + + std::to_string(Type.GetColumns()); + break; + } + + return type; +} + +static void FillArraySizes(const ReflectionData &Reflection, + ReflectionArrayOrElements Elements, + std::vector &Array) { + + if (!Elements.IsArray()) + return; + + if (Elements.Is1DArray()) { + Array.push_back(Elements.Get1DElements()); + return; + } + + const ReflectionArray &arr = + Reflection.Arrays[Elements.GetMultiDimensionalArrayId()]; + + for (uint32_t i = 0; i < arr.ArrayElem(); ++i) + Array.push_back(Reflection.ArraySizes[arr.ArrayStart() + i]); +} + +struct ReflectionPrintSettings { + bool HumanReadable; + bool HideFileInfo; +}; + +static void PrintSymbol(JsonWriter &Json, const ReflectionData &Reflection, + const ReflectionNodeSymbol &Sym, + const ReflectionPrintSettings &Settings, bool MuteName, + bool ShowOnlyName = false) { + + if (Sym.GetNameId() && !MuteName) { + + Json.StringField("Name", Reflection.Strings[Sym.GetNameId()]); + + if (!Settings.HumanReadable) + Json.UIntField("NameId", Sym.GetNameId()); + } + + if (Settings.HideFileInfo || ShowOnlyName) + return; + + if (Sym.HasFileSource()) { + + Json.StringField( + "Source", + Reflection.Strings[Reflection.Sources[Sym.GetFileSourceId()]]); + + if (!Settings.HumanReadable) + Json.UIntField("SourceId", Sym.GetFileSourceId()); + + Json.UIntField("LineId", Sym.GetSourceLineStart()); + + if (Sym.GetSourceLineCount() > 1) + Json.UIntField("LineCount", Sym.GetSourceLineCount()); + + Json.UIntField("ColumnStart", Sym.GetSourceColumnStart()); + Json.UIntField("ColumnEnd", Sym.GetSourceColumnEnd()); + } +} + +static void PrintInterpolationMode(JsonWriter &Json, + D3D_INTERPOLATION_MODE Interp) { + + static const char *interpolationModes[] = {"Undefined", + "Constant", + "Linear", + "LinearCentroid", + "LinearNoperspective", + "LinearNoperspectiveCentroid", + "LinearSample", + "LinearNoperspectiveSample"}; + if (Interp) + Json.StringField("Interpolation", interpolationModes[Interp]); +} + +// Verbose and all members are slightly different; +// Verbose will still print fields even if they aren't relevant, +// while all members will not silence important info but that might not matter +// for human readability +static void PrintNode(JsonWriter &Json, const ReflectionData &Reflection, + uint32_t NodeId, + const ReflectionPrintSettings &Settings) { + + const ReflectionNode &node = Reflection.Nodes[NodeId]; + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!Settings.HumanReadable || !hasSymbols) + Json.UIntField("NodeId", NodeId); + + Json.StringField("NodeType", NodeTypeToString(node.GetNodeType())); + + if (!Settings.HumanReadable) { + Json.UIntField("NodeTypeId", node.GetNodeType()); + Json.UIntField("LocalId", node.GetLocalId()); + Json.IntField("ParentId", node.GetParentId() == uint16_t(-1) + ? -1 + : int64_t(node.GetParentId())); + } + + if (node.GetChildCount() && !Settings.HumanReadable) { + Json.UIntField("ChildCount", node.GetChildCount()); + Json.UIntField("ChildStart", NodeId + 1); + } + + if (node.GetSemanticId() != uint32_t(-1)) { + + Json.StringField("Semantic", + Reflection.StringsNonDebug[node.GetSemanticId()]); + + if (!Settings.HumanReadable) + Json.UIntField("SemanticId", node.GetSemanticId()); + } + + PrintInterpolationMode(Json, node.GetInterpolationMode()); + + if (node.GetAnnotationCount()) { + + if (!Settings.HumanReadable) { + Json.UIntField("AnnotationStart", node.GetAnnotationStart()); + Json.UIntField("AnnotationCount", node.GetAnnotationCount()); + } + + Json.Array("Annotations", [&Reflection, &Json, node] { + for (uint32_t i = 0; i < node.GetAnnotationCount(); ++i) { + + const ReflectionAnnotation &annot = + Reflection.Annotations[node.GetAnnotationStart() + i]; + + std::string name = + Reflection.StringsNonDebug[annot.GetStringNonDebug()]; + + if (annot.GetIsBuiltin()) + name = "[" + name + "]"; + else + name = "[[" + name + "]]"; + + Json.Value(name); + } + }); + } + + if ((node.IsFwdBckDefined() || node.IsFwdDeclare()) && + !Settings.HumanReadable) { + Json.BoolField("IsFwdDeclare", node.IsFwdDeclare()); + Json.IntField("FwdBack", + !node.IsFwdBckDefined() ? -1 : int64_t(node.GetFwdBck())); + } + + if (hasSymbols && !Settings.HideFileInfo) + Json.Object("Symbol", [&Reflection, &Json, NodeId, &Settings] { + const ReflectionNodeSymbol &sym = Reflection.NodeSymbols[NodeId]; + PrintSymbol(Json, Reflection, sym, Settings, true); + }); +} + +static void PrintRegister(JsonWriter &Json, const ReflectionData &Reflection, + uint32_t RegisterId, + const ReflectionPrintSettings &Settings) { + + const ReflectionShaderResource ® = Reflection.Registers[RegisterId]; + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!Settings.HumanReadable || !hasSymbols) { + Json.UIntField("RegisterId", RegisterId); + Json.UIntField("NodeId", reg.GetNodeId()); + } + + if (!Settings.HumanReadable && hasSymbols) + Json.StringField( + "Name", + Reflection + .Strings[Reflection.NodeSymbols[reg.GetNodeId()].GetNameId()]); + + Json.StringField("RegisterType", RegisterTypeToString(reg.GetType())); + + if (reg.GetDimension() != D3D_SRV_DIMENSION_UNKNOWN) + Json.StringField("Dimension", DimensionTypeToString(reg.GetDimension())); + + if (reg.GetReturnType()) + Json.StringField("ReturnType", ReturnTypeToString(reg.GetReturnType())); + + if (reg.GetBindCount() > 1) + Json.UIntField("BindCount", reg.GetBindCount()); + + if (reg.GetArrayId() != uint32_t(-1)) { + + if (!Settings.HumanReadable) + Json.UIntField("ArrayId", reg.GetArrayId()); + + Json.Array("ArraySize", [&Reflection, ®, &Json]() { + const ReflectionArray &arr = Reflection.Arrays[reg.GetArrayId()]; + + for (uint32_t i = 0; i < uint32_t(arr.ArrayElem()); ++i) + Json.Value(uint64_t(Reflection.ArraySizes[arr.ArrayStart() + i])); + }); + } + + bool printBufferId = true; + + switch (reg.GetType()) { + case D3D_SIT_TEXTURE: + case D3D_SIT_SAMPLER: + case D3D_SIT_UAV_RWTYPED: + case D3D_SIT_RTACCELERATIONSTRUCTURE: + case D3D_SIT_UAV_FEEDBACKTEXTURE: + case D3D_SIT_UAV_RWBYTEADDRESS: + case D3D_SIT_BYTEADDRESS: + printBufferId = false; + break; + } + + if (printBufferId && !Settings.HumanReadable) + Json.UIntField("BufferId", reg.GetBufferId()); + + if (reg.GetFlags()) + Json.Array("Flags", [®, &Json]() { + uint32_t flag = reg.GetFlags(); + + if (flag & D3D_SIF_USERPACKED) + Json.Value("UserPacked"); + + if (flag & D3D_SIF_COMPARISON_SAMPLER) + Json.Value("ComparisonSampler"); + + if (flag & D3D_SIF_TEXTURE_COMPONENT_0) + Json.Value("TextureComponent0"); + + if (flag & D3D_SIF_TEXTURE_COMPONENT_1) + Json.Value("TextureComponent1"); + + if (flag & D3D_SIF_UNUSED) + Json.Value("Unused"); + }); +} + +static void PrintTypeName(const ReflectionData &Reflection, uint32_t TypeId, + bool HasSymbols, + const ReflectionPrintSettings &Settings, + JsonWriter &Json, + const char *NameForTypeName = "Name", + bool MuteArgs = false) { + + if (!Settings.HumanReadable || !HasSymbols) + Json.UIntField("TypeId", TypeId); + + std::string name; + std::vector arraySizes; + + std::string underlyingName; + std::vector underlyingArraySizes; + + const ReflectionVariableType &type = Reflection.Types[TypeId]; + + if (!HasSymbols) { + name = GetBuiltinTypeName(Reflection, type); + FillArraySizes(Reflection, type.GetUnderlyingArray(), arraySizes); + } + + else { + + const ReflectionVariableTypeSymbol &symbol = Reflection.TypeSymbols[TypeId]; + + name = Reflection.Strings[symbol.DisplayNameId]; + underlyingName = Reflection.Strings[symbol.UnderlyingNameId]; + + FillArraySizes(Reflection, symbol.DisplayArray, arraySizes); + FillArraySizes(Reflection, type.GetUnderlyingArray(), underlyingArraySizes); + } + + if (name.size()) + Json.StringField(NameForTypeName, name); + + if (type.GetClass() == D3D_SVC_OBJECT && + type.GetType() != D3D_SVT_BYTEADDRESS_BUFFER && + type.GetType() != D3D_SVT_RWBYTEADDRESS_BUFFER && + type.GetMemberCount() == 1 && !MuteArgs) { + + uint32_t innerTypeId = Reflection.MemberTypeIds[type.GetMemberStart()]; + + Json.Array( + "Args", [&Json, &Reflection, innerTypeId, HasSymbols, &Settings]() { + JsonWriter::ObjectScope scope(Json); + PrintTypeName(Reflection, innerTypeId, HasSymbols, Settings, Json); + }); + } + + if (arraySizes.size()) + Json.Array("ArraySize", [&arraySizes, &Json]() { + for (uint32_t i : arraySizes) + Json.Value(uint64_t(i)); + }); + + if (underlyingName.size() && underlyingName != name) + Json.StringField("UnderlyingName", underlyingName); + + if (underlyingArraySizes.size() && underlyingArraySizes != arraySizes) + Json.Array("UnderlyingArraySize", [&underlyingArraySizes, &Json]() { + for (uint32_t i : underlyingArraySizes) + Json.Value(uint64_t(i)); + }); +} + +static void PrintType(const ReflectionData &Reflection, uint32_t TypeId, + bool HasSymbols, const ReflectionPrintSettings &Settings, + JsonWriter &Json, bool Recursive, + const char *NameForTypeName = "Name") { + + const ReflectionVariableType &type = Reflection.Types[TypeId]; + + PrintTypeName(Reflection, TypeId, HasSymbols, Settings, Json, NameForTypeName, + true); + + if (type.GetBaseClass() != uint32_t(-1)) + Json.Object("BaseClass", + [&Reflection, &Json, &type, HasSymbols, Settings, Recursive]() { + if (Recursive) + PrintType(Reflection, type.GetBaseClass(), HasSymbols, + Settings, Json, true, "TypeName"); + + else + PrintTypeName(Reflection, type.GetBaseClass(), HasSymbols, + Settings, Json, "TypeName"); + }); + + if (type.GetInterfaceCount()) + Json.Array( + "Interfaces", [&Reflection, &Json, &type, HasSymbols, Settings]() { + for (uint32_t i = 0; i < uint32_t(type.GetInterfaceCount()); ++i) { + uint32_t interfaceId = type.GetInterfaceStart() + i; + JsonWriter::ObjectScope nodeRoot(Json); + PrintTypeName(Reflection, Reflection.TypeList[interfaceId], + HasSymbols, Settings, Json); + } + }); + + if (type.GetMemberCount()) + Json.Array("Members", [&Reflection, &Json, &type, HasSymbols, Settings, + Recursive]() { + for (uint32_t i = 0; i < uint32_t(type.GetMemberCount()); ++i) { + + uint32_t memberId = type.GetMemberStart() + i; + JsonWriter::ObjectScope nodeRoot(Json); + + if (HasSymbols) { + Json.StringField( + "Name", Reflection.Strings[Reflection.MemberNameIds[memberId]]); + + if (!Settings.HumanReadable) + Json.UIntField("NameId", Reflection.MemberNameIds[memberId]); + } + + if (Recursive) + PrintType(Reflection, Reflection.MemberTypeIds[memberId], HasSymbols, + Settings, Json, true, "TypeName"); + + else + PrintTypeName(Reflection, Reflection.MemberTypeIds[memberId], + HasSymbols, Settings, Json, "TypeName"); + } + }); +} + +static void PrintParameter(const ReflectionData &Reflection, uint32_t TypeId, + bool HasSymbols, JsonWriter &Json, + uint32_t SemanticId, + D3D_INTERPOLATION_MODE InterpMode, uint8_t Flags, + const ReflectionPrintSettings &Settings) { + + PrintTypeName(Reflection, TypeId, HasSymbols, Settings, Json, "TypeName"); + + if (SemanticId != uint32_t(-1)) { + + Json.StringField("Semantic", Reflection.StringsNonDebug[SemanticId]); + + if (!Settings.HumanReadable) + Json.UIntField("SemanticId", SemanticId); + } + + if ((Flags & (D3D_PF_IN | D3D_PF_OUT)) == (D3D_PF_IN | D3D_PF_OUT)) + Json.StringField("Access", "inout"); + + else if (Flags & D3D_PF_IN) + Json.StringField("Access", "in"); + + else if (Flags & D3D_PF_OUT) + Json.StringField("Access", "out"); + + PrintInterpolationMode(Json, InterpMode); +} + +static void PrintFunction(JsonWriter &Json, const ReflectionData &Reflection, + uint32_t FunctionId, + const ReflectionPrintSettings &Settings) { + + const ReflectionFunction &func = Reflection.Functions[FunctionId]; + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!Settings.HumanReadable || !hasSymbols) { + Json.UIntField("FunctionId", FunctionId); + Json.UIntField("NodeId", func.GetNodeId()); + } + + if (!Settings.HumanReadable && hasSymbols) + Json.StringField( + "Name", + Reflection + .Strings[Reflection.NodeSymbols[func.GetNodeId()].GetNameId()]); + + if (!func.HasDefinition() || !Settings.HumanReadable) + Json.BoolField("HasDefinition", func.HasDefinition()); + + Json.Object("Params", [&Reflection, &func, &Json, hasSymbols, &Settings]() { + for (uint32_t i = 0; i < uint32_t(func.GetNumParameters()); ++i) { + + uint32_t nodeId = func.GetNodeId() + 1 + i; + const ReflectionNode &node = Reflection.Nodes[nodeId]; + uint32_t localId = node.GetLocalId(); + + const ReflectionFunctionParameter ¶m = Reflection.Parameters[localId]; + std::string paramName = + hasSymbols + ? Reflection.Strings[Reflection.NodeSymbols[nodeId].GetNameId()] + : std::to_string(i); + + Json.Object(paramName.c_str(), [&Reflection, &func, &Json, hasSymbols, + ¶m, &node, &Settings, nodeId]() { + if (hasSymbols && !Settings.HideFileInfo) { + + const ReflectionNodeSymbol &sym = Reflection.NodeSymbols[nodeId]; + + Json.Object("Symbol", [&Json, &Reflection, &sym, &Settings]() { + PrintSymbol(Json, Reflection, sym, Settings, true); + }); + } + + PrintParameter(Reflection, param.TypeId, hasSymbols, Json, + node.GetSemanticId(), node.GetInterpolationMode(), + param.Flags, Settings); + }); + } + }); + + if (!func.HasReturn()) + Json.Object("ReturnType", + [&Json]() { Json.StringField("TypeName", "void"); }); + + else { + + const ReflectionNode &node = + Reflection.Nodes[func.GetNodeId() + 1 + func.GetNumParameters()]; + const ReflectionFunctionParameter ¶m = + Reflection.Parameters[node.GetLocalId()]; + + Json.Object("ReturnType", [&Reflection, &func, &Json, hasSymbols, ¶m, + &node, &Settings]() { + PrintParameter(Reflection, param.TypeId, hasSymbols, Json, + node.GetSemanticId(), node.GetInterpolationMode(), + param.Flags, Settings); + }); + } +} + +static void PrintValue(JsonWriter &Json, D3D12_HLSL_ENUM_TYPE type, uint64_t v, + const char *Name = "Value") { + + switch (type) { + + case D3D12_HLSL_ENUM_TYPE_INT: + Json.IntField("Value", int32_t(uint32_t(v))); + break; + + case D3D12_HLSL_ENUM_TYPE_INT64_T: + Json.IntField("Value", int64_t(v)); + break; + + case D3D12_HLSL_ENUM_TYPE_INT16_T: + Json.IntField("Value", int16_t(uint16_t(v))); + break; + + default: + Json.UIntField("Value", v); + break; + } +} + +static void PrintEnumValue(JsonWriter &Json, const ReflectionData &Reflection, + uint32_t NodeId, + const ReflectionPrintSettings &Settings) { + + const ReflectionNode &child = Reflection.Nodes[NodeId]; + + const ReflectionEnumValue &val = Reflection.EnumValues[child.GetLocalId()]; + + const ReflectionNode &parent = Reflection.Nodes[child.GetParentId()]; + const ReflectionEnumeration &enm = Reflection.Enums[parent.GetLocalId()]; + + PrintValue(Json, enm.Type, val.Value); + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (hasSymbols) { + + const ReflectionNodeSymbol &sym = Reflection.NodeSymbols[NodeId]; + + Json.Object("Symbol", [&Json, &Reflection, &sym, &Settings]() { + PrintSymbol(Json, Reflection, sym, Settings, false); + }); + } +} + +static void PrintEnum(JsonWriter &Json, const ReflectionData &Reflection, + uint32_t EnumId, + const ReflectionPrintSettings &Settings) { + + const ReflectionEnumeration &enm = Reflection.Enums[EnumId]; + const ReflectionNode &node = Reflection.Nodes[enm.NodeId]; + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!Settings.HumanReadable || !hasSymbols) { + Json.UIntField("EnumId", EnumId); + Json.UIntField("NodeId", enm.NodeId); + } + + if (hasSymbols) + Json.StringField( + "Name", + Reflection.Strings[Reflection.NodeSymbols[enm.NodeId].GetNameId()]); + + Json.StringField("EnumType", EnumTypeToString(enm.Type)); + + Json.Array("Values", + [&Json, &node, &enm, hasSymbols, &Reflection, &Settings]() { + for (uint32_t i = 0; i < node.GetChildCount(); ++i) { + + uint32_t childId = enm.NodeId + 1 + i; + + JsonWriter::ObjectScope valueRoot(Json); + + if (!hasSymbols || !Settings.HumanReadable) + Json.UIntField("ValueId", i); + + PrintEnumValue(Json, Reflection, childId, Settings); + } + }); +} + +static void PrintAnnotation(JsonWriter &Json, const ReflectionData &Reflection, + const ReflectionAnnotation &Annot) { + Json.StringField("Contents", + Reflection.StringsNonDebug[Annot.GetStringNonDebug()]); + Json.StringField("Type", Annot.GetIsBuiltin() ? "Builtin" : "User"); +} + +static uint32_t PrintBufferMember(const ReflectionData &Reflection, + uint32_t NodeId, uint32_t ChildId, + bool HasSymbols, + const ReflectionPrintSettings &Settings, + JsonWriter &Json) { + + const ReflectionNode &node = Reflection.Nodes[NodeId]; + + JsonWriter::ObjectScope root(Json); + + if (!Settings.HumanReadable) + Json.UIntField("NodeId", NodeId); + + if (!HasSymbols || !Settings.HumanReadable) + Json.UIntField("ChildId", ChildId); + + if (HasSymbols) + Json.StringField( + "Name", Reflection.Strings[Reflection.NodeSymbols[NodeId].GetNameId()]); + + PrintType(Reflection, node.GetLocalId(), HasSymbols, Settings, Json, true, + "TypeName"); + + return node.GetChildCount(); +} + +static void PrintBuffer(const ReflectionData &Reflection, uint32_t BufferId, + bool HasSymbols, + const ReflectionPrintSettings &Settings, + JsonWriter &Json) { + + JsonWriter::ObjectScope nodeRoot(Json); + const ReflectionShaderBuffer &buf = Reflection.Buffers[BufferId]; + const ReflectionNode &node = Reflection.Nodes[buf.NodeId]; + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + if (!Settings.HumanReadable || !hasSymbols) { + Json.UIntField("BufferId", BufferId); + Json.UIntField("NodeId", buf.NodeId); + } + + if (hasSymbols) + Json.StringField( + "Name", + Reflection.Strings[Reflection.NodeSymbols[buf.NodeId].GetNameId()]); + + Json.StringField("Type", BufferTypeToString(buf.Type)); + + if (node.GetChildCount()) + Json.Array("Children", + [&node, &Reflection, &buf, &Json, HasSymbols, &Settings]() { + for (uint32_t i = 0, j = 0; i < node.GetChildCount(); ++i, ++j) + i += PrintBufferMember(Reflection, buf.NodeId + 1 + i, j, + HasSymbols, Settings, Json); + }); +} + +static void PrintStatement(const ReflectionData &Reflection, + const ReflectionScopeStmt &Stmt, JsonWriter &Json) { + + const ReflectionNode &node = Reflection.Nodes[Stmt.GetNodeId()]; + + uint32_t nodesA = Stmt.GetNodeCount(); + uint32_t nodesB = node.GetChildCount() - nodesA - Stmt.HasConditionVar(); + + if (Stmt.HasConditionVar()) + Json.BoolField("HasConditionVar", Stmt.HasConditionVar()); + + if (nodesA) + Json.UIntField("Init", nodesA); + + if (nodesB) + Json.UIntField("Body", nodesB); +} + +static void PrintIfSwitchStatement(const ReflectionData &Reflection, + const ReflectionIfSwitchStmt &Stmt, + JsonWriter &Json) { + + if (Stmt.HasConditionVar()) + Json.BoolField("HasConditionVar", Stmt.HasConditionVar()); + + if (Stmt.HasElseOrDefault()) + Json.BoolField("HasElseOrDefault", Stmt.HasElseOrDefault()); +} + +static void PrintBranchStatement(const ReflectionData &Reflection, + const ReflectionBranchStmt &Stmt, + JsonWriter &Json) { + + if (Stmt.HasConditionVar()) + Json.BoolField("HasConditionVar", Stmt.HasConditionVar()); + + if (!Stmt.IsComplexCase()) { + Json.StringField("ValueType", EnumTypeToString(Stmt.GetValueType())); + PrintValue(Json, Stmt.GetValueType(), Stmt.GetValue()); + } + + else + Json.BoolField("IsComplexCase", Stmt.IsComplexCase()); +} + +uint32_t PrintNodeRecursive(const ReflectionData &Reflection, uint32_t NodeId, + JsonWriter &Json, + const ReflectionPrintSettings &Settings); + +void PrintChildren(const ReflectionData &Data, JsonWriter &Json, + const char *ObjectName, uint32_t Start, uint32_t End, + const ReflectionPrintSettings &Settings) { + + if (End > Start) + Json.Array(ObjectName, [&Data, &Json, Start, End, &Settings]() { + for (uint32_t i = Start; i < End; ++i) { + + const ReflectionNode &node = Data.Nodes[i]; + + if (node.IsFwdBckDefined() && !node.IsFwdDeclare()) { + i += node.GetChildCount(); + continue; + } + + JsonWriter::ObjectScope scope(Json); + + // Put Name(Id) into current scope to hide "Symbol" everywhere. + + if (Data.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO) + PrintSymbol(Json, Data, Data.NodeSymbols[i], Settings, false, true); + + i += PrintNodeRecursive(Data, i, Json, Settings); + } + }); +} + +uint32_t PrintNodeRecursive(const ReflectionData &Reflection, uint32_t NodeId, + JsonWriter &Json, + const ReflectionPrintSettings &Settings) { + + bool hasSymbols = + Reflection.Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + ReflectionNode node = Reflection.Nodes[NodeId]; + + // In case we're a fwd declare, don't change how we walk the tree + + uint32_t nodeChildCountForRet = node.GetChildCount(); + + // If this happens, we found the one defining a fwd declare. + // But this can happen in a different scope than the symbol ends up in. + // Mute this node. + // (This should be checked by the caller to avoid empty objects laying around) + if (node.IsFwdBckDefined() && !node.IsFwdDeclare()) + return node.GetChildCount(); + + D3D12_HLSL_NODE_TYPE nodeType = node.GetNodeType(); + + if (node.IsFwdDeclare() && node.IsFwdBckDefined()) { + NodeId = node.GetFwdBck(); + node = Reflection.Nodes[NodeId]; + } + + PrintNode(Json, Reflection, NodeId, Settings); + + uint32_t childrenToSkip = 0; + + bool recurseType = false; + const char *stmtType = nullptr; + + switch (nodeType) { + + case D3D12_HLSL_NODE_TYPE_FUNCTION: + Json.Object( + "Function", [&node, &Reflection, &Json, &Settings, &childrenToSkip]() { + ReflectionFunction func = Reflection.Functions[node.GetLocalId()]; + PrintFunction(Json, Reflection, node.GetLocalId(), Settings); + childrenToSkip = func.GetNumParameters() + func.HasReturn(); + }); + break; + + case D3D12_HLSL_NODE_TYPE_REGISTER: + Json.Object("Register", [&node, &Reflection, &Json, &Settings]() { + PrintRegister(Json, Reflection, node.GetLocalId(), Settings); + }); + break; + + case D3D12_HLSL_NODE_TYPE_ENUM: + Json.Object("Enum", + [&node, &Reflection, &Json, &Settings, &childrenToSkip]() { + PrintEnum(Json, Reflection, node.GetLocalId(), Settings); + childrenToSkip = node.GetChildCount(); + }); + break; + + case D3D12_HLSL_NODE_TYPE_STRUCT: + case D3D12_HLSL_NODE_TYPE_UNION: { + + if (node.IsFwdDeclare()) + break; + + const ReflectionVariableType &type = Reflection.Types[node.GetLocalId()]; + + if (type.GetBaseClass() != uint32_t(-1) || type.GetInterfaceCount()) + Json.Object("Class", [&Json, &type, &Reflection, hasSymbols, + &Settings]() { + if (type.GetBaseClass() != uint32_t(-1)) + Json.Object("BaseClass", + [&Json, &type, &Reflection, hasSymbols, &Settings]() { + PrintTypeName(Reflection, type.GetBaseClass(), + hasSymbols, Settings, Json); + }); + + if (type.GetInterfaceCount()) + Json.Array("Interfaces", [&Json, &type, &Reflection, hasSymbols, + &Settings]() { + for (uint32_t i = 0; i < uint32_t(type.GetInterfaceCount()); ++i) { + uint32_t interfaceId = type.GetInterfaceStart() + i; + JsonWriter::ObjectScope nodeRoot(Json); + PrintTypeName(Reflection, Reflection.TypeList[interfaceId], + hasSymbols, Settings, Json); + } + }); + }); + + break; + } + + case D3D12_HLSL_NODE_TYPE_VARIABLE: + case D3D12_HLSL_NODE_TYPE_STATIC_VARIABLE: + case D3D12_HLSL_NODE_TYPE_GROUPSHARED_VARIABLE: + recurseType = true; + [[fallthrough]]; + + case D3D12_HLSL_NODE_TYPE_TYPEDEF: + case D3D12_HLSL_NODE_TYPE_USING: + + Json.Object("Type", [&node, &Reflection, &Json, &Settings, hasSymbols, + recurseType]() { + PrintType(Reflection, node.GetLocalId(), hasSymbols, Settings, Json, + recurseType); + }); + + break; + + case D3D12_HLSL_NODE_TYPE_CASE: + + Json.Object( + "Case", [&node, &Reflection, &Json, &Settings, &childrenToSkip]() { + const ReflectionBranchStmt &branch = + Reflection.BranchStatements[node.GetLocalId()]; + if (!branch.IsComplexCase()) { + Json.StringField("Type", EnumTypeToString(branch.GetValueType())); + PrintValue(Json, branch.GetValueType(), branch.GetValue()); + } + }); + + break; + + case D3D12_HLSL_NODE_TYPE_IF_FIRST: + case D3D12_HLSL_NODE_TYPE_ELSE_IF: { + + const ReflectionBranchStmt &stmt = Reflection.BranchStatements[node.GetLocalId()]; + uint32_t start = NodeId + 1; + + if (stmt.HasConditionVar()) + Json.Object("Branch", [NodeId, &Reflection, &Json, &start, &Settings, + hasSymbols, &childrenToSkip]() { + Json.Object("Condition", [NodeId, &Reflection, &Json, &start, &Settings, + hasSymbols, &childrenToSkip]() { + if (hasSymbols) + PrintSymbol(Json, Reflection, Reflection.NodeSymbols[start], + Settings, false, true); + + start += PrintNodeRecursive(Reflection, start, Json, Settings); + ++start; + + childrenToSkip = start - NodeId - 1; + }); + }); + + break; + } + + case D3D12_HLSL_NODE_TYPE_FOR: + stmtType = "For"; + break; + + case D3D12_HLSL_NODE_TYPE_WHILE: + stmtType = "While"; + break; + } + + // While; turns into ("Condition"), ("Body") + // For; turns into ("Condition"), ("Init"), ("Body") + + if (stmtType) { + Json.Object(stmtType, [&node, &Reflection, &Json, &Settings, NodeId, + &childrenToSkip, nodeType, hasSymbols]() { + const ReflectionScopeStmt &stmt = + Reflection.Statements[node.GetLocalId()]; + + uint32_t start = NodeId + 1; + + if (stmt.HasConditionVar()) + Json.Object("Condition", [NodeId, &Reflection, &Json, &start, &Settings, + hasSymbols]() { + if (hasSymbols) + PrintSymbol(Json, Reflection, Reflection.NodeSymbols[start], + Settings, false, true); + + start += PrintNodeRecursive(Reflection, start, Json, Settings); + ++start; + }); + + uint32_t end = start + stmt.GetNodeCount(); + + if (stmt.GetNodeCount()) + PrintChildren(Reflection, Json, "Init", start, end, Settings); + + start = end; + end = NodeId + 1 + node.GetChildCount(); + + PrintChildren(Reflection, Json, "Body", start, end, Settings); + + childrenToSkip = node.GetChildCount(); + }); + } + + // Switch; turns into ("Condition"), ("Case": []) + // If(Root); is just a container for IfFirst/ElseIf/Else (no need to handle it here) + + else if (nodeType == D3D12_HLSL_NODE_TYPE_SWITCH) { + + const ReflectionIfSwitchStmt &stmt = + Reflection.IfSwitchStatements[node.GetLocalId()]; + + if (stmt.HasConditionVar()) + Json.Object("Switch", [&stmt, &Reflection, &Json, &Settings, NodeId, + &childrenToSkip, nodeType, hasSymbols]() { + uint32_t start = NodeId + 1; + + if (stmt.HasConditionVar()) + Json.Object("Condition", [NodeId, &Reflection, &Json, &start, + &Settings, hasSymbols]() { + if (hasSymbols) + PrintSymbol(Json, Reflection, Reflection.NodeSymbols[start], + Settings, false, true); + + start += PrintNodeRecursive(Reflection, start, Json, Settings); + ++start; + }); + + childrenToSkip = start - NodeId - 1; + }); + } + + // Children + + uint32_t start = NodeId + 1 + childrenToSkip; + uint32_t end = NodeId + 1 + node.GetChildCount(); + + PrintChildren(Reflection, Json, "Children", start, end, Settings); + + return nodeChildCountForRet; +} + +// IsHumanFriendly = false: Raw view of the real file data +// IsHumanFriendly = true: Clean view that's relatively close to the real tree +std::string ReflectionData::ToJson(bool HideFileInfo, + bool IsHumanFriendly) const { + + JsonWriter json; + + { + JsonWriter::ObjectScope root(json); + + // Features + + PrintFeatures(Features, json); + + bool hasSymbols = Features & D3D12_HLSL_REFLECTION_FEATURE_SYMBOL_INFO; + + ReflectionPrintSettings settings{}; + settings.HideFileInfo = HideFileInfo; + settings.HumanReadable = IsHumanFriendly; + + // Print raw contents + + if (!IsHumanFriendly) { + + json.Array("Strings", [this, &json] { + for (const std::string &s : Strings) + json.Value(s); + }); + + json.Array("StringsNonDebug", [this, &json] { + for (const std::string &s : StringsNonDebug) + json.Value(s); + }); + + json.Array("Sources", [this, &json] { + for (uint32_t id : Sources) + json.Value(Strings[id]); + }); + + json.Array("SourcesAsId", [this, &json] { + for (uint32_t id : Sources) + json.Value(uint64_t(id)); + }); + + json.Array("Nodes", [this, &json, &settings] { + for (uint32_t i = 0; i < uint32_t(Nodes.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + PrintNode(json, *this, i, settings); + } + }); + + json.Array("Registers", [this, &json, &settings] { + for (uint32_t i = 0; i < uint32_t(Registers.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + PrintRegister(json, *this, i, settings); + } + }); + + json.Array("Functions", [this, &json, HideFileInfo, &settings] { + for (uint32_t i = 0; i < uint32_t(Functions.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + PrintFunction(json, *this, i, settings); + } + }); + + // Already referenced indirectly through other properties we printed + // before, still printing it to allow consistency checks. + // For pure pretty prints, you should use the human version. + + json.Array("Parameters", [this, &json, hasSymbols, &settings] { + for (uint32_t i = 0; i < uint32_t(Parameters.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + + const ReflectionFunctionParameter ¶m = Parameters[i]; + std::string paramName = + hasSymbols ? Strings[NodeSymbols[param.NodeId].GetNameId()] + : std::to_string(i); + + json.StringField("ParamName", paramName); + + const ReflectionNode &node = Nodes[param.NodeId]; + + PrintParameter(*this, param.TypeId, hasSymbols, json, + node.GetSemanticId(), node.GetInterpolationMode(), + param.Flags, settings); + } + }); + + json.Array("Enums", [this, &json, hasSymbols, HideFileInfo, &settings] { + for (uint32_t i = 0; i < uint32_t(Enums.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + PrintEnum(json, *this, i, settings); + } + }); + + json.Array( + "EnumValues", [this, &json, hasSymbols, HideFileInfo, &settings] { + for (uint32_t i = 0; i < uint32_t(EnumValues.size()); ++i) { + JsonWriter::ObjectScope valueRoot(json); + PrintEnumValue(json, *this, EnumValues[i].NodeId, settings); + } + }); + + json.Array("Annotations", [this, &json, hasSymbols] { + for (uint32_t i = 0; i < uint32_t(Annotations.size()); ++i) { + const ReflectionAnnotation &annot = Annotations[i]; + JsonWriter::ObjectScope valueRoot(json); + json.UIntField("StringId", annot.GetStringNonDebug()); + PrintAnnotation(json, *this, annot); + } + }); + + json.Array("Arrays", [this, &json] { + for (uint32_t i = 0; i < uint32_t(Arrays.size()); ++i) { + const ReflectionArray &arr = Arrays[i]; + JsonWriter::ObjectScope valueRoot(json); + json.UIntField("ArrayElem", arr.ArrayElem()); + json.UIntField("ArrayStart", arr.ArrayStart()); + json.Array("ArraySizes", [this, &json, &arr] { + for (uint32_t i = 0; i < arr.ArrayElem(); ++i) { + json.Value(uint64_t(ArraySizes[arr.ArrayStart() + i])); + } + }); + } + }); + + json.Array("ArraySizes", [this, &json] { + for (uint32_t id : ArraySizes) + json.Value(uint64_t(id)); + }); + + json.Array("Members", [this, &json, hasSymbols, &settings] { + for (uint32_t i = 0; i < uint32_t(MemberTypeIds.size()); ++i) { + + JsonWriter::ObjectScope valueRoot(json); + + if (hasSymbols) { + json.StringField("Name", Strings[MemberNameIds[i]]); + json.UIntField("NameId", MemberNameIds[i]); + } + + PrintTypeName(*this, MemberTypeIds[i], hasSymbols, settings, json, + "TypeName"); + } + }); + + json.Array("TypeList", [this, &json, hasSymbols, &settings] { + for (uint32_t id : TypeList) { + JsonWriter::ObjectScope valueRoot(json); + PrintTypeName(*this, id, hasSymbols, settings, json); + } + }); + + json.Array("Types", [this, &json, hasSymbols, &settings] { + for (uint32_t i = 0; i < uint32_t(Types.size()); ++i) { + JsonWriter::ObjectScope nodeRoot(json); + PrintType(*this, i, hasSymbols, settings, json, false); + } + }); + + json.Array("Buffers", [this, &json, hasSymbols, &settings] { + for (uint32_t i = 0; i < uint32_t(Buffers.size()); ++i) + PrintBuffer(*this, i, hasSymbols, settings, json); + }); + + json.Array("Statements", [this, &json] { + for (uint32_t i = 0; i < uint32_t(Statements.size()); ++i) { + + const ReflectionScopeStmt &stat = Statements[i]; + JsonWriter::ObjectScope valueRoot(json); + json.StringField( + "Type", NodeTypeToString(Nodes[stat.GetNodeId()].GetNodeType())); + json.UIntField("NodeId", stat.GetNodeId()); + + PrintStatement(*this, stat, json); + } + }); + + json.Array("IfSwitchStatements", [this, &json] { + for (uint32_t i = 0; i < uint32_t(IfSwitchStatements.size()); ++i) { + + const ReflectionIfSwitchStmt &stat = IfSwitchStatements[i]; + JsonWriter::ObjectScope valueRoot(json); + json.StringField( + "Type", NodeTypeToString(Nodes[stat.GetNodeId()].GetNodeType())); + json.UIntField("NodeId", stat.GetNodeId()); + + PrintIfSwitchStatement(*this, stat, json); + } + }); + + json.Array("BranchStatements", [this, &json] { + for (uint32_t i = 0; i < uint32_t(BranchStatements.size()); ++i) { + + const ReflectionBranchStmt &stat = BranchStatements[i]; + JsonWriter::ObjectScope valueRoot(json); + json.StringField( + "Type", NodeTypeToString(Nodes[stat.GetNodeId()].GetNodeType())); + json.UIntField("NodeId", stat.GetNodeId()); + + PrintBranchStatement(*this, stat, json); + } + }); + } + + else + PrintChildren(*this, json, "Children", 1, Nodes.size(), settings); + } + return json.str(); +} + +} // namespace hlsl diff --git a/tools/clang/tools/dxreflector/CMakeLists.txt b/tools/clang/tools/dxreflector/CMakeLists.txt new file mode 100644 index 0000000000..6e938f8b78 --- /dev/null +++ b/tools/clang/tools/dxreflector/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) Microsoft Corporation. All rights reserved. +# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. +# Builds dxreflector.exe + +set( LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + dxcsupport + Option # option library + Support # For Atomic increment/decrement + ) + +add_clang_executable(dxreflector + dxreflector.cpp +# dxreflector.rc + ) + +target_link_libraries(dxreflector + dxclib + dxcompiler + ) + +set_target_properties(dxreflector PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION}) +# set_target_properties(dxreflector PROPERTIES ENABLE_EXPORTS 1) + +include_directories(${LLVM_SOURCE_DIR}/tools/clang/tools) + +add_dependencies(dxreflector dxclib dxcompiler) + +if(UNIX) + set(CLANGXX_LINK_OR_COPY create_symlink) +# Create a relative symlink + set(dxreflector_binary "dxreflector${CMAKE_EXECUTABLE_SUFFIX}") +else() + set(CLANGXX_LINK_OR_COPY copy) + set(dxreflector_binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/dxreflector${CMAKE_EXECUTABLE_SUFFIX}") +endif() + +install(TARGETS dxreflector + RUNTIME DESTINATION bin) + +if(MSVC) + target_compile_options(dxreflector PRIVATE /W4 /WX) +else() + target_compile_options(dxreflector PRIVATE -Wall -Wextra -Werror -Wno-pedantic) +endif() + diff --git a/tools/clang/tools/dxreflector/dxreflector.cpp b/tools/clang/tools/dxreflector/dxreflector.cpp new file mode 100644 index 0000000000..613f8eaebf --- /dev/null +++ b/tools/clang/tools/dxreflector/dxreflector.cpp @@ -0,0 +1,268 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxreflector.cpp // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Provides the entry point for the dxreflector console program. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#include "dxc/Support/Global.h" +#include "dxc/Support/Unicode.h" +#include "dxc/Support/WinFunctions.h" +#include "dxc/Support/WinIncludes.h" +#include "dxc/Support/microcom.h" +#include "dxclib/dxc.h" +#include +#include + +#include "dxc/Support/HLSLOptions.h" +#include "dxc/Support/WinFunctions.h" +#include "dxc/Support/dxcapi.use.h" +#include "dxc/dxcapi.h" +#include "dxc/dxcreflect.h" +#include "llvm/Support/raw_ostream.h" + +#include "dxc/DXIL/DxilShaderModel.h" + +inline bool wcsieq(LPCWSTR a, LPCWSTR b) { return _wcsicmp(a, b) == 0; } + +using namespace dxc; +using namespace llvm::opt; +using namespace hlsl::options; + +#ifdef _WIN32 +int __cdecl wmain(int argc, const wchar_t **argv_) { +#else +int main(int argc, const char **argv) { + // Convert argv to wchar. + WArgV ArgV(argc, argv); + const wchar_t **argv_ = ArgV.argv(); +#endif + if (FAILED(DxcInitThreadMalloc())) + return 1; + DxcSetThreadMallocToDefault(); + try { + if (initHlslOptTable()) + throw std::bad_alloc(); + + // Parse command line options. + const OptTable *optionTable = getHlslOptTable(); + MainArgs argStrings(argc, argv_); + DxcOpts dxreflectorOpts; + DXCLibraryDllLoader dxcSupport; + + // Read options and check errors. + { + std::string errorString; + llvm::raw_string_ostream errorStream(errorString); + + // Target profile is used to detect for example if 16-bit types are + // allowed. This is the only way to correct the missing target. + + { + unsigned missingArgIndex = 0, missingArgCount = 0; + InputArgList Args = + optionTable->ParseArgs(argStrings.getArrayRef(), missingArgIndex, + missingArgCount, DxreflectorFlags); + + if (!Args.hasArg(OPT_target_profile)) { + + const hlsl::ShaderModel *SM = hlsl::ShaderModel::Get( + hlsl::DXIL::ShaderKind::Library, hlsl::ShaderModel::kHighestMajor, + hlsl::ShaderModel::kHighestMinor); + + if (SM && SM->IsValid()) { + + dxreflectorOpts.TargetProfile = SM->GetName(); + + argStrings.Utf8StringVector.push_back("-T"); + argStrings.Utf8StringVector.push_back(SM->GetName()); + + argStrings.Utf8CharPtrVector.resize( + argStrings.Utf8CharPtrVector.size() + 2); + + for (uint64_t i = 0; i < argStrings.Utf8StringVector.size(); ++i) + argStrings.Utf8CharPtrVector[i] = + argStrings.Utf8StringVector[i].c_str(); + } + } + } + + int optResult = ReadDxcOpts(optionTable, DxreflectorFlags, argStrings, + dxreflectorOpts, errorStream); + errorStream.flush(); + if (errorString.size()) { + fprintf(stderr, "dxreflector failed : %s\n", errorString.data()); + } + if (optResult != 0) { + return optResult; + } + } + + // Apply defaults. + if (dxreflectorOpts.EntryPoint.empty() && + !dxreflectorOpts.RecompileFromBinary) { + dxreflectorOpts.EntryPoint = "main"; + } + + // Setup a helper DLL. + { + std::string dllErrorString; + llvm::raw_string_ostream dllErrorStream(dllErrorString); + int dllResult = + SetupSpecificDllLoader(dxreflectorOpts, dxcSupport, dllErrorStream); + dllErrorStream.flush(); + if (dllErrorString.size()) { + fprintf(stderr, "%s\n", dllErrorString.data()); + } + if (dllResult) + return dllResult; + } + + EnsureEnabled(dxcSupport); + // Handle help request, which overrides any other processing. + if (dxreflectorOpts.ShowHelp) { + std::string helpString; + llvm::raw_string_ostream helpStream(helpString); + std::string version; + llvm::raw_string_ostream versionStream(version); + WriteDxCompilerVersionInfo(versionStream, + dxreflectorOpts.ExternalLib.empty() + ? (LPCSTR) nullptr + : dxreflectorOpts.ExternalLib.data(), + dxreflectorOpts.ExternalFn.empty() + ? (LPCSTR) nullptr + : dxreflectorOpts.ExternalFn.data(), + dxcSupport); + versionStream.flush(); + optionTable->PrintHelp(helpStream, "dxreflector.exe", "DX Reflector", + version.c_str(), hlsl::options::ReflectOption, + (dxreflectorOpts.ShowHelpHidden ? 0 : HelpHidden)); + helpStream.flush(); + WriteUtf8ToConsoleSizeT(helpString.data(), helpString.size()); + return 0; + } + + if (dxreflectorOpts.ShowVersion) { + std::string version; + llvm::raw_string_ostream versionStream(version); + WriteDxCompilerVersionInfo(versionStream, + dxreflectorOpts.ExternalLib.empty() + ? (LPCSTR) nullptr + : dxreflectorOpts.ExternalLib.data(), + dxreflectorOpts.ExternalFn.empty() + ? (LPCSTR) nullptr + : dxreflectorOpts.ExternalFn.data(), + dxcSupport); + versionStream.flush(); + WriteUtf8ToConsoleSizeT(version.data(), version.size()); + return 0; + } + + CComPtr pReflector; + CComPtr pReflectionResult; + CComPtr pSource; + std::wstring wName(CA2W(dxreflectorOpts.InputFile.empty() + ? "" + : dxreflectorOpts.InputFile.data())); + if (!dxreflectorOpts.InputFile.empty()) + ReadFileIntoBlob(dxcSupport, wName.c_str(), &pSource); + + CComPtr pLibrary; + CComPtr pIncludeHandler; + IFT(dxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary)); + IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler)); + IFT(dxcSupport.CreateInstance(CLSID_DxcReflector, &pReflector)); + + std::vector wargs; + std::vector wargsC; + + wargs.reserve(argStrings.Utf8CharPtrVector.size()); + wargsC.reserve(argStrings.Utf8CharPtrVector.size()); + + for (const char *arg : argStrings.Utf8CharPtrVector) { + wargs.push_back(std::wstring(CA2W(arg))); + wargsC.push_back(wargs.back().c_str()); + } + + IFT(pReflector->FromSource(pSource, wName.c_str(), wargsC.data(), + uint32_t(wargsC.size()), nullptr, 0, + pIncludeHandler, &pReflectionResult)); + + if (dxreflectorOpts.OutputObject.empty()) { + + // No -Fo, print to console + + CComPtr pJson; + CComPtr pReflectionBlob; + CComPtr pReflectionData; + + ReflectorFormatSettings formatSettings{}; + formatSettings.PrintFileInfo = dxreflectorOpts.ReflOpt.ShowFileInfo; + formatSettings.IsHumanReadable = !dxreflectorOpts.ReflOpt.ShowRawData; + + WriteOperationResultToConsole(pReflectionResult, + !dxreflectorOpts.OutputWarnings); + + HRESULT hr; + IFT(pReflectionResult->GetStatus(&hr)); + + if (SUCCEEDED(hr)) { + IFT(pReflectionResult->GetResult(&pReflectionBlob)); + IFT(pReflector->FromBlob(pReflectionBlob, &pReflectionData)); + IFT(pReflector->ToString(pReflectionData, formatSettings, &pJson)); + WriteBlobToConsole(pJson, STD_OUTPUT_HANDLE); + } + + } else { + WriteOperationErrorsToConsole(pReflectionResult, + !dxreflectorOpts.OutputWarnings); + HRESULT hr; + IFT(pReflectionResult->GetStatus(&hr)); + if (SUCCEEDED(hr)) { + CA2W wOutputObject(dxreflectorOpts.OutputObject.data()); + CComPtr pObject; + IFT(pReflectionResult->GetResult(&pObject)); + WriteBlobToFile(pObject, wOutputObject.m_psz, + dxreflectorOpts.DefaultTextCodePage); + } + } + + } catch (const ::hlsl::Exception &hlslException) { + try { + const char *msg = hlslException.what(); + Unicode::acp_char + printBuffer[128]; // printBuffer is safe to treat as UTF-8 because we + // use ASCII contents only + if (msg == nullptr || *msg == '\0') { + sprintf_s(printBuffer, _countof(printBuffer), + "Reflection failed - error code 0x%08x.", hlslException.hr); + msg = printBuffer; + } + + std::string textMessage; + bool lossy; + if (!Unicode::UTF8ToConsoleString(msg, &textMessage, &lossy) || lossy) { + // Do a direct assignment as a last-ditch effort and print out as UTF-8. + textMessage = msg; + } + + printf("%s\n", textMessage.c_str()); + } catch (...) { + printf("Reflection failed - unable to retrieve error message.\n"); + } + + return 1; + } catch (std::bad_alloc &) { + printf("Reflection failed - out of memory.\n"); + return 1; + } catch (...) { + printf("Reflection failed - unable to retrieve error message.\n"); + return 1; + } + + return 0; +} diff --git a/tools/clang/tools/dxreflector/dxreflector.rc b/tools/clang/tools/dxreflector/dxreflector.rc new file mode 100644 index 0000000000..9f2f600e51 --- /dev/null +++ b/tools/clang/tools/dxreflector/dxreflector.rc @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#include +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "DX Reflector" +#define VER_INTERNALNAME_STR "DX Reflector" +#define VER_ORIGINALFILENAME_STR "dxreflector.exe" + +#include \ No newline at end of file diff --git a/tools/clang/tools/libclang/CMakeLists.txt b/tools/clang/tools/libclang/CMakeLists.txt index ed49cbaf44..724d24ccc8 100644 --- a/tools/clang/tools/libclang/CMakeLists.txt +++ b/tools/clang/tools/libclang/CMakeLists.txt @@ -179,6 +179,7 @@ endif() endif() # HLSL Change add_dependencies(libclang TablegenHLSLOptions) # HLSL Change +target_link_libraries(libclang PRIVATE dxcreflection) # HLSL Change # HLSL Change Starts # add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES}) diff --git a/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp b/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp index e4e8936d21..206f808f12 100644 --- a/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp +++ b/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp @@ -48,6 +48,8 @@ #include "dxc/Test/D3DReflectionDumper.h" #include "dxc/Test/RDATDumper.h" +#include "dxc/dxcreflect.h" + using namespace hlsl::dump; using namespace std; @@ -98,6 +100,8 @@ FileRunCommandPart::Run(dxc::DllLoader &DllSupport, return RunDxilVer(DllSupport, Prior); } else if (0 == _stricmp(Command.c_str(), "%dxc")) { return RunDxc(DllSupport, Prior); + } else if (0 == _stricmp(Command.c_str(), "%dxreflector")) { + return RunDxReflector(DllSupport, Prior); } else if (0 == _stricmp(Command.c_str(), "%dxv")) { return RunDxv(DllSupport, Prior); } else if (0 == _stricmp(Command.c_str(), "%opt")) { @@ -598,6 +602,69 @@ FileRunCommandPart::RunDxc(dxc::DllLoader &DllSupport, return result; } +FileRunCommandResult +FileRunCommandPart::RunDxReflector(dxc::DllLoader &DllSupport, + const FileRunCommandResult *Prior) { + // Support piping stdin from prior if needed. + UNREFERENCED_PARAMETER(Prior); + hlsl::options::MainArgs args; + hlsl::options::DxcOpts opts; + FileRunCommandResult readOptsResult = + ReadOptsForDxc(args, opts, hlsl::options::ReflectOption); + if (readOptsResult.ExitCode) + return readOptsResult; + + std::vector flags; + + std::vector argWStrings; + CopyArgsToWStrings(opts.Args, hlsl::options::ReflectOption, argWStrings); + for (const std::wstring &a : argWStrings) + flags.push_back(a.data()); + + CComPtr pLibrary; + CComPtr pReflector; + CComPtr pResult; + CComPtr pSource; + CComPtr pJson; + CComPtr pReflectionBlob; + CComPtr pReflectionData; + + ReflectorFormatSettings formatSettings{}; + formatSettings.PrintFileInfo = opts.ReflOpt.ShowFileInfo; + formatSettings.IsHumanReadable = !opts.ReflOpt.ShowRawData; + + HRESULT resultStatus; + + IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary)); + IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource)); + CComPtr pIncludeHandler = + AllocVFSIncludeHandler(pLibrary, pVFS); + IFT(DllSupport.CreateInstance(CLSID_DxcReflector, &pReflector)); + IFT(pReflector->FromSource(pSource, CommandFileName, flags.data(), + flags.size(), nullptr, 0, pIncludeHandler, + &pResult)); + IFT(pResult->GetStatus(&resultStatus)); + + FileRunCommandResult result = {}; + if (SUCCEEDED(resultStatus)) { + IFT(pResult->GetResult(&pReflectionBlob)); + IFT(pReflector->FromBlob(pReflectionBlob, &pReflectionData)); + IFT(pReflector->ToString(pReflectionData, formatSettings, &pJson)); + result.StdOut = BlobToUtf8(pJson); + CComPtr pStdErr; + IFT(pResult->GetErrorBuffer(&pStdErr)); + result.StdErr = BlobToUtf8(pStdErr); + result.ExitCode = 0; + } else { + IFT(pResult->GetErrorBuffer(&pJson)); + result.StdErr = BlobToUtf8(pJson); + result.ExitCode = resultStatus; + } + + result.OpResult = pResult; + return result; +} + FileRunCommandResult FileRunCommandPart::RunDxv(dxc::DllLoader &DllSupport, const FileRunCommandResult *Prior) {