summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-emit-c-like.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-emit-c-like.cpp')
-rw-r--r--source/slang/slang-emit-c-like.cpp479
1 files changed, 4 insertions, 475 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index d21e16186..d916019c7 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -22,6 +22,8 @@
#include "slang-type-layout.h"
#include "slang-visitor.h"
+#include "slang-intrinsic-expand.h"
+
#include "slang-emit-source-writer.h"
#include "slang-mangled-lexer.h"
@@ -1417,481 +1419,8 @@ void CLikeSourceEmitter::emitIntrinsicCallExprImpl(
}
else
{
- int openParenCount = 0;
-
- const auto returnType = inst->getDataType();
-
- // If it returns void -> then we don't need parenthesis
- if (as<IRVoidType>(returnType) == nullptr)
- {
- m_writer->emit("(");
- openParenCount++;
- }
-
- // General case: we are going to emit some more complex text.
-
- char const* cursor = name.begin();
- char const* end = name.end();
- while(cursor != end)
- {
- char c = *cursor++;
- if( c != '$' )
- {
- // Not an escape sequence
- m_writer->emitRawTextSpan(&c, &c+1);
- continue;
- }
-
- SLANG_RELEASE_ASSERT(cursor != end);
-
- char d = *cursor++;
-
- switch (d)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- // Simple case: emit one of the direct arguments to the call
- Index argIndex = d - '0';
- SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < argCount));
- m_writer->emit("(");
- emitOperand(args[argIndex].get(), getInfo(EmitOp::General));
- m_writer->emit(")");
- }
- break;
-
- case 'T':
- // Get the the 'element' type for the type of the param at the index
- {
- SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9');
- Index argIndex = (*cursor++) - '0';
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- IRType* type = args[argIndex].get()->getDataType();
- if (auto baseTextureType = as<IRTextureType>(type))
- {
- type = baseTextureType->getElementType();
- }
- emitType(type);
- }
- break;
-
- case 'S':
- // Get the scalar type of a generic at specified index
- {
- SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9');
- Index argIndex = (*cursor++) - '0';
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- IRType* type = args[argIndex].get()->getDataType();
- if (auto baseTextureType = as<IRTextureType>(type))
- {
- type = baseTextureType->getElementType();
- }
-
- IRBasicType* underlyingType = nullptr;
- if (auto basicType = as<IRBasicType>(type))
- {
- underlyingType = basicType;
- }
- else if (auto vectorType = as<IRVectorType>(type))
- {
- underlyingType = as<IRBasicType>(vectorType->getElementType());
- }
- else if (auto matrixType = as<IRMatrixType>(type))
- {
- underlyingType = as<IRBasicType>(matrixType->getElementType());
- }
-
- SLANG_ASSERT(underlyingType);
-
- emitSimpleType(underlyingType);
- }
- break;
- case 'p':
- {
- // If we are calling a D3D texturing operation in the form t.Foo(s, ...),
- // then this form will pair up the t and s arguments as needed for a GLSL
- // texturing operation.
- SLANG_RELEASE_ASSERT(argCount >= 2);
-
- auto textureArg = args[0].get();
- auto samplerArg = args[1].get();
-
- if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType()))
- {
- emitTextureOrTextureSamplerTypeImpl(baseTextureType, "sampler");
-
- if (auto samplerType = as<IRSamplerStateTypeBase>(samplerArg->getDataType()))
- {
- if (as<IRSamplerComparisonStateType>(samplerType))
- {
- m_writer->emit("Shadow");
- }
- }
-
- m_writer->emit("(");
- emitOperand(textureArg, getInfo(EmitOp::General));
- m_writer->emit(",");
- emitOperand(samplerArg, getInfo(EmitOp::General));
- m_writer->emit(")");
- }
- else
- {
- SLANG_UNEXPECTED("bad format in intrinsic definition");
- }
- }
- break;
-
- case 'c':
- {
- // When doing texture access in glsl the result may need to be cast.
- // In particular if the underlying texture is 'half' based, glsl only accesses (read/write)
- // as float. So we need to cast to a half type on output.
- // When storing into a texture it is still the case the value written must be half - but
- // we don't need to do any casting there as half is coerced to float without a problem.
- SLANG_RELEASE_ASSERT(argCount >= 1);
-
- auto textureArg = args[0].get();
- if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType()))
- {
- auto elementType = baseTextureType->getElementType();
- IRBasicType* underlyingType = nullptr;
- if (auto basicType = as<IRBasicType>(elementType))
- {
- underlyingType = basicType;
- }
- else if (auto vectorType = as<IRVectorType>(elementType))
- {
- underlyingType = as<IRBasicType>(vectorType->getElementType());
- }
-
- // We only need to output a cast if the underlying type is half.
- if (underlyingType && underlyingType->op == kIROp_HalfType)
- {
- emitSimpleType(elementType);
- m_writer->emit("(");
- openParenCount++;
- }
- }
- }
- break;
-
- case 'z':
- {
- // If we are calling a D3D texturing operation in the form t.Foo(s, ...),
- // where `t` is a `Texture*<T>`, then this is the step where we try to
- // properly swizzle the output of the equivalent GLSL call into the right
- // shape.
- SLANG_RELEASE_ASSERT(argCount >= 1);
-
- auto textureArg = args[0].get();
- if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType()))
- {
- auto elementType = baseTextureType->getElementType();
- if (auto basicType = as<IRBasicType>(elementType))
- {
- // A scalar result is expected
- m_writer->emit(".x");
- }
- else if (auto vectorType = as<IRVectorType>(elementType))
- {
- // A vector result is expected
- auto elementCount = getIntVal(vectorType->getElementCount());
-
- if (elementCount < 4)
- {
- char const* swiz[] = { "", ".x", ".xy", ".xyz", "" };
- m_writer->emit(swiz[elementCount]);
- }
- }
- else
- {
- // What other cases are possible?
- }
- }
- else
- {
- SLANG_UNEXPECTED("bad format in intrinsic definition");
- }
- }
- break;
-
- case 'N':
- {
- // Extract the element count from a vector argument so that
- // we can use it in the constructed expression.
-
- SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9');
- Index argIndex = (*cursor++) - '0';
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- auto vectorArg = args[argIndex].get();
- if (auto vectorType = as<IRVectorType>(vectorArg->getDataType()))
- {
- auto elementCount = getIntVal(vectorType->getElementCount());
- m_writer->emit(elementCount);
- }
- else
- {
- SLANG_UNEXPECTED("bad format in intrinsic definition");
- }
- }
- break;
-
- case 'V':
- {
- // Take an argument of some scalar/vector type and pad
- // it out to a 4-vector with the same element type
- // (this is the inverse of `$z`).
- //
- SLANG_RELEASE_ASSERT(*cursor >= '0' && *cursor <= '9');
- Index argIndex = (*cursor++) - '0';
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- auto arg = args[argIndex].get();
- IRIntegerValue elementCount = 1;
- IRType* elementType = arg->getDataType();
- if (auto vectorType = as<IRVectorType>(elementType))
- {
- elementCount = getIntVal(vectorType->getElementCount());
- elementType = vectorType->getElementType();
- }
-
- if(elementCount == 4)
- {
- // In the simple case, the operand is already a 4-vector,
- // so we can just emit it as-is.
- emitOperand(arg, getInfo(EmitOp::General));
- }
- else
- {
- // Otherwise, we need to construct a 4-vector from the
- // value we have, padding it out with zero elements as
- // needed.
- //
- emitVectorTypeName(elementType, 4);
- m_writer->emit("(");
- emitOperand(arg, getInfo(EmitOp::General));
- for(IRIntegerValue ii = elementCount; ii < 4; ++ii)
- {
- m_writer->emit(", ");
- if(getSourceLanguage() == SourceLanguage::GLSL)
- {
- emitSimpleType(elementType);
- m_writer->emit("(0)");
- }
- else
- {
- m_writer->emit("0");
- }
- }
- m_writer->emit(")");
- }
- }
- break;
-
- case 'a':
- {
- // We have an operation that needs to lower to either
- // `atomic*` or `imageAtomic*` for GLSL, depending on
- // whether its first operand is a subscript into an
- // array. This `$a` is the first `a` in `atomic`,
- // so we will replace it accordingly.
- //
- // TODO: This distinction should be made earlier,
- // with the front-end picking the right overload
- // based on the "address space" of the argument.
-
- Index argIndex = 0;
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- auto arg = args[argIndex].get();
- if(arg->op == kIROp_ImageSubscript)
- {
- m_writer->emit("imageA");
- }
- else
- {
- m_writer->emit("a");
- }
- }
- break;
-
- case 'A':
- {
- // We have an operand that represents the destination
- // of an atomic operation in GLSL, and it should
- // be lowered based on whether it is an ordinary l-value,
- // or an image subscript. In the image subscript case
- // this operand will turn into multiple arguments
- // to the `imageAtomic*` function.
- //
-
- Index argIndex = 0;
- SLANG_RELEASE_ASSERT(argCount > argIndex);
-
- auto arg = args[argIndex].get();
- if(arg->op == kIROp_ImageSubscript)
- {
- if(getSourceLanguage() == SourceLanguage::GLSL)
- {
- // TODO: we don't handle the multisample
- // case correctly here, where the last
- // component of the image coordinate needs
- // to be broken out into its own argument.
- //
- m_writer->emit("(");
- emitOperand(arg->getOperand(0), getInfo(EmitOp::General));
- m_writer->emit("), ");
-
- // The coordinate argument will have been computed
- // as a `vector<uint, N>` because that is how the
- // HLSL image subscript operations are defined.
- // In contrast, the GLSL `imageAtomic*` operations
- // expect `vector<int, N>` coordinates, so we
- // will hackily insert the conversion here as
- // part of the intrinsic op.
- //
- auto coords = arg->getOperand(1);
- auto coordsType = coords->getDataType();
-
- auto coordsVecType = as<IRVectorType>(coordsType);
- IRIntegerValue elementCount = 1;
- if(coordsVecType)
- {
- coordsType = coordsVecType->getElementType();
- elementCount = getIntVal(coordsVecType->getElementCount());
- }
-
- SLANG_ASSERT(coordsType->op == kIROp_UIntType);
-
- if (elementCount > 1)
- {
- m_writer->emit("ivec");
- m_writer->emit(elementCount);
- }
- else
- {
- m_writer->emit("int");
- }
-
- m_writer->emit("(");
- emitOperand(arg->getOperand(1), getInfo(EmitOp::General));
- m_writer->emit(")");
- }
- else
- {
- m_writer->emit("(");
- emitOperand(arg, getInfo(EmitOp::General));
- m_writer->emit(")");
- }
- }
- else
- {
- m_writer->emit("(");
- emitOperand(arg, getInfo(EmitOp::General));
- m_writer->emit(")");
- }
- }
- break;
-
- // We will use the `$X` case as a prefix for
- // special logic needed when cross-compiling ray-tracing
- // shaders.
- case 'X':
- {
- SLANG_RELEASE_ASSERT(*cursor);
- switch(*cursor++)
- {
- case 'P':
- {
- // The `$XP` case handles looking up
- // the associated `location` for a variable
- // used as the argument ray payload at a
- // trace call site.
-
- Index argIndex = 0;
- SLANG_RELEASE_ASSERT(argCount > argIndex);
- auto arg = args[argIndex].get();
- auto argLoad = as<IRLoad>(arg);
- SLANG_RELEASE_ASSERT(argLoad);
- auto argVar = argLoad->getOperand(0);
- m_writer->emit(getRayPayloadLocation(argVar));
- }
- break;
-
- case 'C':
- {
- // The `$XC` case handles looking up
- // the associated `location` for a variable
- // used as the argument callable payload at a
- // call site.
-
- Index argIndex = 0;
- SLANG_RELEASE_ASSERT(argCount > argIndex);
- auto arg = args[argIndex].get();
- auto argLoad = as<IRLoad>(arg);
- SLANG_RELEASE_ASSERT(argLoad);
- auto argVar = argLoad->getOperand(0);
- m_writer->emit(getCallablePayloadLocation(argVar));
- }
- break;
-
- default:
- SLANG_RELEASE_ASSERT(false);
- break;
- }
- }
- break;
-
- case 'P':
- // Type-based prefix as used for CUDA and C++ targets
- {
- Index argIndex = 0;
- SLANG_RELEASE_ASSERT(argCount > argIndex);
- auto arg = args[argIndex].get();
- auto argType = arg->getDataType();
-
- const char* str = "";
- switch(argType->op)
- {
- #define CASE(OP, STR) \
- case kIROp_##OP: str = #STR; break
-
- CASE(Int8Type, I8);
- CASE(Int16Type, I16);
- CASE(IntType, I32);
- CASE(Int64Type, I64);
- CASE(UInt8Type, U8);
- CASE(UInt16Type, U16);
- CASE(UIntType, U32);
- CASE(UInt64Type, U64);
- CASE(HalfType, F16);
- CASE(FloatType, F32);
- CASE(DoubleType, F64);
-
- #undef CASE
-
- default:
- SLANG_UNEXPECTED("unexpected type in intrinsic definition");
- break;
- }
- m_writer->emit(str);
- }
- break;
-
- default:
- SLANG_UNEXPECTED("bad format in intrinsic definition");
- break;
- }
- }
-
- // Close any remaining open parens
- for (; openParenCount > 0; --openParenCount)
- {
- m_writer->emit(")");
- }
+ IntrinsicExpandContext context(this);
+ context.emit(inst, args, argCount, name);
}
}