summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-cpp.h
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-07-09 13:59:30 -0400
committerGitHub <noreply@github.com>2019-07-09 13:59:30 -0400
commitf52f5cd4a7b5b71617b949fc62a78abe8c4822b3 (patch)
tree48f636f33e199b3508d779941c034f7be91debc4 /source/slang/slang-emit-cpp.h
parent691ebae763e29327249735d67fbb231c75b17840 (diff)
WIP: slang to C++ code generation (#997)
* WIP: Emitting Cpp * Added HLSLType instead of using IRInst - because they don't seem to be deduped. * Removed need for lexer to take a String. Added mechansim to lookup intrinsic functions on C++. * A c/c++ cross compilation test. * WIP Cpp output using cloning and slang types. * More work to generate mul funcs. * WIP: Outputting some simple C++. * Expose findOrEmitHoistableInst to IRBuilder to aid cloning, * Simplification for checking for BasicTypes. Test infrastructure compiles output C++ code. * Dot and mat/vec multiplication output. * First pass at swizzling. * First support for binary ops. * Builtin binary and unary functions. * Any and all. * WIP adding support for other functions. Added code to generate function signature. * Add scalar functions to slang-cpp-prelude.h * Support for most built in operations. * Tested first ternary. * Checking the emitting of corner cases functions - normalize, length, any, all, normalize, reflect. * Check asfloat etc work. * Fmod support. * WIP Array handling in C++. * First stage in being able to handl arbitrary type output for CLikeSourceEmitter * Removed Handler/Emitter split - so can implement more easily complex type naming. * Array passing by value first pass. * Rename Array -> FixedArray * Outputs structs in C++. * Emit the thread config. * Dimension -> TypeDimension * SpecializedOperation -> SpecializedIntrinsic Operation -> IntrinsicOp Use shared impl of isNominalOp Commented use of m_uniqueModule etc. * Add code to test slang->cpp when compiled doesn't have errors. Does so by building shared library and exporting the entry point. * Fix linux clang/gcc compile error about override not being specified. * Make sure c-cross-compile is run on linux targets/smoke. * Remove c-cross-compile.slang from smoke. * Fix running tests/cross-compile/c-cross-compile.slang on Ubuntu 16.04 * Only add -std=c++11 for C++ source.
Diffstat (limited to 'source/slang/slang-emit-cpp.h')
-rw-r--r--source/slang/slang-emit-cpp.h238
1 files changed, 227 insertions, 11 deletions
diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h
index d5d95507c..cd33dc431 100644
--- a/source/slang/slang-emit-cpp.h
+++ b/source/slang/slang-emit-cpp.h
@@ -3,37 +3,253 @@
#define SLANG_EMIT_CPP_H
#include "slang-emit-c-like.h"
+#include "slang-ir-clone.h"
+
+#include "../core/slang-string-slice-pool.h"
namespace Slang
{
+#define SLANG_CPP_INTRINSIC_OP(x) \
+ x(Invalid, "", -1) \
+ x(Init, "", -1) \
+ \
+ x(Mul, "*", 2) \
+ x(Div, "/", 2) \
+ x(Add, "+", 2) \
+ x(Sub, "-", 2) \
+ x(Lsh, "<<", 2) \
+ x(Rsh, ">>", 2) \
+ x(Mod, "%", 2) \
+ \
+ x(Eql, "==", 2) \
+ x(Neq, "!=", 2) \
+ x(Greater, ">", 2) \
+ x(Less, "<", 2) \
+ x(Geq, ">=", 2) \
+ x(Leq, "<=", 2) \
+ \
+ x(BitAnd, "&", 2) \
+ x(BitXor, "^", 2) \
+ x(BitOr, "|" , 2) \
+ \
+ x(And, "&&", 2) \
+ x(Or, "||", 2) \
+ \
+ x(Neg, "-", 1) \
+ x(Not, "!", 1) \
+ x(BitNot, "~", 1) \
+ \
+ x(Any, "any", 1) \
+ x(All, "all", 1) \
+ \
+ x(Swizzle, "", -1) \
+ \
+ x(Dot, "dot", 2) \
+ x(VecMatMul, "mul", 2) \
+ \
+ x(Normalize, "normalize", 1) \
+ x(Length, "length", 1) \
+ \
+ x(Sin, "sin", 1) \
+ x(Cos, "cos", 1) \
+ x(Tan, "tan", 1) \
+ \
+ x(ArcSin, "asin", 1) \
+ x(ArcCos, "acos", 1) \
+ x(ArcTan, "atan", 1) \
+ \
+ x(ArcTan2, "atan2", 2) \
+ x(SinCos, "sincos", 3) \
+ \
+ x(Rcp, "rcp", 1) \
+ x(Sign, "sign", 1) \
+ x(Saturate, "saturate", 1) \
+ x(Frac, "frac", 1) \
+ \
+ x(Ceil, "ceil", 1) \
+ x(Floor, "floor", 1) \
+ x(Trunc, "trunc", 1) \
+ \
+ x(Sqrt, "sqrt", 1) \
+ x(RecipSqrt, "rsqrt", 1) \
+ \
+ x(Exp2, "exp2", 1) \
+ x(Exp, "exp", 1) \
+ \
+ x(Abs, "abs", 1) \
+ \
+ x(Min, "min", 2) \
+ x(Max, "max", 2) \
+ x(Pow, "pow", 2) \
+ x(FMod, "fmod", 2) \
+ x(Cross, "cross", 2) \
+ x(Reflect, "reflect", 2) \
+ \
+ x(SmoothStep, "smoothstep", 3) \
+ x(Lerp, "lerp", 3) \
+ x(Clamp, "clamp", 3) \
+ x(Step, "step", 2) \
+ \
+ x(AsFloat, "asfloat", 1) \
+ x(AsInt, "asint", 1) \
+ x(AsUInt, "asuint", 1)
+
+
class CPPSourceEmitter: public CLikeSourceEmitter
{
public:
typedef CLikeSourceEmitter Super;
- enum class BuiltInCOp
+#define SLANG_CPP_INTRINSIC_OP_ENUM(x, op, numOperands) x,
+ enum class IntrinsicOp
{
- Splat, //< Splat a single value to all values of a vector or matrix type
- Init, //< Initialize with parameters (must match the type)
+ SLANG_CPP_INTRINSIC_OP(SLANG_CPP_INTRINSIC_OP_ENUM)
};
- CPPSourceEmitter(const Desc& desc) :
- Super(desc)
- {}
+ struct OperationInfo
+ {
+ UnownedStringSlice name;
+ UnownedStringSlice funcName;
+ int8_t numOperands; ///< -1 if can't be handled automatically via amount of params
+ };
-protected:
+ struct SpecializedIntrinsic
+ {
+ typedef SpecializedIntrinsic ThisType;
- void _emitCVecType(IROp op, Int size);
- void _emitCMatType(IROp op, IRIntegerValue rowCount, IRIntegerValue colCount);
- void _emitCFunc(BuiltInCOp cop, IRType* type);
+ UInt GetHashCode() const { return combineHash(int(op), Slang::GetHashCode(signatureType)); }
+
+ bool operator==(const ThisType& rhs) const { return op == rhs.op && returnType == rhs.returnType && signatureType == rhs.signatureType; }
+ bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
+
+ bool isScalar() const
+ {
+ int paramCount = int(signatureType->getParamCount());
+ for (int i = 0; i < paramCount; ++i)
+ {
+ IRType* paramType = signatureType->getParamType(i);
+ // If any are vec or matrix, then we
+ if (paramType->op == kIROp_MatrixType || paramType->op == kIROp_VectorType)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ IntrinsicOp op;
+ IRType* returnType;
+ IRFuncType* signatureType; // Same as funcType, but has return type of void
+ };
+
+ struct TypeDimension
+ {
+ bool isScalar() const { return rowCount <= 1 && colCount <= 1; }
+
+ int rowCount;
+ int colCount;
+ };
+
+ virtual SpecializedIntrinsic getSpecializedOperation(IntrinsicOp op, IRType*const* argTypes, int argTypesCount, IRType* retType);
+ virtual void useType(IRType* type);
+ virtual void emitCall(const SpecializedIntrinsic& specOp, IRInst* inst, const IRUse* operands, int numOperands, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec);
+ virtual void emitTypeDefinition(IRType* type);
+ virtual void emitSpecializedOperationDefinition(const SpecializedIntrinsic& specOp);
+
+ void emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* operands, int operandCount, IRType* retType, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec);
+
+ static UnownedStringSlice getBuiltinTypeName(IROp op);
+
+ static const OperationInfo& getOperationInfo(IntrinsicOp op);
+
+ static IntrinsicOp getOperation(IROp op);
+
+ IntrinsicOp getOperationByName(const UnownedStringSlice& slice);
+
+ SourceWriter* getSourceWriter() const { return m_writer; }
+
+ CPPSourceEmitter(const Desc& desc);
+
+protected:
+ // Implement CLikeSourceEmitter interface
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE;
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, EntryPointLayout* entryPointLayout) SLANG_OVERRIDE;
virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE;
+ virtual void emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc) SLANG_OVERRIDE;
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE;
-
virtual bool tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE;
+ virtual void emitPreprocessorDirectivesImpl() SLANG_OVERRIDE;
+
+ void emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitMode mode, EmitOpInfo const& inOuterPrec);
+
+ void _emitVecMatMulDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+
+ void _emitAryDefinition(const SpecializedIntrinsic& specOp);
+
+ // Really we don't want any of these defined like they are here, they should be defined in slang stdlib
+ void _emitAnyAllDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+ void _emitCrossDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+ void _emitLengthDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+ void _emitNormalizeDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+ void _emitReflectDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+
+ void _emitSignature(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
+
+ UnownedStringSlice _getAndEmitSpecializedOperationDefinition(IntrinsicOp op, IRType*const* argTypes, Int argCount, IRType* retType);
+
+ static TypeDimension _getTypeDimension(IRType* type, bool vecSwap);
+ static void _emitAccess(const UnownedStringSlice& name, const TypeDimension& dimension, int row, int col, SourceWriter* writer);
+
+ IRType* _getVecType(IRType* elementType, int elementCount);
+
+ IRInst* _clone(IRInst* inst);
+ IRType* _cloneType(IRType* type) { return (IRType*)_clone((IRInst*)type); }
+
+ StringSlicePool::Handle _calcScalarFuncName(IntrinsicOp op, IRBasicType* type);
+ UnownedStringSlice _getScalarFuncName(IntrinsicOp operation, IRBasicType* scalarType);
+
+ UnownedStringSlice _getFuncName(const SpecializedIntrinsic& specOp);
+ StringSlicePool::Handle _calcFuncName(const SpecializedIntrinsic& specOp);
+
+ UnownedStringSlice _getTypeName(IRType* type);
+ StringSlicePool::Handle _calcTypeName(IRType* type);
+
+ Dictionary<SpecializedIntrinsic, StringSlicePool::Handle> m_intrinsicNameMap;
+ Dictionary<IRType*, StringSlicePool::Handle> m_typeNameMap;
+
+ /* This is used so as to try and use slangs type system to uniquely identify types and specializations on intrinsice.
+ That we want to have a pointer to a type be unique, and slang supports this through the m_sharedIRBuilder. BUT for this to
+ work all work on the module must use the same sharedIRBuilder, and that appears to not be the case in terms
+ of other passes.
+ Even if it was the case when we may want to add types as part of emitting, we can't use the previously used
+ shared builder, so again we end up with pointers to the same things not being the same thing.
+
+ To work around this we clone types we want to use as keys into the 'unique module'.
+ This is not necessary for all types though - as we assume nominal types *must* have unique pointers (that is the
+ definition of nominal).
+
+ This could be handled in other ways (for example not testing equality on pointer equality). Anyway for now this
+ works, but probably needs to be handled in a better way. The better way may involve having guarantees about equality
+ enabled in other code generation and making de-duping possible in emit code.
+
+ Note that one pro for this approach is that it does not alter the source module. That as it stands it's not necessary
+ for the source module to be immutable, because it is created for emitting and then discarded.
+ */
+ RefPtr<IRModule> m_uniqueModule;
+ SharedIRBuilder m_sharedIRBuilder;
+ IRBuilder m_irBuilder;
+
+ Dictionary<IRInst*, IRInst*> m_cloneMap;
+
+ Dictionary<IRType*, bool> m_typeEmittedMap;
+ Dictionary<SpecializedIntrinsic, bool> m_intrinsicEmittedMap;
+
+ // Maps from a name (in the form of a handle/index from m_slicePool) to an operation
+ List<IntrinsicOp> m_intrinsicOpMap;
+
+ StringSlicePool m_slicePool;
};
}