summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp263
1 files changed, 234 insertions, 29 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 64ac85bd4..2d42a79ed 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -2877,6 +2877,9 @@ struct EmitVisitor
}
Substitutions* subst = declRef.substitutions.Ptr();
+ if (!subst)
+ return;
+
Emit("<");
UInt argCount = subst->args.Count();
for (UInt aa = 0; aa < argCount; ++aa)
@@ -3973,14 +3976,45 @@ emitDeclImpl(decl, nullptr);
return id;
}
- String getName(IRValue* inst)
+ String getIRName(Decl* decl)
+ {
+ // It is a bit ugly, but we need a deterministic way
+ // to get a name for things when emitting from the IR
+ // that won't conflict with any keywords, builtins, etc.
+ // in the target language.
+ //
+ // Eventually we should accomplish this by using
+ // mangled names everywhere, but that complicates things
+ // when we are also using direct comparison to fxc/glslang
+ // output for some of our tests.
+ //
+ // TODO: need a flag to get rid of the step that adds
+ // a prefix here, so that we can get "clean" output
+ // when needed.
+ //
+
+ String name;
+ if (!(context->shared->entryPoint->compileRequest->compileFlags & SLANG_COMPILE_FLAG_NO_MANGLING))
+ {
+ name.append("_s");
+ }
+ name.append(getText(decl->getName()));
+ return name;
+ }
+
+ String getIRName(DeclRefBase const& declRef)
+ {
+ return getIRName(declRef.decl);
+ }
+
+ String getIRName(IRValue* inst)
{
switch(inst->op)
{
case kIROp_decl_ref:
{
auto irDeclRef = (IRDeclRef*) inst;
- return getText(irDeclRef->declRef.GetName());
+ return getIRName(irDeclRef->declRef);
}
break;
@@ -3996,7 +4030,7 @@ emitDeclImpl(decl, nullptr);
return getText(reflectionNameMod->nameAndLoc.name);
}
- return getText(decl->getName());
+ return getIRName(decl);
}
StringBuilder sb;
@@ -4376,7 +4410,7 @@ emitDeclImpl(decl, nullptr);
switch(inst->op)
{
default:
- emit(getName(inst));
+ emit(getIRName(inst));
break;
}
}
@@ -4428,7 +4462,7 @@ emitDeclImpl(decl, nullptr);
if(!type)
return;
- emitIRType(context, type, getName(inst));
+ emitIRType(context, type, getIRName(inst));
emit(" = ");
}
@@ -4487,7 +4521,7 @@ emitDeclImpl(decl, nullptr);
emitIROperand(context, fieldExtract->getBase());
emit(".");
- emit(getName(fieldExtract->getField()));
+ emit(getIRName(fieldExtract->getField()));
}
break;
@@ -4503,7 +4537,7 @@ emitDeclImpl(decl, nullptr);
emit(".");
}
- emit(getName(ii->getField()));
+ emit(getIRName(ii->getField()));
}
break;
@@ -4592,11 +4626,11 @@ emitDeclImpl(decl, nullptr);
{
emitIROperand(context, inst->getArg(0));
emit("(");
- UInt argCount = inst->getArgCount() - 1;
- for( UInt aa = 0; aa < argCount; ++aa )
+ UInt argCount = inst->getArgCount();
+ for( UInt aa = 1; aa < argCount; ++aa )
{
- if(aa != 0) emit(", ");
- emitIROperand(context, inst->getArg(aa + 1));
+ if(aa != 1) emit(", ");
+ emitIROperand(context, inst->getArg(aa));
}
emit(")");
}
@@ -4688,7 +4722,7 @@ emitDeclImpl(decl, nullptr);
auto ptrType = inst->getType();
auto valType = ((PtrType*)ptrType)->getValueType();
- auto name = getName(inst);
+ auto name = getIRName(inst);
emitIRType(context, valType, name);
emit(";\n");
}
@@ -5016,6 +5050,37 @@ emitDeclImpl(decl, nullptr);
return func->getFirstBlock() != nullptr;
}
+ String getIRFuncName(
+ IRFunc* func)
+ {
+ if (isEntryPoint(func))
+ {
+ // GLSL will always need to use `main` as the
+ // name for an entry-point function, but other
+ // targets should try to use the original name.
+ //
+ // TODO: always use `main`, and have any code
+ // that wraps this know to use `main` instead
+ // of the original entry-point name...
+ //
+ if (getTarget(context) != CodeGenTarget::GLSL)
+ {
+ if (auto highLevelDeclDecoration = func->findDecoration<IRHighLevelDeclDecoration>())
+ {
+ return getText(highLevelDeclDecoration->decl->getName());
+ }
+ }
+
+ //
+
+ return "main";
+ }
+ else
+ {
+ return getIRName(func);
+ }
+ }
+
void emitIRSimpleFunc(
EmitContext* context,
IRFunc* func)
@@ -5036,7 +5101,7 @@ emitDeclImpl(decl, nullptr);
emit(")]\n");
}
- auto name = getName(func);
+ auto name = getIRFuncName(func);
emitIRType(context, resultType, name);
@@ -5047,7 +5112,7 @@ emitDeclImpl(decl, nullptr);
if(pp != firstParam)
emit(", ");
- auto paramName = getName(pp);
+ auto paramName = getIRName(pp);
emitIRType(context, pp->getType(), paramName);
emitIRSemantics(context, pp);
@@ -5085,7 +5150,7 @@ emitDeclImpl(decl, nullptr);
auto funcType = func->getType();
auto resultType = func->getResultType();
- auto name = getName(func);
+ auto name = getIRFuncName(func);
emitIRType(context, resultType, name);
@@ -5163,7 +5228,7 @@ emitDeclImpl(decl, nullptr);
// result parameter into an `out` parameter, so that
// we can handle those uniformly.
//
- String resultName = getName(func) + "_result";
+ String resultName = getIRName(func) + "_result";
emitGLSLLayoutQualifiers(entryPointLayout->resultLayout);
emit("out ");
emitIRType(context, resultType, resultName);
@@ -5182,7 +5247,7 @@ emitDeclImpl(decl, nullptr);
// TODO: actually handle `out` parameters here.
auto paramLayout = getVarLayout(context, pp);
- auto paramName = getName(pp);
+ auto paramName = getIRName(pp);
emitGLSLLayoutQualifiers(paramLayout);
emit("in ");
emitIRType(context, pp->getType(), paramName);
@@ -5218,6 +5283,19 @@ emitDeclImpl(decl, nullptr);
return false;
}
+ // Detect if the given IR function represents a
+ // declaration of an intrinsic/builtin for the
+ // current code-generation target.
+ bool isTargetIntrinsic(
+ EmitContext* ctxt,
+ IRFunc* func)
+ {
+ // For now we do this in an overly simplistic
+ // fashion: we say that *any* function declaration
+ // (rather then definition) must be an intrinsic:
+ return !isDefinition(func);
+ }
+
void emitIRFunc(
EmitContext* context,
IRFunc* func)
@@ -5239,7 +5317,13 @@ emitDeclImpl(decl, nullptr);
// This is just a function declaration,
// and so we want to emit it as such.
// (Or maybe not emit it at all).
- //
+
+ // We do not emit the declaration for
+ // functions that appear to be intrinsics/builtins
+ // in the target langugae.
+ if (isTargetIntrinsic(context, func))
+ return;
+
emitIRFuncDecl(context, func);
}
else
@@ -5280,6 +5364,8 @@ emitDeclImpl(decl, nullptr);
if (!layout)
return;
+ auto target = context->shared->target;
+
// We need to handle the case where the variable has
// a matrix type, and has been given a non-standard
// layout attribute (for HLSL, `row_major` is the
@@ -5287,16 +5373,45 @@ emitDeclImpl(decl, nullptr);
//
if (auto matrixTypeLayout = layout->typeLayout.As<MatrixTypeLayout>())
{
- switch (matrixTypeLayout->mode)
+ switch (target)
{
- case kMatrixLayoutMode_ColumnMajor:
- emit("column_major ");
+ case CodeGenTarget::HLSL:
+ switch (matrixTypeLayout->mode)
+ {
+ case kMatrixLayoutMode_ColumnMajor:
+ if(target == CodeGenTarget::GLSL)
+ emit("column_major ");
+ break;
+
+ case kMatrixLayoutMode_RowMajor:
+ emit("row_major ");
+ break;
+ }
+ break;
+
+ case CodeGenTarget::GLSL:
+ // Reminder: the meaning of row/column major layout
+ // in our semantics is the *opposite* of what GLSL
+ // calls them, because what they call "columns"
+ // are what we call "rows."
+ //
+ switch (matrixTypeLayout->mode)
+ {
+ case kMatrixLayoutMode_ColumnMajor:
+ if(target == CodeGenTarget::GLSL)
+ emit("layout(row_major)\n");
+ break;
+
+ case kMatrixLayoutMode_RowMajor:
+ emit("layout(column_major)\n");
+ break;
+ }
break;
- case kMatrixLayoutMode_RowMajor:
- emit("row_major ");
+ default:
break;
}
+
}
if (context->shared->target == CodeGenTarget::GLSL)
@@ -5325,13 +5440,13 @@ emitDeclImpl(decl, nullptr);
}
}
- void emitIRParameterBlock(
+ void emitHLSLParameterBlock(
EmitContext* context,
IRGlobalVar* varDecl,
UniformParameterBlockType* type)
{
emit("cbuffer ");
- emit(getName(varDecl));
+ emit(getIRName(varDecl));
auto layout = getVarLayout(context, varDecl);
assert(layout);
@@ -5375,7 +5490,7 @@ emitDeclImpl(decl, nullptr);
emitIRVarModifiers(context, fieldLayout);
auto fieldType = GetType(ff);
- emitIRType(context, fieldType, ff.GetName());
+ emitIRType(context, fieldType, getIRName(ff));
emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
@@ -5391,6 +5506,96 @@ emitDeclImpl(decl, nullptr);
emit("}\n");
}
+ void emitGLSLParameterBlock(
+ EmitContext* context,
+ IRGlobalVar* varDecl,
+ UniformParameterBlockType* type)
+ {
+ auto layout = getVarLayout(context, varDecl);
+ assert(layout);
+
+ auto info = layout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot);
+ if (info)
+ {
+ emitGLSLLayoutQualifier(*info);
+ }
+
+ emit("uniform ");
+ emit(getIRName(varDecl));
+
+ emit("\n{\n");
+
+ auto elementType = type->getElementType();
+
+ auto typeLayout = layout->typeLayout;
+ if( auto parameterBlockTypeLayout = typeLayout.As<ParameterBlockTypeLayout>() )
+ {
+ typeLayout = parameterBlockTypeLayout->elementTypeLayout;
+ }
+
+ if(auto declRefType = elementType->As<DeclRefType>())
+ {
+ if(auto structDeclRef = declRefType->declRef.As<StructDecl>())
+ {
+ auto structTypeLayout = typeLayout.As<StructTypeLayout>();
+ assert(structTypeLayout);
+
+ UInt fieldIndex = 0;
+ for(auto ff : GetFields(structDeclRef))
+ {
+ // TODO: need a plan to deal with the case where the IR-level
+ // `struct` type might not match the high-level type, so that
+ // the numbering of fields is different.
+ //
+ // The right plan is probably to require that the lowering pass
+ // create a fresh layout for any type/variable that it splits
+ // in this fashion, so that the layout information it attaches
+ // can always be assumed to apply to the actual instruciton.
+ //
+
+ auto fieldLayout = structTypeLayout->fields[fieldIndex++];
+
+ emitIRVarModifiers(context, fieldLayout);
+
+ auto fieldType = GetType(ff);
+ emitIRType(context, fieldType, getIRName(ff));
+
+// emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
+
+ emit(";\n");
+ }
+ }
+ }
+ else
+ {
+ emit("/* unexpected */");
+ }
+
+ // TODO: we should consider always giving parameter blocks
+ // names when outputting GLSL, since that shouldn't affect
+ // the semantics of things, and will reduce the risk of
+ // collisions in the global namespace...
+
+ emit("};\n");
+ }
+
+ void emitIRParameterBlock(
+ EmitContext* context,
+ IRGlobalVar* varDecl,
+ UniformParameterBlockType* type)
+ {
+ switch (context->shared->target)
+ {
+ case CodeGenTarget::HLSL:
+ emitHLSLParameterBlock(context, varDecl, type);
+ break;
+
+ case CodeGenTarget::GLSL:
+ emitGLSLParameterBlock(context, varDecl, type);
+ break;
+ }
+ }
+
void emitIRVar(
EmitContext* context,
IRVar* varDecl)
@@ -5430,7 +5635,7 @@ emitDeclImpl(decl, nullptr);
}
#endif
- emitIRType(context, varType, getName(varDecl));
+ emitIRType(context, varType, getIRName(varDecl));
emitIRSemantics(context, varDecl);
@@ -5474,7 +5679,7 @@ emitDeclImpl(decl, nullptr);
}
#endif
- emitIRType(context, varType, getName(varDecl));
+ emitIRType(context, varType, getIRName(varDecl));
emitIRSemantics(context, varDecl);
@@ -5547,7 +5752,7 @@ emitDeclImpl(decl, nullptr);
continue;
auto fieldType = GetType(ff);
- emitIRType(context, fieldType, ff.GetName());
+ emitIRType(context, fieldType, getIRName(ff));
EmitSemantics(ff.getDecl());