summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-hlsl.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-06-06 17:48:39 -0400
committerGitHub <noreply@github.com>2019-06-06 17:48:39 -0400
commitfc083a75b94ac4b4e735b4a7ff566191b9123f74 (patch)
treeac1168718ac36099374373fdb55b9be178a0a9fa /source/slang/slang-emit-hlsl.cpp
parent0d9071bd1511ee2cb7d6ba6ce9e250d25613ddca (diff)
Split out target code generation from CLikeSourceEmitter (#976)
* * Added SourceStyle to CLikeSourceEmitter, to limit cases to actual target types. * Made Impl methods _ prefixed * Small tidyup * * SourceStream -> SourceWriter * use slang-emit- prefix on SourceWriter file * * Remove EmitContext -> merge into CLikeSourceEmitter * slang-c-like-source-emitter -> slang-emit-source.cpp * ExtensionUsageTracker -> GLSLExtensionTracker slang-extension-usage-tracker.cpp/.h -> slang-emit-glsl-extension-tracker.cpp/.h * emit-source.cpp.h -> emit-c-like.cpp/.h * Small fix to move where some _ prefixed functions are declared in CLikeSourceEmitter. * * CLikeSourceEmitter::CInfo -> Desc * Functions to get and find CodeGenTarget by name * Split out empty language impls * Create an impl based on SourceStyle * * CodeGenTarget conversion to and from string * Move HLSL specific functions to HLSLEmitSource. * Emitting texture and image types. * Move move GLSL specific functionality to GLSLSourceEmitter * Split more out of slang-emit-c-like * Refactor more out of slang-emit-c-like * * tryEmitIRInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec) * Fix bug around output of uintBitsToFloat * More work refactoring out target specifics from slang-emit-c-like * Move functions that are only implemented once in GLSL impl into their Impl method. * Move rate qualification out of slang-emit-c-like * * Added getEmitOpForOp - allows for table usage so different ops can be dealt with the same way * Moved vector comparison to slang-emit-glsl * * * Use EmitOpInfo to control output in slang-emit-c-like.cpp for unary ops * Move more functionality from CLikeSourceEmitter to HLSLSourceEmitter * Make output of parameters implementaion specific. * Extracted interpolation modifiers. * Remove IR from methods that don't need them. * Remove IR from method names. * Refactor handling of output of types - to make the impls implement the full path without lots of cases for specific impls * Add variable declaration modifiers and matrix layout to larget specific in slang-emit. * Make target specific internal functions _ prefixed.
Diffstat (limited to 'source/slang/slang-emit-hlsl.cpp')
-rw-r--r--source/slang/slang-emit-hlsl.cpp816
1 files changed, 816 insertions, 0 deletions
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
new file mode 100644
index 000000000..b4cebd3a3
--- /dev/null
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -0,0 +1,816 @@
+// slang-emit-hlsl.cpp
+#include "slang-emit-hlsl.h"
+
+#include "../core/slang-writer.h"
+
+#include "slang-emit-source-writer.h"
+#include "slang-mangled-lexer.h"
+
+#include <assert.h>
+
+namespace Slang {
+
+
+void HLSLSourceEmitter::_emitHLSLAttributeSingleString(const char* name, FuncDecl* entryPoint, Attribute* attrib)
+{
+ assert(attrib);
+
+ attrib->args.getCount();
+ if (attrib->args.getCount() != 1)
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Attribute expects single parameter");
+ return;
+ }
+
+ Expr* expr = attrib->args[0];
+
+ auto stringLitExpr = as<StringLiteralExpr>(expr);
+ if (!stringLitExpr)
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Attribute parameter expecting to be a string ");
+ return;
+ }
+
+ m_writer->emit("[");
+ m_writer->emit(name);
+ m_writer->emit("(\"");
+ m_writer->emit(stringLitExpr->value);
+ m_writer->emit("\")]\n");
+}
+
+void HLSLSourceEmitter::_emitHLSLAttributeSingleInt(const char* name, FuncDecl* entryPoint, Attribute* attrib)
+{
+ assert(attrib);
+
+ attrib->args.getCount();
+ if (attrib->args.getCount() != 1)
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Attribute expects single parameter");
+ return;
+ }
+
+ Expr* expr = attrib->args[0];
+
+ auto intLitExpr = as<IntegerLiteralExpr>(expr);
+ if (!intLitExpr)
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Attribute expects an int");
+ return;
+ }
+
+ m_writer->emit("[");
+ m_writer->emit(name);
+ m_writer->emit("(");
+ m_writer->emit(intLitExpr->value);
+ m_writer->emit(")]\n");
+}
+
+void HLSLSourceEmitter::_emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitVarChain* chain, char const* uniformSemanticSpelling)
+{
+ if (!chain)
+ return;
+ if (!chain->varLayout->FindResourceInfo(kind))
+ return;
+
+ UInt index = getBindingOffset(chain, kind);
+ UInt space = getBindingSpace(chain, kind);
+
+ switch (kind)
+ {
+ case LayoutResourceKind::Uniform:
+ {
+ UInt offset = index;
+
+ // The HLSL `c` register space is logically grouped in 16-byte registers,
+ // while we try to traffic in byte offsets. That means we need to pick
+ // a register number, based on the starting offset in 16-byte register
+ // units, and then a "component" within that register, based on 4-byte
+ // offsets from there. We cannot support more fine-grained offsets than that.
+
+ m_writer->emit(" : ");
+ m_writer->emit(uniformSemanticSpelling);
+ m_writer->emit("(c");
+
+ // Size of a logical `c` register in bytes
+ auto registerSize = 16;
+
+ // Size of each component of a logical `c` register, in bytes
+ auto componentSize = 4;
+
+ size_t startRegister = offset / registerSize;
+ m_writer->emit(int(startRegister));
+
+ size_t byteOffsetInRegister = offset % registerSize;
+
+ // If this field doesn't start on an even register boundary,
+ // then we need to emit additional information to pick the
+ // right component to start from
+ if (byteOffsetInRegister != 0)
+ {
+ // The value had better occupy a whole number of components.
+ SLANG_RELEASE_ASSERT(byteOffsetInRegister % componentSize == 0);
+
+ size_t startComponent = byteOffsetInRegister / componentSize;
+
+ static const char* kComponentNames[] = { "x", "y", "z", "w" };
+ m_writer->emit(".");
+ m_writer->emit(kComponentNames[startComponent]);
+ }
+ m_writer->emit(")");
+ }
+ break;
+
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::GenericResource:
+ case LayoutResourceKind::ExistentialTypeParam:
+ case LayoutResourceKind::ExistentialObjectParam:
+ // ignore
+ break;
+ default:
+ {
+ m_writer->emit(" : register(");
+ switch (kind)
+ {
+ case LayoutResourceKind::ConstantBuffer:
+ m_writer->emit("b");
+ break;
+ case LayoutResourceKind::ShaderResource:
+ m_writer->emit("t");
+ break;
+ case LayoutResourceKind::UnorderedAccess:
+ m_writer->emit("u");
+ break;
+ case LayoutResourceKind::SamplerState:
+ m_writer->emit("s");
+ break;
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled HLSL register type");
+ break;
+ }
+ m_writer->emit(index);
+ if (space)
+ {
+ m_writer->emit(", space");
+ m_writer->emit(space);
+ }
+ m_writer->emit(")");
+ }
+ }
+}
+
+void HLSLSourceEmitter::_emitHLSLRegisterSemantics(EmitVarChain* chain, char const* uniformSemanticSpelling)
+{
+ if (!chain) return;
+
+ auto layout = chain->varLayout;
+
+ switch (getSourceStyle())
+ {
+ default:
+ return;
+
+ case SourceStyle::HLSL:
+ break;
+ }
+
+ for (auto rr : layout->resourceInfos)
+ {
+ _emitHLSLRegisterSemantic(rr.kind, chain, uniformSemanticSpelling);
+ }
+}
+
+void HLSLSourceEmitter::_emitHLSLRegisterSemantics(VarLayout* varLayout, char const* uniformSemanticSpelling)
+{
+ if (!varLayout)
+ return;
+
+ EmitVarChain chain(varLayout);
+ _emitHLSLRegisterSemantics(&chain, uniformSemanticSpelling);
+}
+
+void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(EmitVarChain* chain)
+{
+ if (!chain)
+ return;
+
+ auto layout = chain->varLayout;
+ for (auto rr : layout->resourceInfos)
+ {
+ _emitHLSLRegisterSemantic(rr.kind, chain, "packoffset");
+ }
+}
+
+void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(RefPtr<VarLayout> fieldLayout, EmitVarChain* inChain)
+{
+ EmitVarChain chain(fieldLayout, inChain);
+ _emitHLSLParameterGroupFieldLayoutSemantics(&chain);
+}
+
+void HLSLSourceEmitter::_emitHLSLParameterGroup(IRGlobalParam* varDecl, IRUniformParameterGroupType* type)
+{
+ if (as<IRTextureBufferType>(type))
+ {
+ m_writer->emit("tbuffer ");
+ }
+ else
+ {
+ m_writer->emit("cbuffer ");
+ }
+ m_writer->emit(getName(varDecl));
+
+ auto varLayout = getVarLayout(varDecl);
+ SLANG_RELEASE_ASSERT(varLayout);
+
+ EmitVarChain blockChain(varLayout);
+
+ EmitVarChain containerChain = blockChain;
+ EmitVarChain elementChain = blockChain;
+
+ auto typeLayout = varLayout->typeLayout;
+ if (auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ {
+ containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
+ elementChain = EmitVarChain(parameterGroupTypeLayout->elementVarLayout, &blockChain);
+
+ typeLayout = parameterGroupTypeLayout->elementVarLayout->typeLayout;
+ }
+
+ _emitHLSLRegisterSemantic(LayoutResourceKind::ConstantBuffer, &containerChain);
+
+ m_writer->emit("\n{\n");
+ m_writer->indent();
+
+ auto elementType = type->getElementType();
+
+ emitType(elementType, getName(varDecl));
+ m_writer->emit(";\n");
+
+ m_writer->dedent();
+ m_writer->emit("}\n");
+}
+
+void HLSLSourceEmitter::_emitHLSLEntryPointAttributes(IRFunc* irFunc, EntryPointLayout* entryPointLayout)
+{
+ auto profile = m_effectiveProfile;
+ auto stage = entryPointLayout->profile.GetStage();
+
+ if (profile.getFamily() == ProfileFamily::DX)
+ {
+ if (profile.GetVersion() >= ProfileVersion::DX_6_1)
+ {
+ char const* stageName = getStageName(stage);
+ if (stageName)
+ {
+ m_writer->emit("[shader(\"");
+ m_writer->emit(stageName);
+ m_writer->emit("\")]");
+ }
+ }
+ }
+
+ switch (stage)
+ {
+ case Stage::Compute:
+ {
+ static const UInt kAxisCount = 3;
+ UInt sizeAlongAxis[kAxisCount];
+
+ // TODO: this is kind of gross because we are using a public
+ // reflection API function, rather than some kind of internal
+ // utility it forwards to...
+ spReflectionEntryPoint_getComputeThreadGroupSize(
+ (SlangReflectionEntryPoint*)entryPointLayout,
+ kAxisCount,
+ &sizeAlongAxis[0]);
+
+ m_writer->emit("[numthreads(");
+ for (int ii = 0; ii < 3; ++ii)
+ {
+ if (ii != 0) m_writer->emit(", ");
+ m_writer->emit(sizeAlongAxis[ii]);
+ }
+ m_writer->emit(")]\n");
+ }
+ break;
+ case Stage::Geometry:
+ {
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<MaxVertexCountAttribute>())
+ {
+ m_writer->emit("[maxvertexcount(");
+ m_writer->emit(attrib->value);
+ m_writer->emit(")]\n");
+ }
+ if (auto attrib = entryPointLayout->entryPoint->FindModifier<InstanceAttribute>())
+ {
+ m_writer->emit("[instance(");
+ m_writer->emit(attrib->value);
+ m_writer->emit(")]\n");
+ }
+ break;
+ }
+ case Stage::Domain:
+ {
+ FuncDecl* entryPoint = entryPointLayout->entryPoint;
+ /* [domain("isoline")] */
+ if (auto attrib = entryPoint->FindModifier<DomainAttribute>())
+ {
+ _emitHLSLAttributeSingleString("domain", entryPoint, attrib);
+ }
+
+ break;
+ }
+ case Stage::Hull:
+ {
+ // Lists these are only attributes for hull shader
+ // https://docs.microsoft.com/en-us/windows/desktop/direct3d11/direct3d-11-advanced-stages-hull-shader-design
+
+ FuncDecl* entryPoint = entryPointLayout->entryPoint;
+
+ /* [domain("isoline")] */
+ if (auto attrib = entryPoint->FindModifier<DomainAttribute>())
+ {
+ _emitHLSLAttributeSingleString("domain", entryPoint, attrib);
+ }
+ /* [domain("partitioning")] */
+ if (auto attrib = entryPoint->FindModifier<PartitioningAttribute>())
+ {
+ _emitHLSLAttributeSingleString("partitioning", entryPoint, attrib);
+ }
+ /* [outputtopology("line")] */
+ if (auto attrib = entryPoint->FindModifier<OutputTopologyAttribute>())
+ {
+ _emitHLSLAttributeSingleString("outputtopology", entryPoint, attrib);
+ }
+ /* [outputcontrolpoints(4)] */
+ if (auto attrib = entryPoint->FindModifier<OutputControlPointsAttribute>())
+ {
+ _emitHLSLAttributeSingleInt("outputcontrolpoints", entryPoint, attrib);
+ }
+ /* [patchconstantfunc("HSConst")] */
+ if (auto attrib = entryPoint->FindModifier<PatchConstantFuncAttribute>())
+ {
+ _emitHLSLFuncDeclPatchConstantFuncAttribute(irFunc, entryPoint, attrib);
+ }
+
+ break;
+ }
+ case Stage::Pixel:
+ {
+ if (irFunc->findDecoration<IREarlyDepthStencilDecoration>())
+ {
+ m_writer->emit("[earlydepthstencil]\n");
+ }
+ break;
+ }
+ // TODO: There are other stages that will need this kind of handling.
+ default:
+ break;
+ }
+}
+
+
+void HLSLSourceEmitter::_emitHLSLTextureType(IRTextureTypeBase* texType)
+{
+ switch (texType->getAccess())
+ {
+ case SLANG_RESOURCE_ACCESS_READ:
+ break;
+
+ case SLANG_RESOURCE_ACCESS_READ_WRITE:
+ m_writer->emit("RW");
+ break;
+
+ case SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
+ m_writer->emit("RasterizerOrdered");
+ break;
+
+ case SLANG_RESOURCE_ACCESS_APPEND:
+ m_writer->emit("Append");
+ break;
+
+ case SLANG_RESOURCE_ACCESS_CONSUME:
+ m_writer->emit("Consume");
+ break;
+
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource access mode");
+ break;
+ }
+
+ switch (texType->GetBaseShape())
+ {
+ case TextureFlavor::Shape::Shape1D: m_writer->emit("Texture1D"); break;
+ case TextureFlavor::Shape::Shape2D: m_writer->emit("Texture2D"); break;
+ case TextureFlavor::Shape::Shape3D: m_writer->emit("Texture3D"); break;
+ case TextureFlavor::Shape::ShapeCube: m_writer->emit("TextureCube"); break;
+ case TextureFlavor::Shape::ShapeBuffer: m_writer->emit("Buffer"); break;
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled resource shape");
+ break;
+ }
+
+ if (texType->isMultisample())
+ {
+ m_writer->emit("MS");
+ }
+ if (texType->isArray())
+ {
+ m_writer->emit("Array");
+ }
+ m_writer->emit("<");
+ emitType(texType->getElementType());
+ m_writer->emit(" >");
+}
+
+void HLSLSourceEmitter::_emitHLSLFuncDeclPatchConstantFuncAttribute(IRFunc* irFunc, FuncDecl* entryPoint, PatchConstantFuncAttribute* attrib)
+{
+ SLANG_UNUSED(attrib);
+
+ auto irPatchFunc = irFunc->findDecoration<IRPatchConstantFuncDecoration>();
+ assert(irPatchFunc);
+ if (!irPatchFunc)
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Unable to find [patchConstantFunc(...)] decoration");
+ return;
+ }
+
+ const String irName = getName(irPatchFunc->getFunc());
+
+ m_writer->emit("[patchconstantfunc(\"");
+ m_writer->emit(irName);
+ m_writer->emit("\")]\n");
+}
+
+void HLSLSourceEmitter::emitLayoutSemanticsImpl(IRInst* inst, char const* uniformSemanticSpelling)
+{
+ auto layout = getVarLayout(inst);
+ if (layout)
+ {
+ _emitHLSLRegisterSemantics(layout, uniformSemanticSpelling);
+ }
+}
+
+void HLSLSourceEmitter::emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type)
+{
+ _emitHLSLParameterGroup(varDecl, type);
+}
+
+void HLSLSourceEmitter::emitEntryPointAttributesImpl(IRFunc* irFunc, EntryPointLayout* entryPointLayout)
+{
+ _emitHLSLEntryPointAttributes(irFunc, entryPointLayout);
+}
+
+bool HLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec)
+{
+ switch (inst->op)
+ {
+ case kIROp_Construct:
+ case kIROp_makeVector:
+ case kIROp_MakeMatrix:
+ {
+ if (inst->getOperandCount() == 1)
+ {
+ EmitOpInfo outerPrec = inOuterPrec;
+ bool needClose = false;
+
+ auto prec = getInfo(EmitOp::Prefix);
+ needClose = maybeEmitParens(outerPrec, prec);
+
+ // Need to emit as cast for HLSL
+ m_writer->emit("(");
+ emitType(inst->getDataType());
+ m_writer->emit(") ");
+ emitOperand(inst->getOperand(0), mode, rightSide(outerPrec, prec));
+
+ maybeCloseParens(needClose);
+ // Handled
+ return true;
+ }
+ break;
+ }
+ case kIROp_BitCast:
+ {
+ auto toType = extractBaseType(inst->getDataType());
+ switch (toType)
+ {
+ default:
+ m_writer->emit("/* unhandled */");
+ break;
+ case BaseType::UInt:
+ break;
+ case BaseType::Int:
+ m_writer->emit("(");
+ emitType(inst->getDataType());
+ m_writer->emit(")");
+ break;
+ case BaseType::Float:
+ m_writer->emit("asfloat");
+ break;
+ }
+
+ m_writer->emit("(");
+ emitOperand(inst->getOperand(0), mode, getInfo(EmitOp::General));
+ m_writer->emit(")");
+ return true;
+ }
+ default: break;
+ }
+ // Not handled
+ return false;
+}
+
+void HLSLSourceEmitter::emitLayoutDirectivesImpl(TargetRequest* targetReq)
+{
+ switch (targetReq->getDefaultMatrixLayoutMode())
+ {
+ case kMatrixLayoutMode_RowMajor:
+ default:
+ m_writer->emit("#pragma pack_matrix(row_major)\n");
+ break;
+ case kMatrixLayoutMode_ColumnMajor:
+ m_writer->emit("#pragma pack_matrix(column_major)\n");
+ break;
+ }
+}
+
+void HLSLSourceEmitter::emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount)
+{
+ // TODO(tfoley) : should really emit these with sugar
+ m_writer->emit("vector<");
+ emitType(elementType);
+ m_writer->emit(",");
+ m_writer->emit(elementCount);
+ m_writer->emit(">");
+}
+
+void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
+{
+ switch (type->op)
+ {
+ case kIROp_VoidType:
+ case kIROp_BoolType:
+ case kIROp_Int8Type:
+ case kIROp_Int16Type:
+ case kIROp_IntType:
+ case kIROp_Int64Type:
+ case kIROp_UInt8Type:
+ case kIROp_UInt16Type:
+ case kIROp_UIntType:
+ case kIROp_UInt64Type:
+ case kIROp_FloatType:
+ case kIROp_DoubleType:
+ case kIROp_HalfType:
+ {
+ m_writer->emit(getDefaultBuiltinTypeName(type->op));
+ return;
+ }
+ case kIROp_StructType:
+ m_writer->emit(getName(type));
+ return;
+
+ case kIROp_VectorType:
+ {
+ auto vecType = (IRVectorType*)type;
+ emitVectorTypeNameImpl(vecType->getElementType(), GetIntVal(vecType->getElementCount()));
+ return;
+ }
+ case kIROp_MatrixType:
+ {
+ auto matType = (IRMatrixType*)type;
+
+ // TODO(tfoley): should really emit these with sugar
+ m_writer->emit("matrix<");
+ emitType(matType->getElementType());
+ m_writer->emit(",");
+ emitVal(matType->getRowCount(), getInfo(EmitOp::General));
+ m_writer->emit(",");
+ emitVal(matType->getColumnCount(), getInfo(EmitOp::General));
+ m_writer->emit("> ");
+ return;
+ }
+ case kIROp_SamplerStateType:
+ case kIROp_SamplerComparisonStateType:
+ {
+ auto samplerStateType = cast<IRSamplerStateTypeBase>(type);
+
+ switch (samplerStateType->op)
+ {
+ case kIROp_SamplerStateType: m_writer->emit("SamplerState"); break;
+ case kIROp_SamplerComparisonStateType: m_writer->emit("SamplerComparisonState"); break;
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled sampler state flavor");
+ break;
+ }
+ return;
+ }
+ default: break;
+ }
+
+ // TODO: Ideally the following should be data-driven,
+ // based on meta-data attached to the definitions of
+ // each of these IR opcodes.
+ if (auto texType = as<IRTextureType>(type))
+ {
+ _emitHLSLTextureType(texType);
+ return;
+ }
+ else if (auto textureSamplerType = as<IRTextureSamplerType>(type))
+ {
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "this target should see combined texture-sampler types");
+ return;
+ }
+ else if (auto imageType = as<IRGLSLImageType>(type))
+ {
+ _emitHLSLTextureType(imageType);
+ return;
+ }
+ else if (auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type))
+ {
+ switch (structuredBufferType->op)
+ {
+ case kIROp_HLSLStructuredBufferType: m_writer->emit("StructuredBuffer"); break;
+ case kIROp_HLSLRWStructuredBufferType: m_writer->emit("RWStructuredBuffer"); break;
+ case kIROp_HLSLRasterizerOrderedStructuredBufferType: m_writer->emit("RasterizerOrderedStructuredBuffer"); break;
+ case kIROp_HLSLAppendStructuredBufferType: m_writer->emit("AppendStructuredBuffer"); break;
+ case kIROp_HLSLConsumeStructuredBufferType: m_writer->emit("ConsumeStructuredBuffer"); break;
+
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled structured buffer type");
+ break;
+ }
+
+ m_writer->emit("<");
+ emitType(structuredBufferType->getElementType());
+ m_writer->emit(" >");
+
+ return;
+ }
+ else if (auto untypedBufferType = as<IRUntypedBufferResourceType>(type))
+ {
+ switch (type->op)
+ {
+ case kIROp_HLSLByteAddressBufferType: m_writer->emit("ByteAddressBuffer"); break;
+ case kIROp_HLSLRWByteAddressBufferType: m_writer->emit("RWByteAddressBuffer"); break;
+ case kIROp_HLSLRasterizerOrderedByteAddressBufferType: m_writer->emit("RasterizerOrderedByteAddressBuffer"); break;
+ case kIROp_RaytracingAccelerationStructureType: m_writer->emit("RaytracingAccelerationStructure"); break;
+
+ default:
+ SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled buffer type");
+ break;
+ }
+
+ return;
+ }
+
+ // HACK: As a fallback for HLSL targets, assume that the name of the
+ // instruction being used is the same as the name of the HLSL type.
+ {
+ auto opInfo = getIROpInfo(type->op);
+ m_writer->emit(opInfo.name);
+ UInt operandCount = type->getOperandCount();
+ if (operandCount)
+ {
+ m_writer->emit("<");
+ for (UInt ii = 0; ii < operandCount; ++ii)
+ {
+ if (ii != 0) m_writer->emit(", ");
+ emitVal(type->getOperand(ii), getInfo(EmitOp::General));
+ }
+ m_writer->emit(" >");
+ }
+ }
+}
+
+void HLSLSourceEmitter::emitRateQualifiersImpl(IRRate* rate)
+{
+ if (as<IRGroupSharedRate>(rate))
+ {
+ m_writer->emit("groupshared ");
+ }
+}
+
+void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst)
+{
+ if (auto semanticDecoration = inst->findDecoration<IRSemanticDecoration>())
+ {
+ m_writer->emit(" : ");
+ m_writer->emit(semanticDecoration->getSemanticName());
+ return;
+ }
+
+ if (auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>())
+ {
+ auto layout = layoutDecoration->getLayout();
+ if (auto varLayout = as<VarLayout>(layout))
+ {
+ emitSemantics(varLayout);
+ }
+ else if (auto entryPointLayout = as<EntryPointLayout>(layout))
+ {
+ if (auto resultLayout = entryPointLayout->resultLayout)
+ {
+ emitSemantics(resultLayout);
+ }
+ }
+ }
+}
+
+void HLSLSourceEmitter::emitSimpleFuncParamImpl(IRParam* param)
+{
+ if (auto layoutDecor = param->findDecoration<IRLayoutDecoration>())
+ {
+ Layout* layout = layoutDecor->getLayout();
+ VarLayout* varLayout = as<VarLayout>(layout);
+
+ if (varLayout)
+ {
+ auto var = varLayout->getVariable();
+
+ if (auto primTypeModifier = var->FindModifier<HLSLGeometryShaderInputPrimitiveTypeModifier>())
+ {
+ if (as<HLSLTriangleModifier>(primTypeModifier))
+ m_writer->emit("triangle ");
+ else if (as<HLSLPointModifier>(primTypeModifier))
+ m_writer->emit("point ");
+ else if (as<HLSLLineModifier>(primTypeModifier))
+ m_writer->emit("line ");
+ else if (as<HLSLLineAdjModifier>(primTypeModifier))
+ m_writer->emit("lineadj ");
+ else if (as<HLSLTriangleAdjModifier>(primTypeModifier))
+ m_writer->emit("triangleadj ");
+ }
+ }
+ }
+
+ Super::emitSimpleFuncParamImpl(param);
+}
+
+static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode)
+{
+ switch (mode)
+ {
+ case IRInterpolationMode::NoInterpolation: return UnownedStringSlice::fromLiteral("nointerpolation");
+ case IRInterpolationMode::NoPerspective: return UnownedStringSlice::fromLiteral("noperspective");
+ case IRInterpolationMode::Linear: return UnownedStringSlice::fromLiteral("linear");
+ case IRInterpolationMode::Sample: return UnownedStringSlice::fromLiteral("sample");
+ case IRInterpolationMode::Centroid: return UnownedStringSlice::fromLiteral("centroid");
+ default: return UnownedStringSlice();
+ }
+}
+
+void HLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout)
+{
+ SLANG_UNUSED(layout);
+ SLANG_UNUSED(valueType);
+
+ for (auto dd : varInst->getDecorations())
+ {
+ if (dd->op != kIROp_InterpolationModeDecoration)
+ continue;
+
+ auto decoration = (IRInterpolationModeDecoration*)dd;
+
+ UnownedStringSlice modeText = _getInterpolationModifierText(decoration->getMode());
+ if (modeText.size() > 0)
+ {
+ m_writer->emit(modeText);
+ m_writer->emitChar(' ');
+ }
+ }
+}
+
+void HLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
+{
+ if (varDecl->findDecoration<IRGloballyCoherentDecoration>())
+ {
+ m_writer->emit("globallycoherent\n");
+ }
+}
+
+void HLSLSourceEmitter::emitMatrixLayoutModifiersImpl(VarLayout* layout)
+{
+ // When a variable has a matrix type, we want to emit an explicit
+ // layout qualifier based on what the layout has been computed to be.
+ //
+
+ auto typeLayout = layout->typeLayout;
+ while (auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout))
+ typeLayout = arrayTypeLayout->elementTypeLayout;
+
+ if (auto matrixTypeLayout = typeLayout.as<MatrixTypeLayout>())
+ {
+ switch (matrixTypeLayout->mode)
+ {
+ case kMatrixLayoutMode_ColumnMajor:
+ m_writer->emit("column_major ");
+ break;
+
+ case kMatrixLayoutMode_RowMajor:
+ m_writer->emit("row_major ");
+ break;
+ }
+ }
+}
+
+
+} // namespace Slang