From ce7b8319d0532a96ef66ba06d1d184a6c61b65cc Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Wed, 22 Jan 2020 16:05:45 -0500 Subject: 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. --- source/slang/slang-emit-c-like.cpp | 8 +- source/slang/slang-emit-c-like.h | 1 + source/slang/slang-emit-cpp.cpp | 163 ++++++++++++++++++++---------- source/slang/slang-emit-cpp.h | 7 +- source/slang/slang-emit-cuda.cpp | 7 ++ source/slang/slang-hlsl-intrinsic-set.cpp | 50 ++++++++- source/slang/slang-hlsl-intrinsic-set.h | 8 +- 7 files changed, 180 insertions(+), 64 deletions(-) (limited to 'source') 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(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(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(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& actions); void _calcGlobalParams(const List& actions, List& outParams, IRGlobalParam** outEntryPointGlobalParams); void _emitUniformStateMembers(const List& 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(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(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(targetType)) + { + targetType = as(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(paramType->getOperand(0)); + } + // If any are vec or matrix, then we if (paramType->op == kIROp_MatrixType || paramType->op == kIROp_VectorType) { -- cgit v1.2.3