summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2020-01-22 16:05:45 -0500
committerGitHub <noreply@github.com>2020-01-22 16:05:45 -0500
commitce7b8319d0532a96ef66ba06d1d184a6c61b65cc (patch)
tree05938b6ec95e44fee542713638c694d6b87a05cb /source
parentc74a700681b0be44a74f16b0f9eaad05bba159d2 (diff)
Matrix indexing (#1172)
* Added hlsl-intrinsic test folder. Enabled ceil as works across targets. * log10 support. * Fix float % on CPU/CUDA to match HLSL which is fmod (not fremainder). * Added log10 tests back to scalar-float.slang * Don't add the ( for $Sx - it's clearer what's going on without it. * Works on CUDA/CPU. Problem with asint/asuint do not seem to be found. * Only asuint exists for double. * Support countbits on CUDA and C++. * Fix typo in C++ population count. * First pass at int vector intrinsic tests. * Swizzle for int. * Bit cast tests on CUDA. * Fix warning on gcc. * Fix bit-cast-double execution on CUDA. * scalar-int test working on gcc release. * GetAt working on CUDA/C++ * Split out runtime index into it's own test. * Removed SetAt, as can use assignment with GetAt. * Allowing getAt to be used on matrices. * Don't need [] on matrix type any longer because use getAt. * Enable clamp on matrix-int. * Fix matrix-int.slang test - because clamp behavior varied if min and max were say inverted. Added runtime indexing version of matrix-int.
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-emit-c-like.cpp8
-rw-r--r--source/slang/slang-emit-c-like.h1
-rw-r--r--source/slang/slang-emit-cpp.cpp163
-rw-r--r--source/slang/slang-emit-cpp.h7
-rw-r--r--source/slang/slang-emit-cuda.cpp7
-rw-r--r--source/slang/slang-hlsl-intrinsic-set.cpp50
-rw-r--r--source/slang/slang-hlsl-intrinsic-set.h8
7 files changed, 180 insertions, 64 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index ae6becf0f..10790567e 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -1114,7 +1114,13 @@ IRTargetIntrinsicDecoration* CLikeSourceEmitter::findTargetIntrinsicDecoration(I
return true;
}
-void CLikeSourceEmitter::emitIntrinsicCallExpr(
+
+void CLikeSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec)
+{
+ emitIntrinsicCallExprImpl(inst, targetIntrinsic, inOuterPrec);
+}
+
+void CLikeSourceEmitter::emitIntrinsicCallExprImpl(
IRCall* inst,
IRTargetIntrinsicDecoration* targetIntrinsic,
EmitOpInfo const& inOuterPrec)
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index a6c48dc73..611678865 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -327,6 +327,7 @@ public:
virtual void emitSimpleFuncImpl(IRFunc* func);
virtual void emitOperandImpl(IRInst* inst, EmitOpInfo const& outerPrec);
virtual void emitParamTypeImpl(IRType* type, String const& name);
+ virtual void emitIntrinsicCallExprImpl(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec);
// Only needed for glsl output with $ prefix intrinsics - so perhaps removable in the future
virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) { SLANG_UNUSED(type); SLANG_UNUSED(baseName); }
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index 5dd028182..5ea3c72a2 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -544,6 +544,14 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S
void CPPSourceEmitter::useType(IRType* type)
{
+ if (type->op == kIROp_PtrType)
+ {
+ // TODO(JS):
+ // If it's a pointer type we ignore. We may want to strip but in practice it's
+ // probably not necessary.
+ return;
+ }
+
_getTypeName(type);
}
@@ -969,33 +977,52 @@ void CPPSourceEmitter::_emitGetAtDefinition(const UnownedStringSlice& funcName,
IRType* srcType = funcType->getParamType(0);
- emitSpecializedOperationDefinitionPreamble(specOp);
+ for (Index i = 0; i < 2; ++i)
+ {
+ UnownedStringSlice typePrefix = (i == 0) ? UnownedStringSlice::fromLiteral("const ") : UnownedStringSlice();
- IRType* retType = specOp->returnType;
- emitType(retType);
- m_writer->emit("& ");
+ emitSpecializedOperationDefinitionPreamble(specOp);
- writer->emit(funcName);
- writer->emit("(");
+ writer->emit(typePrefix);
+ emitType(specOp->returnType);
+ m_writer->emit("& ");
- emitType(funcType->getParamType(0));
- writer->emit("& a, ");
- emitType(funcType->getParamType(1));
- writer->emit(" b)\n{\n");
+ writer->emit(funcName);
+ writer->emit("(");
- writer->indent();
+ writer->emit(typePrefix);
+ emitType(funcType->getParamType(0));
+ writer->emit("& a, ");
+ emitType(funcType->getParamType(1));
+ writer->emit(" b)\n{\n");
- IRVectorType* vectorType = as<IRVectorType>(srcType);
- int vecSize = int(GetIntVal(vectorType->getElementCount()));
+ writer->indent();
- writer->emit("assert(b >= 0 && b < ");
- writer->emit(vecSize);
- writer->emit(");\n");
+ if (auto vectorType = as<IRVectorType>(srcType))
+ {
+ int vecSize = int(GetIntVal(vectorType->getElementCount()));
- writer->emit("return (&a.x)[b];\n");
+ writer->emit("assert(b >= 0 && b < ");
+ writer->emit(vecSize);
+ writer->emit(");\n");
- writer->dedent();
- writer->emit("}\n\n");
+ writer->emit("return (&a.x)[b];\n");
+ }
+ else if (auto matrixType = as<IRMatrixType>(srcType))
+ {
+ //int colCount = int(GetIntVal(matrixType->getColumnCount()));
+ int rowCount = int(GetIntVal(matrixType->getRowCount()));
+
+ writer->emit("assert(b >= 0 && b < ");
+ writer->emit(rowCount);
+ writer->emit(");\n");
+
+ writer->emit("return a.rows[b];\n");
+ }
+
+ writer->dedent();
+ writer->emit("}\n\n");
+ }
}
void CPPSourceEmitter::_emitNormalizeDefinition(const UnownedStringSlice& funcName, const HLSLIntrinsic* specOp)
@@ -1549,11 +1576,6 @@ SlangResult CPPSourceEmitter::calcFuncName(const HLSLIntrinsic* specOp, StringBu
outBuilder << "getAt";
return SLANG_OK;
}
- case Op::SetAt:
- {
- outBuilder << "setAt";
- return SLANG_OK;
- }
default: break;
}
@@ -1810,7 +1832,7 @@ void CPPSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc)
}
}
-void CPPSourceEmitter::emitIntrinsicCallExpr(
+void CPPSourceEmitter::emitIntrinsicCallExprImpl(
IRCall* inst,
IRTargetIntrinsicDecoration* targetIntrinsic,
EmitOpInfo const& inOuterPrec)
@@ -1826,13 +1848,9 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(
auto outerPrec = inOuterPrec;
bool needClose = false;
- // For a call with N arguments, the instruction will
- // have N+1 operands. We will start consuming operands
- // starting at the index 1.
- UInt operandCount = inst->getOperandCount();
- UInt operandIndex = 1;
-
-
+ Index argCount = Index(inst->getArgCount());
+ auto args = inst->getArgs();
+
auto name = targetIntrinsic->getDefinition();
// We will special-case some names here, that
@@ -1841,23 +1859,56 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(
// syntax.
if (name == ".operator[]")
{
- // The user is invoking a built-in subscript operator
+ SLANG_ASSERT(argCount == 2 || argCount == 3);
+
+ // If the first item is either a matrix or a vector, we use 'getAt' logic
+ IRType* targetType = args[0].get()->getDataType();
+ if (targetType->op == kIROp_VectorType || targetType->op == kIROp_MatrixType)
+ {
+ // Work out the intrinsic used
+ HLSLIntrinsic intrinsic;
+ m_intrinsicSet.calcIntrinsic(HLSLIntrinsic::Op::GetAt, inst->getDataType(), args, 2, intrinsic);
+ HLSLIntrinsic* specOp = m_intrinsicSet.add(intrinsic);
+
+ if (argCount == 2)
+ {
+ // Load
+ emitCall(specOp, inst, args, 2, inOuterPrec);
+ }
+ else
+ {
+ // Store
+ auto prec = getInfo(EmitOp::Postfix);
+ needClose = maybeEmitParens(outerPrec, prec);
- auto prec = getInfo(EmitOp::Postfix);
- needClose = maybeEmitParens(outerPrec, prec);
+ emitCall(specOp, inst, inst->getOperands(), 2, inOuterPrec);
- emitOperand(inst->getOperand(operandIndex++), leftSide(outerPrec, prec));
- m_writer->emit("[");
- emitOperand(inst->getOperand(operandIndex++), getInfo(EmitOp::General));
- m_writer->emit("]");
+ m_writer->emit(" = ");
+ emitOperand(inst->getOperand(2), getInfo(EmitOp::General));
- if (operandIndex < operandCount)
+ maybeCloseParens(needClose);
+ }
+ }
+ else
{
- m_writer->emit(" = ");
- emitOperand(inst->getOperand(operandIndex++), getInfo(EmitOp::General));
+ // The user is invoking a built-in subscript operator
+ auto prec = getInfo(EmitOp::Postfix);
+ needClose = maybeEmitParens(outerPrec, prec);
+
+ emitOperand(args[0].get(), leftSide(outerPrec, prec));
+ m_writer->emit("[");
+ emitOperand(args[1].get(), getInfo(EmitOp::General));
+ m_writer->emit("]");
+
+ if (argCount == 3)
+ {
+ m_writer->emit(" = ");
+ emitOperand(args[2].get(), getInfo(EmitOp::General));
+ }
+
+ maybeCloseParens(needClose);
}
- maybeCloseParens(needClose);
return;
}
@@ -1867,37 +1918,39 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(
if (name[0] == '.')
{
// Looks like a member function call
- emitOperand(inst->getOperand(operandIndex), leftSide(outerPrec, prec));
+ emitOperand(args[0].get(), leftSide(outerPrec, prec));
m_writer->emit(".");
- name = UnownedStringSlice(name.begin()+1, name.end());
- operandIndex++;
+ name = UnownedStringSlice(name.begin() + 1, name.end());
+
+ args++;
+ argCount--;
}
else
{
Op op = m_opLookup->getOpByName(name);
if (op != Op::Invalid)
{
- IRUse* operands = inst->getOperands() + operandIndex;
-
+
// Work out the intrinsic used
HLSLIntrinsic intrinsic;
- m_intrinsicSet.calcIntrinsic(op, inst->getDataType(), operands, int(operandCount - operandIndex), intrinsic);
+ m_intrinsicSet.calcIntrinsic(op, inst->getDataType(), args, argCount, intrinsic);
HLSLIntrinsic* specOp = m_intrinsicSet.add(intrinsic);
- emitCall(specOp, inst, operands, int(operandCount - operandIndex), inOuterPrec);
+ emitCall(specOp, inst, args, int(argCount), inOuterPrec);
return;
}
}
m_writer->emit(name);
m_writer->emit("(");
- bool first = true;
- for (; operandIndex < operandCount; ++operandIndex)
+ for (Index i = 0; i < argCount; ++i)
{
- if (!first) m_writer->emit(", ");
- emitOperand(inst->getOperand(operandIndex), getInfo(EmitOp::General));
- first = false;
+ if (i != 0)
+ {
+ m_writer->emit(", ");
+ }
+ emitOperand(args[i].get(), getInfo(EmitOp::General));
}
m_writer->emit(")");
maybeCloseParens(needClose);
diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h
index 12bc0939e..9ea083199 100644
--- a/source/slang/slang-emit-cpp.h
+++ b/source/slang/slang-emit-cpp.h
@@ -77,6 +77,8 @@ protected:
virtual void emitParamTypeImpl(IRType* type, String const& name) SLANG_OVERRIDE;
virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) SLANG_OVERRIDE;
+ virtual void emitIntrinsicCallExprImpl(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec) SLANG_OVERRIDE;
+
// Replaceable for classes derived from CPPSourceEmitter
virtual SlangResult calcTypeName(IRType* type, CodeGenTarget target, StringBuilder& out);
@@ -87,11 +89,6 @@ protected:
void _maybeEmitSpecializedOperationDefinition(const HLSLIntrinsic* specOp);
- void emitIntrinsicCallExpr(
- IRCall* inst,
- IRTargetIntrinsicDecoration* targetIntrinsic,
- EmitOpInfo const& inOuterPrec);
-
void _emitForwardDeclarations(const List<EmitAction>& actions);
void _calcGlobalParams(const List<EmitAction>& actions, List<GlobalParamInfo>& outParams, IRGlobalParam** outEntryPointGlobalParams);
void _emitUniformStateMembers(const List<EmitAction>& actions, IRGlobalParam** outEntryPointGlobalParams);
diff --git a/source/slang/slang-emit-cuda.cpp b/source/slang/slang-emit-cuda.cpp
index c72b9125a..93508813b 100644
--- a/source/slang/slang-emit-cuda.cpp
+++ b/source/slang/slang-emit-cuda.cpp
@@ -219,6 +219,13 @@ SlangResult CUDASourceEmitter::calcScalarFuncName(HLSLIntrinsic::Op op, IRBasicT
SlangResult CUDASourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, StringBuilder& out)
{
SLANG_UNUSED(target);
+
+ if (target == CodeGenTarget::CSource)
+ {
+ return Super::calcTypeName(type, target, out);
+ }
+
+ // We allow C source, because if we need a name
SLANG_ASSERT(target == CodeGenTarget::CUDASource);
switch (type->op)
diff --git a/source/slang/slang-hlsl-intrinsic-set.cpp b/source/slang/slang-hlsl-intrinsic-set.cpp
index 9bc7e7d54..1f42836f3 100644
--- a/source/slang/slang-hlsl-intrinsic-set.cpp
+++ b/source/slang/slang-hlsl-intrinsic-set.cpp
@@ -55,6 +55,35 @@ void HLSLIntrinsicSet::_calcIntrinsic(HLSLIntrinsic::Op op, IRType* returnType,
switch (op)
{
+ case Op::GetAt:
+ {
+ IRType* argTypes[3];
+
+ SLANG_ASSERT(argsCount == 2 || argsCount == 3);
+ // TODO(JS):
+ // HACK! GetAt can be from getElementPtr or from getElement. Get element ptr means the return type will be
+ // a pointer. We don't want to deal with that, so strip it
+ if (returnType->op == kIROp_PtrType)
+ {
+ returnType = as<IRType>(returnType->getOperand(0));
+ }
+
+ // TODO(JS): Similarly for the input parameters
+ for (Index i = 0; i < argsCount; ++i)
+ {
+ IRType* argType = inArgs[i];
+
+ if (argType->op == kIROp_PtrType)
+ {
+ argType = as<IRType>(argType->getOperand(0));
+ }
+ argTypes[i] = argType;
+ }
+
+ out.returnType = returnType;
+ out.signatureType = builder.getFuncType(argsCount, argTypes, builder.getVoidType());
+ break;
+ }
case Op::ConstructFromScalar:
{
//SLANG_ASSERT(argsCount == 1);
@@ -269,10 +298,10 @@ SlangResult HLSLIntrinsicSet::makeIntrinsic(IRInst* inst, HLSLIntrinsic& out)
break;
}
case kIROp_getElement:
- case kIROp_getElementPtr:
{
IRInst* target = inst->getOperand(0);
- if (target->getDataType()->op == kIROp_VectorType)
+ IRType* targetType = target->getDataType();
+ if (targetType->op == kIROp_VectorType || targetType->op == kIROp_MatrixType)
{
// Specially handle this
calcIntrinsic(Op::GetAt, inst, out);
@@ -280,6 +309,23 @@ SlangResult HLSLIntrinsicSet::makeIntrinsic(IRInst* inst, HLSLIntrinsic& out)
}
break;
}
+ case kIROp_getElementPtr:
+ {
+ IRInst* target = inst->getOperand(0);
+ IRType* targetType = target->getDataType();
+
+ if (auto ptrType = as<IRPtrType>(targetType))
+ {
+ targetType = as<IRType>(ptrType->getOperand(0));
+ if (targetType->op == kIROp_VectorType || targetType->op == kIROp_MatrixType)
+ {
+ // Specially handle this
+ calcIntrinsic(Op::GetAt, inst, out);
+ return SLANG_OK;
+ }
+ }
+ break;
+ }
case kIROp_Call:
{
IRCall* callInst = (IRCall*)inst;
diff --git a/source/slang/slang-hlsl-intrinsic-set.h b/source/slang/slang-hlsl-intrinsic-set.h
index df1677b17..17e88fc9a 100644
--- a/source/slang/slang-hlsl-intrinsic-set.h
+++ b/source/slang/slang-hlsl-intrinsic-set.h
@@ -123,7 +123,6 @@ just constructXXXFromScalar. Would be good if there was a suitable name to encom
x(ConstructFromScalar, "", 1) \
\
x(GetAt, "", 2) \
- x(SetAt, "", 3) \
\
x(CountBits, "countbits", 1)
@@ -153,6 +152,13 @@ struct HLSLIntrinsic
for (Index i = 0; i < paramCount; ++i)
{
IRType* paramType = signatureType->getParamType(i);
+
+ // Strip off ptr if it's an operand type
+ if (paramType->op == kIROp_PtrType)
+ {
+ paramType = as<IRType>(paramType->getOperand(0));
+ }
+
// If any are vec or matrix, then we
if (paramType->op == kIROp_MatrixType || paramType->op == kIROp_VectorType)
{