diff options
Diffstat (limited to 'source/slang/emit.cpp')
| -rw-r--r-- | source/slang/emit.cpp | 1538 |
1 files changed, 704 insertions, 834 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 15f295740..28fb0b551 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -282,7 +282,6 @@ static EOpInfo const* const kInfixOpInfos[] = &kEOp_Mod, }; - // // represents a declarator for use in emitting types @@ -302,16 +301,10 @@ struct EDeclarator SourceLoc loc; // Used for `Flavor::Array` - IntVal* elementCount; -}; - -struct TypeEmitArg -{ - EDeclarator* declarator; + IRInst* elementCount; }; struct EmitVisitor - : TypeVisitorWithArg<EmitVisitor, TypeEmitArg> { EmitContext* context; EmitVisitor(EmitContext* context) @@ -466,23 +459,6 @@ struct EmitVisitor emitName(name, SourceLoc()); } - void emitName( - Decl* decl, - SourceLoc const& loc) - { - if(auto name = decl->getName()) - emitName(name, loc); - - Emit("_S"); - Emit(getID(decl)); - } - - void emitName( - Decl* decl) - { - emitName(decl, SourceLoc()); - } - void Emit(IntegerLiteralValue value) { char buffer[32]; @@ -752,22 +728,6 @@ struct EmitVisitor // Types // - void Emit(RefPtr<IntVal> val) - { - if(auto constantIntVal = val.As<ConstantIntVal>()) - { - Emit(constantIntVal->value); - } - else if(auto varRefVal = val.As<GenericParamIntVal>()) - { - EmitDeclRef(varRefVal->declRef); - } - else - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unknown type of integer constant value"); - } - } - void EmitDeclarator(EDeclarator* declarator) { if (!declarator) return; @@ -785,7 +745,7 @@ struct EmitVisitor Emit("["); if(auto elementCount = declarator->elementCount) { - Emit(elementCount); + EmitVal(elementCount); } Emit("]"); break; @@ -802,41 +762,35 @@ struct EmitVisitor } void emitGLSLTypePrefix( - RefPtr<Type> type) + IRType* type) { - if(auto basicElementType = type->As<BasicExpressionType>()) + switch (type->op) { - switch (basicElementType->baseType) - { - case BaseType::Float: - // no prefix - break; + case kIROp_FloatType: + // no prefix + break; - case BaseType::Int: Emit("i"); break; - case BaseType::UInt: Emit("u"); break; - case BaseType::Bool: Emit("b"); break; - case BaseType::Double: Emit("d"); break; - default: - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled GLSL type prefix"); - break; - } - } - else if(auto vectorType = type->As<VectorExpressionType>()) - { - emitGLSLTypePrefix(vectorType->elementType); - } - else if(auto matrixType = type->As<MatrixExpressionType>()) - { - emitGLSLTypePrefix(matrixType->getElementType()); - } - else - { + case kIROp_IntType: Emit("i"); break; + case kIROp_UIntType: Emit("u"); break; + case kIROp_BoolType: Emit("b"); break; + case kIROp_DoubleType: Emit("d"); break; + + case kIROp_VectorType: + emitGLSLTypePrefix(cast<IRVectorType>(type)->getElementType()); + break; + + case kIROp_MatrixType: + emitGLSLTypePrefix(cast<IRMatrixType>(type)->getElementType()); + break; + + default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled GLSL type prefix"); + break; } } void emitHLSLTextureType( - RefPtr<TextureTypeBase> texType) + IRTextureTypeBase* texType) { switch(texType->getAccess()) { @@ -885,15 +839,15 @@ struct EmitVisitor Emit("Array"); } Emit("<"); - EmitType(texType->elementType); + EmitType(texType->getElementType()); Emit(" >"); } void emitGLSLTextureOrTextureSamplerType( - RefPtr<TextureTypeBase> type, - char const* baseName) + IRTextureTypeBase* type, + char const* baseName) { - emitGLSLTypePrefix(type->elementType); + emitGLSLTypePrefix(type->getElementType()); Emit(baseName); switch (type->GetBaseShape()) @@ -919,7 +873,7 @@ struct EmitVisitor } void emitGLSLTextureType( - RefPtr<TextureType> texType) + IRTextureType* texType) { switch(texType->getAccess()) { @@ -935,19 +889,19 @@ struct EmitVisitor } void emitGLSLTextureSamplerType( - RefPtr<TextureSamplerType> type) + IRTextureSamplerType* type) { emitGLSLTextureOrTextureSamplerType(type, "sampler"); } void emitGLSLImageType( - RefPtr<GLSLImageType> type) + IRGLSLImageType* type) { emitGLSLTextureOrTextureSamplerType(type, "image"); } void emitTextureType( - RefPtr<TextureType> texType) + IRTextureType* texType) { switch(context->shared->target) { @@ -966,7 +920,7 @@ struct EmitVisitor } void emitTextureSamplerType( - RefPtr<TextureSamplerType> type) + IRTextureSamplerType* type) { switch(context->shared->target) { @@ -981,7 +935,7 @@ struct EmitVisitor } void emitImageType( - RefPtr<GLSLImageType> type) + IRGLSLImageType* type) { switch(context->shared->target) { @@ -999,79 +953,27 @@ struct EmitVisitor } } - void emitTypeImpl(RefPtr<Type> type, EDeclarator* declarator) - { - TypeEmitArg arg; - arg.declarator = declarator; - - TypeVisitorWithArg::dispatch(type, arg); - } - -#define UNEXPECTED(NAME) \ - void visit##NAME(NAME*, TypeEmitArg const& arg) \ - { Emit(#NAME); EmitDeclarator(arg.declarator); } - - UNEXPECTED(ErrorType); - UNEXPECTED(OverloadGroupType); - UNEXPECTED(FuncType); - UNEXPECTED(TypeType); - UNEXPECTED(GenericDeclRefType); - UNEXPECTED(InitializerListType); - - UNEXPECTED(IRBasicBlockType); - UNEXPECTED(PtrType); - -#undef UNEXPECTED - - void visitNamedExpressionType(NamedExpressionType* type, TypeEmitArg const& arg) - { - // We will always emit the actual type referenced by - // a named type declaration, rather than try to produce - // equivalent `typedef` declarations in the output. - - emitTypeImpl(GetType(type->declRef), arg.declarator); - } - - void visitBasicExpressionType(BasicExpressionType* basicType, TypeEmitArg const& arg) - { - auto declarator = arg.declarator; - switch (basicType->baseType) - { - case BaseType::Void: Emit("void"); break; - case BaseType::Int: Emit("int"); break; - case BaseType::Float: Emit("float"); break; - case BaseType::UInt: Emit("uint"); break; - case BaseType::Bool: Emit("bool"); break; - case BaseType::Double: Emit("double"); break; - default: - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled scalar type"); - break; - } - - EmitDeclarator(declarator); - } - void visitVectorExpressionType(VectorExpressionType* vecType, TypeEmitArg const& arg) + void emitVectorTypeImpl(IRVectorType* vecType) { - auto declarator = arg.declarator; switch(context->shared->target) { case CodeGenTarget::GLSL: case CodeGenTarget::GLSL_Vulkan: case CodeGenTarget::GLSL_Vulkan_OneDesc: { - emitGLSLTypePrefix(vecType->elementType); + emitGLSLTypePrefix(vecType->getElementType()); Emit("vec"); - Emit(vecType->elementCount); + EmitVal(vecType->getElementCount()); } break; case CodeGenTarget::HLSL: // TODO(tfoley): should really emit these with sugar Emit("vector<"); - EmitType(vecType->elementType); + EmitType(vecType->getElementType()); Emit(","); - Emit(vecType->elementCount); + EmitVal(vecType->getElementCount()); Emit(">"); break; @@ -1079,13 +981,10 @@ struct EmitVisitor SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled code generation target"); break; } - - EmitDeclarator(declarator); } - void visitMatrixExpressionType(MatrixExpressionType* matType, TypeEmitArg const& arg) + void emitMatrixTypeImpl(IRMatrixType* matType) { - auto declarator = arg.declarator; switch(context->shared->target) { case CodeGenTarget::GLSL: @@ -1094,11 +993,11 @@ struct EmitVisitor { emitGLSLTypePrefix(matType->getElementType()); Emit("mat"); - Emit(matType->getRowCount()); + EmitVal(matType->getRowCount()); // TODO(tfoley): only emit the next bit // for non-square matrix Emit("x"); - Emit(matType->getColumnCount()); + EmitVal(matType->getColumnCount()); } break; @@ -1107,9 +1006,9 @@ struct EmitVisitor Emit("matrix<"); EmitType(matType->getElementType()); Emit(","); - Emit(matType->getRowCount()); + EmitVal(matType->getRowCount()); Emit(","); - Emit(matType->getColumnCount()); + EmitVal(matType->getColumnCount()); Emit("> "); break; @@ -1117,42 +1016,18 @@ struct EmitVisitor SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled code generation target"); break; } - - EmitDeclarator(declarator); } - void visitTextureType(TextureType* texType, TypeEmitArg const& arg) + void emitSamplerStateType(IRSamplerStateTypeBase* samplerStateType) { - auto declarator = arg.declarator; - emitTextureType(texType); - EmitDeclarator(declarator); - } - - void visitTextureSamplerType(TextureSamplerType* textureSamplerType, TypeEmitArg const& arg) - { - auto declarator = arg.declarator; - emitTextureSamplerType(textureSamplerType); - EmitDeclarator(declarator); - } - - void visitGLSLImageType(GLSLImageType* imageType, TypeEmitArg const& arg) - { - auto declarator = arg.declarator; - emitImageType(imageType); - EmitDeclarator(declarator); - } - - void visitSamplerStateType(SamplerStateType* samplerStateType, TypeEmitArg const& arg) - { - auto declarator = arg.declarator; switch(context->shared->target) { case CodeGenTarget::HLSL: default: - switch (samplerStateType->flavor) + switch (samplerStateType->op) { - case SamplerStateFlavor::SamplerState: Emit("SamplerState"); break; - case SamplerStateFlavor::SamplerComparisonState: Emit("SamplerComparisonState"); break; + case kIROp_SamplerStateType: Emit("SamplerState"); break; + case kIROp_SamplerComparisonStateType: Emit("SamplerComparisonState"); break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled sampler state flavor"); break; @@ -1160,10 +1035,10 @@ struct EmitVisitor break; case CodeGenTarget::GLSL: - switch (samplerStateType->flavor) + switch (samplerStateType->op) { - case SamplerStateFlavor::SamplerState: Emit("sampler"); break; - case SamplerStateFlavor::SamplerComparisonState: Emit("samplerShadow"); break; + case kIROp_SamplerStateType: Emit("sampler"); break; + case kIROp_SamplerComparisonStateType: Emit("samplerShadow"); break; default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled sampler state flavor"); break; @@ -1171,69 +1046,217 @@ struct EmitVisitor break; break; } + } + + void emitStructuredBufferType(IRHLSLStructuredBufferTypeBase* type) + { + switch(context->shared->target) + { + case CodeGenTarget::HLSL: + default: + { + switch (type->op) + { + case kIROp_HLSLStructuredBufferType: Emit("StructuredBuffer"); break; + case kIROp_HLSLRWStructuredBufferType: Emit("RWStructuredBuffer"); break; + case kIROp_HLSLAppendStructuredBufferType: Emit("AppendStructuredBuffer"); break; + case kIROp_HLSLConsumeStructuredBufferType: Emit("ConsumeStructuredBuffer"); break; + + default: + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled structured buffer type"); + break; + } - EmitDeclarator(declarator); + Emit("<"); + EmitType(type->getElementType()); + Emit(" >"); + } + break; + + case CodeGenTarget::GLSL: + // TODO: We desugar global variables with structured-buffer type into GLSL + // `buffer` declarations, but we don't currently handle structured-buffer types + // in other contexts (e.g., as function parameters). The simplest thing to do + // would be to emit a `StructuredBuffer<Foo>` as `Foo[]` and `RWStructuredBuffer<Foo>` + // as `in out Foo[]`, but that is starting to get into the realm of transformations + // that should really be handled during legalization, rather than during emission. + // + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "structured buffer type used unexpectedly"); + break; + } } - void visitDeclRefType(DeclRefType* declRefType, TypeEmitArg const& arg) + void emitUntypedBufferType(IRUntypedBufferResourceType* type) { - auto declarator = arg.declarator; - EmitDeclRef(declRefType->declRef); - EmitDeclarator(declarator); + switch(context->shared->target) + { + case CodeGenTarget::HLSL: + default: + { + switch (type->op) + { + case kIROp_HLSLByteAddressBufferType: Emit("ByteAddressBuffer"); break; + case kIROp_HLSLRWByteAddressBufferType: Emit("RWByteAddressBuffer"); break; + case kIROp_RaytracingAccelerationStructureType: Emit("RaytracingAccelerationStructureType"); break; + + default: + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled buffer type"); + break; + } + } + break; + + case CodeGenTarget::GLSL: + { + switch (type->op) + { + case kIROp_HLSLByteAddressBufferType: Emit("ByteAddressBuffer"); break; + case kIROp_HLSLRWByteAddressBufferType: Emit("RWByteAddressBuffer"); break; + case kIROp_RaytracingAccelerationStructureType: Emit("RaytracingAccelerationStructureType"); break; + + default: + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled buffer type"); + break; + } + } + break; + } } - void visitArrayExpressionType(ArrayExpressionType* arrayType, TypeEmitArg const& arg) + void emitSimpleTypeImpl(IRType* type) { - auto declarator = arg.declarator; + switch (type->op) + { + default: + break; - EDeclarator arrayDeclarator; - arrayDeclarator.next = declarator; + case kIROp_VoidType: Emit("void"); return; + case kIROp_IntType: Emit("int"); return; + case kIROp_UIntType: Emit("uint"); return; + case kIROp_BoolType: Emit("bool"); return; + case kIROp_HalfType: Emit("half"); return; + case kIROp_FloatType: Emit("float"); return; + case kIROp_DoubleType: Emit("double"); return; + + case kIROp_VectorType: + emitVectorTypeImpl((IRVectorType*)type); + return; + + case kIROp_MatrixType: + emitMatrixTypeImpl((IRMatrixType*)type); + return; + + case kIROp_SamplerStateType: + case kIROp_SamplerComparisonStateType: + emitSamplerStateType(cast<IRSamplerStateTypeBase>(type)); + return; + + case kIROp_StructType: + emit(getIRName(type)); + return; + } + + // TODO: Ideally the following should be data-driven, + // based on meta-data attached to the definitions of + // each of these IR opcodes. - if(arrayType->ArrayLength) + if (auto texType = as<IRTextureType>(type)) { - arrayDeclarator.flavor = EDeclarator::Flavor::Array; - arrayDeclarator.elementCount = arrayType->ArrayLength.Ptr(); + emitTextureType(texType); + return; } - else + else if (auto textureSamplerType = as<IRTextureSamplerType>(type)) + { + emitTextureSamplerType(textureSamplerType); + return; + } + else if (auto imageType = as<IRGLSLImageType>(type)) { - arrayDeclarator.flavor = EDeclarator::Flavor::UnsizedArray; + emitImageType(imageType); + return; + } + else if (auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type)) + { + emitStructuredBufferType(structuredBufferType); + return; + } + else if(auto untypedBufferType = as<IRUntypedBufferResourceType>(type)) + { + emitUntypedBufferType(untypedBufferType); + return; } + // HACK: As a fallback for HLSL targets, assume that the name of the + // instruction being used is the same as the name of the HLSL type. + if(context->shared->target == CodeGenTarget::HLSL) + { + auto opInfo = getIROpInfo(type->op); + emit(opInfo.name); + UInt operandCount = type->getOperandCount(); + if(operandCount) + { + emit("<"); + for(UInt ii = 0; ii < operandCount; ++ii) + { + if(ii != 0) emit(", "); + EmitVal(type->getOperand(ii)); + } + emit(" >"); + } - emitTypeImpl(arrayType->baseType, &arrayDeclarator); + return; + } + + SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled type"); } - void visitRateQualifiedType(RateQualifiedType* type, TypeEmitArg const& arg) + void emitArrayTypeImpl(IRArrayType* arrayType, EDeclarator* declarator) { - emitTypeImpl(type->valueType, arg.declarator); + EDeclarator arrayDeclarator; + arrayDeclarator.flavor = EDeclarator::Flavor::Array; + arrayDeclarator.next = declarator; + arrayDeclarator.elementCount = arrayType->getElementCount(); + + emitTypeImpl(arrayType->getElementType(), &arrayDeclarator); } - void visitConstExprRate(ConstExprRate* /*rate*/, TypeEmitArg const& /*arg*/) + void emitUnsizedArrayTypeImpl(IRUnsizedArrayType* arrayType, EDeclarator* declarator) { - // This should never appear as a data type - SLANG_UNEXPECTED("Rates not expected during emit"); + EDeclarator arrayDeclarator; + arrayDeclarator.flavor = EDeclarator::Flavor::UnsizedArray; + arrayDeclarator.next = declarator; + + emitTypeImpl(arrayType->getElementType(), &arrayDeclarator); } - void visitGroupSharedType(GroupSharedType* type, TypeEmitArg const& arg) + void emitTypeImpl(IRType* type, EDeclarator* declarator) { - switch(getTarget(context)) + switch (type->op) { - case CodeGenTarget::HLSL: - Emit("groupshared "); + default: + emitSimpleTypeImpl(type); + EmitDeclarator(declarator); break; - case CodeGenTarget::GLSL: - Emit("shared "); + case kIROp_RateQualifiedType: + { + auto rateQualifiedType = cast<IRRateQualifiedType>(type); + emitTypeImpl(rateQualifiedType->getValueType(), declarator); + } + + case kIROp_ArrayType: + emitArrayTypeImpl(cast<IRArrayType>(type), declarator); break; - default: + case kIROp_UnsizedArrayType: + emitUnsizedArrayTypeImpl(cast<IRUnsizedArrayType>(type), declarator); break; } - emitTypeImpl(type->valueType, arg.declarator); + } void EmitType( - RefPtr<Type> type, + IRType* type, SourceLoc const& typeLoc, Name* name, SourceLoc const& nameLoc) @@ -1247,12 +1270,12 @@ struct EmitVisitor emitTypeImpl(type, &nameDeclarator); } - void EmitType(RefPtr<Type> type, Name* name) + void EmitType(IRType* type, Name* name) { EmitType(type, SourceLoc(), name, SourceLoc()); } - void EmitType(RefPtr<Type> type, String const& name) + void EmitType(IRType* type, String const& name) { // HACK: the rest of the code wants a `Name`, // so we'll create one for a bit... @@ -1263,7 +1286,7 @@ struct EmitVisitor } - void EmitType(RefPtr<Type> type) + void EmitType(IRType* type) { emitTypeImpl(type, nullptr); } @@ -1300,6 +1323,20 @@ struct EmitVisitor } } + void EmitType(IRType* type, Name* name, SourceLoc const& nameLoc) + { + EmitType( + type, + SourceLoc(), + name, + nameLoc); + } + + void EmitType(IRType* type, NameLoc const& nameAndLoc) + { + EmitType(type, nameAndLoc.name, nameAndLoc.loc); + } + bool isTargetIntrinsicModifierApplicable( IRTargetIntrinsicDecoration* decoration) { @@ -1407,78 +1444,16 @@ struct EmitVisitor } } - // - // Declaration References - // - - void EmitVal(RefPtr<Val> val) + void EmitVal(IRInst* val) { - if (auto type = val.As<Type>()) + if(auto type = as<IRType>(val)) { EmitType(type); } - else if (auto intVal = val.As<IntVal>()) - { - Emit(intVal); - } else { - // Note(tfoley): ignore unhandled cases for semantics for now... - // assert(!"unimplemented"); - } - } - - bool isBuiltinDecl(Decl* decl) - { - for (auto dd = decl; dd; dd = dd->ParentDecl) - { - if (dd->FindModifier<FromStdLibModifier>()) - return true; - } - return false; - } - - void EmitDeclRef(DeclRef<Decl> declRef) - { - // When refering to anything other than a builtin, use its IR-facing name - if (!isBuiltinDecl(declRef.getDecl())) - { - emit(getIRName(declRef)); - return; - } - - - // TODO: need to qualify a declaration name based on parent scopes/declarations - - // Emit the name for the declaration itself - emitName(declRef.GetName()); - - // If the declaration is nested directly in a generic, then - // we need to output the generic arguments here - auto parentDeclRef = declRef.GetParent(); - if (auto genericDeclRef = parentDeclRef.As<GenericDecl>()) - { - // Only do this for declarations of appropriate flavors - if(auto funcDeclRef = declRef.As<FunctionDeclBase>()) - { - // Don't emit generic arguments for functions, because HLSL doesn't allow them - return; - } - - GenericSubstitution* subst = declRef.substitutions.genericSubstitutions; - if (!subst) - return; - - Emit("<"); - UInt argCount = subst->args.Count(); - for (UInt aa = 0; aa < argCount; ++aa) - { - if (aa != 0) Emit(","); - EmitVal(subst->args[aa]); - } - Emit(" >"); + emitIRInstExpr(context, val, IREmitMode::Default); } - } typedef unsigned int ESemanticMask; @@ -1491,50 +1466,6 @@ struct EmitVisitor kESemanticMask_Default = kESemanticMask_NoPackOffset, }; - void EmitSemantic(RefPtr<HLSLSemantic> semantic, ESemanticMask /*mask*/) - { - if (auto simple = semantic.As<HLSLSimpleSemantic>()) - { - Emit(" : "); - emit(simple->name.Content); - } - else if(auto registerSemantic = semantic.As<HLSLRegisterSemantic>()) - { - // Don't print out semantic from the user, since we are going to print the same thing our own way... - } - else if(auto packOffsetSemantic = semantic.As<HLSLPackOffsetSemantic>()) - { - // Don't print out semantic from the user, since we are going to print the same thing our own way... - } - else - { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), semantic->loc, "unhandled kind of semantic"); - } - } - - - void EmitSemantics(RefPtr<Decl> decl, ESemanticMask mask = kESemanticMask_Default ) - { - // Don't emit semantics if we aren't translating down to HLSL - switch (context->shared->target) - { - case CodeGenTarget::HLSL: - break; - - default: - return; - } - - for (auto mod = decl->modifiers.first; mod; mod = mod->next) - { - auto semantic = mod.As<HLSLSemantic>(); - if (!semantic) - continue; - - EmitSemantic(semantic, mask); - } - } - // A chain of variables to use for emitting semantic/layout info struct EmitVarChain { @@ -1851,7 +1782,6 @@ struct EmitVisitor } } - void emitGLSLVersionDirective( ModuleDecl* /*program*/) { @@ -1949,19 +1879,6 @@ struct EmitVisitor return context->shared->uniqueIDCounter++; } - UInt getID(Decl* decl) - { - auto& mapDeclToID = context->shared->mapDeclToID; - - UInt id = 0; - if(mapDeclToID.TryGetValue(decl, id)) - return id; - - id = allocateUniqueID(); - mapDeclToID.Add(decl, id); - return id; - } - // IR-level emit logc UInt getID(IRInst* value) @@ -1977,105 +1894,25 @@ struct EmitVisitor return id; } - String getIRName(Decl* decl) - { - // 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) - { - // In general, when referring to a declaration that has been lowered - // via the IR, we want to use its mangled name. - // - // There are two main exceptions to this: - // - // 1. For debugging, we accept the `-no-mangle` flag which basically - // instructs us to try to use the original name of all declarations, - // to make the output more like what is expected to come out of - // fxc pass-through. This case should get deprecated some day. - // - // 2. It is really annoying to have the fields of a `struct` type - // get ridiculously lengthy mangled names, and this also messes - // up stuff like specialization (since the mangled name of a field - // would then include the mangled name of the outer type). - // - - String name; - if (context->shared->entryPoint->compileRequest->compileFlags & SLANG_COMPILE_FLAG_NO_MANGLING) - { - // Special case (1): - name.append(getText(declRef.GetName())); - return name; - } - - // Special case (2) - if (declRef.GetParent().decl->As<AggTypeDecl>()) - { - name.append(declRef.decl->nameAndLoc.name->text); - return name; - } - // General case: - name.append(getMangledName(declRef)); - return name; - } - String getIRName( IRInst* inst) { - switch(inst->op) - { - case kIROp_decl_ref: - { - auto irDeclRef = (IRDeclRef*) inst; - return getIRName(irDeclRef->declRef); - } - break; - - default: - break; - } - - if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>()) - { - auto decl = decoration->decl; - if (auto reflectionNameMod = decl->FindModifier<ParameterGroupReflectionName>()) - { - return getText(reflectionNameMod->nameAndLoc.name); - } - - if ((context->shared->entryPoint->compileRequest->compileFlags & SLANG_COMPILE_FLAG_NO_MANGLING)) - { - return getIRName(decl); - } - } - - switch (inst->op) + // If the instruction has a mangled name, then emit using that. + if (auto globalValue = as<IRGlobalValue>(inst)) { - case kIROp_global_var: - case kIROp_global_constant: - case kIROp_Func: + auto mangledName = globalValue->mangledName; + if (mangledName) { - auto& mangledName = ((IRGlobalValue*)inst)->mangledName; - if(getText(mangledName).Length() != 0) + auto mangledNameText = getText(mangledName); + if (mangledNameText.Length() != 0) + { return getText(mangledName); + } } - break; - - default: - break; } + // Otherwise fall back to a construct temporary name + // for the instruction. StringBuilder sb; sb << "_S"; sb << getID(inst); @@ -2180,8 +2017,8 @@ struct EmitVisitor break; case kIROp_Var: - case kIROp_global_var: - case kIROp_global_constant: + case kIROp_GlobalVar: + case kIROp_GlobalConstant: case kIROp_Param: return false; @@ -2190,7 +2027,7 @@ struct EmitVisitor case kIROp_boolConst: case kIROp_FieldAddress: case kIROp_getElementPtr: - case kIROp_specialize: + case kIROp_Specialize: case kIROp_BufferElementRef: return true; } @@ -2204,23 +2041,23 @@ struct EmitVisitor // variables. auto type = inst->getDataType(); - while (auto ptrType = type->As<PtrTypeBase>()) + while (auto ptrType = as<IRPtrTypeBase>(type)) { type = ptrType->getValueType(); } - if(type->As<UniformParameterGroupType>()) + if(as<IRUniformParameterGroupType>(type)) { // TODO: we need to be careful here, because // HLSL shader model 6 allows these as explicit // types. return true; } - else if (type->As<HLSLStreamOutputType>()) + else if (as<IRHLSLStreamOutputType>(type)) { return true; } - else if (type->As<HLSLPatchType>()) + else if (as<IRHLSLPatchType>(type)) { return true; } @@ -2231,15 +2068,15 @@ struct EmitVisitor // to fold them into their use sites in all cases if (getTarget(ctx) == CodeGenTarget::GLSL) { - if(type->As<ResourceTypeBase>()) + if(as<IRResourceTypeBase>(type)) { return true; } - else if(type->As<HLSLStructuredBufferTypeBase>()) + else if(as<IRHLSLStructuredBufferTypeBase>(type)) { return true; } - else if(type->As<SamplerStateType>()) + else if(as<IRSamplerStateType>(type)) { return true; } @@ -2255,7 +2092,7 @@ struct EmitVisitor { auto type = inst->getDataType(); - if(type->As<UniformParameterGroupType>() && !type->As<ParameterBlockType>()) + if(as<IRUniformParameterGroupType>(type) && !as<IRParameterBlockType>(type)) { // TODO: we need to be careful here, because // HLSL shader model 6 allows these as explicit @@ -2332,11 +2169,11 @@ struct EmitVisitor void emitIRRateQualifiers( EmitContext* ctx, - Type* rate) + IRRate* rate) { if(!rate) return; - if( auto constExprRate = rate->As<ConstExprRate>() ) + if(as<IRConstExprRate>(rate)) { switch( getTarget(ctx) ) { @@ -2348,6 +2185,23 @@ struct EmitVisitor break; } } + + if (as<IRGroupSharedRate>(rate)) + { + switch( getTarget(ctx) ) + { + case CodeGenTarget::HLSL: + Emit("groupshared "); + break; + + case CodeGenTarget::GLSL: + Emit("shared "); + break; + + default: + break; + } + } } void emitIRRateQualifiers( @@ -2366,7 +2220,7 @@ struct EmitVisitor if(!type) return; - if (type->Equals(getSession()->getVoidType())) + if (as<IRVoidType>(type)) return; emitIRRateQualifiers(ctx, inst); @@ -2708,13 +2562,13 @@ struct EmitVisitor auto textureArg = args[0].get(); auto samplerArg = args[1].get(); - if (auto baseTextureType = textureArg->type->As<TextureType>()) + if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) { emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); - if (auto samplerType = samplerArg->type->As<SamplerStateType>()) + if (auto samplerType = as<IRSamplerStateTypeBase>(samplerArg->getDataType())) { - if (samplerType->flavor == SamplerStateFlavor::SamplerComparisonState) + if (as<IRSamplerComparisonStateType>(samplerType)) { Emit("Shadow"); } @@ -2746,7 +2600,7 @@ struct EmitVisitor // We are going to hack this *hard* for now. auto textureArg = args[0].get(); - if (auto baseTextureType = textureArg->type->As<TextureType>()) + if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) { emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); Emit("("); @@ -2772,18 +2626,18 @@ struct EmitVisitor SLANG_RELEASE_ASSERT(argCount >= 1); auto textureArg = args[0].get(); - if (auto baseTextureType = textureArg->type->As<TextureType>()) + if (auto baseTextureType = as<IRTextureType>(textureArg->getDataType())) { - auto elementType = baseTextureType->elementType; - if (auto basicType = elementType->As<BasicExpressionType>()) + auto elementType = baseTextureType->getElementType(); + if (auto basicType = as<IRBasicType>(elementType)) { // A scalar result is expected Emit(".x"); } - else if (auto vectorType = elementType->As<VectorExpressionType>()) + else if (auto vectorType = as<IRVectorType>(elementType)) { // A vector result is expected - auto elementCount = GetIntVal(vectorType->elementCount); + auto elementCount = GetIntVal(vectorType->getElementCount()); if (elementCount < 4) { @@ -2813,9 +2667,9 @@ struct EmitVisitor SLANG_RELEASE_ASSERT(argCount > argIndex); auto vectorArg = args[argIndex].get(); - if (auto vectorType = vectorArg->type->As<VectorExpressionType>()) + if (auto vectorType = as<IRVectorType>(vectorArg->getDataType())) { - auto elementCount = GetIntVal(vectorType->elementCount); + auto elementCount = GetIntVal(vectorType->getElementCount()); Emit(elementCount); } else @@ -2850,7 +2704,7 @@ struct EmitVisitor UInt operandIndex = 1; - // + // if (auto targetIntrinsicDecoration = findTargetIntrinsicDecoration(ctx, func)) { emitTargetIntrinsicCallExpr( @@ -2869,7 +2723,29 @@ struct EmitVisitor // be better strategies (including just stuffing // a pointer to the original decl onto the callee). - UnmangleContext um(getText(func->mangledName)); + // If the intrinsic the user is calling is a generic, + // then the mangled name will have been set on the + // outer-most generic, and not on the leaf value + // (which is `func` above), so we need to walk + // upwards to find it. + // + IRGlobalValue* valueForName = func; + for(;;) + { + auto parentBlock = as<IRBlock>(valueForName->parent); + if(!parentBlock) + break; + + auto parentGeneric = as<IRGeneric>(parentBlock->parent); + if(!parentGeneric) + break; + + valueForName = parentGeneric; + } + + // We will use the `UnmangleContext` utility to + // help us split the original name into its pieces. + UnmangleContext um(getText(valueForName->mangledName)); um.startUnmangling(); // We'll read through the qualified name of the @@ -3075,8 +2951,8 @@ struct EmitVisitor case kIROp_Mul: // Are we targetting GLSL, and are both operands matrices? if(getTarget(ctx) == CodeGenTarget::GLSL - && inst->getOperand(0)->type->As<MatrixExpressionType>() - && inst->getOperand(1)->type->As<MatrixExpressionType>()) + && as<IRMatrixType>(inst->getOperand(0)->getDataType()) + && as<IRMatrixType>(inst->getOperand(1)->getDataType())) { emit("matrixCompMult("); emitIROperand(ctx, inst->getOperand(0), mode); @@ -3096,7 +2972,7 @@ struct EmitVisitor case kIROp_Not: { - if (inst->getDataType()->Equals(getSession()->getBoolType())) + if (as<IRBoolType>(inst->getDataType())) { emit("!"); } @@ -3248,7 +3124,7 @@ struct EmitVisitor } break; - case kIROp_specialize: + case kIROp_Specialize: { emitIROperand(ctx, inst->getOperand(0), mode); } @@ -3322,8 +3198,8 @@ struct EmitVisitor case kIROp_Var: { - auto ptrType = inst->getDataType(); - auto valType = ((PtrType*)ptrType)->getValueType(); + auto ptrType = cast<IRPtrType>(inst->getDataType()); + auto valType = ptrType->getValueType(); auto name = getIRName(inst); emitIRType(ctx, valType, name); @@ -3384,6 +3260,21 @@ struct EmitVisitor } void emitIRSemantics( + EmitContext*, + VarLayout* varLayout) + { + if(varLayout->flags & VarLayoutFlag::HasSemantic) + { + Emit(" : "); + emit(varLayout->semanticName); + if(varLayout->semanticIndex) + { + Emit(varLayout->semanticIndex); + } + } + } + + void emitIRSemantics( EmitContext* ctx, IRInst* inst) { @@ -3397,31 +3288,24 @@ struct EmitVisitor return; } - if(auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>()) + if (auto semanticDecoration = inst->findDecoration<IRSemanticDecoration>()) { - if(auto varLayout = layoutDecoration->layout.As<VarLayout>()) - { - if(varLayout->flags & VarLayoutFlag::HasSemantic) - { - Emit(" : "); - emit(varLayout->semanticName); - if(varLayout->semanticIndex) - { - Emit(varLayout->semanticIndex); - } - - return; - } - } + Emit(" : "); + emit(semanticDecoration->semanticName); + return; } - // TODO(tfoley): should we ever need to use the high-level declaration - // for this? It seems like the wrong approach... - - auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>(); - if( decoration ) + if(auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>()) { - EmitSemantics(decoration->decl); + auto layout = layoutDecoration->layout; + if(auto varLayout = layout.As<VarLayout>()) + { + emitIRSemantics(ctx, varLayout); + } + else if (auto entryPointLayout = layout.As<EntryPointLayout>()) + { + emitIRSemantics(ctx, entryPointLayout->resultLayout); + } } } @@ -3502,7 +3386,7 @@ struct EmitVisitor // may exit this region with operations that do *not* branch // to `end`, but such non-local control flow will hopefully // be captured. - // + // void emitIRStmtsForBlocks( EmitContext* ctx, IRBlock* begin, @@ -4003,7 +3887,7 @@ struct EmitVisitor return getText(entryPointLayout->entryPoint->getName()); } - // + // return "main"; } @@ -4250,7 +4134,7 @@ struct EmitVisitor auto name = getIRFuncName(func); - emitIRType(ctx, resultType, name); + EmitType(resultType, name); emit("("); auto firstParam = func->getFirstParam(); @@ -4312,19 +4196,19 @@ struct EmitVisitor void emitIRParamType( EmitContext* ctx, - Type* type, + IRType* type, String const& name) { // An `out` or `inout` parameter will have been // encoded as a parameter of pointer type, so // we need to decode that here. // - if( auto outType = type->As<OutType>() ) + if( auto outType = as<IROutType>(type)) { emit("out "); type = outType->getValueType(); } - else if( auto inOutType = type->As<InOutType>() ) + else if( auto inOutType = as<IRInOutType>(type)) { emit("inout "); type = inOutType->getValueType(); @@ -4333,16 +4217,29 @@ struct EmitVisitor emitIRType(ctx, type, name); } + IRInst* getSpecializedValue(IRSpecialize* specInst) + { + auto base = specInst->getBase(); + auto baseGeneric = as<IRGeneric>(base); + if (!baseGeneric) + return base; + + auto lastBlock = baseGeneric->getLastBlock(); + if (!lastBlock) + return base; + + auto returnInst = as<IRReturnVal>(lastBlock->getTerminator()); + if (!returnInst) + return base; + + return returnInst->getVal(); + } + void emitIRFuncDecl( EmitContext* ctx, IRFunc* func) { - // We don't want to declare generic functions, - // because none of our targets actually support them. - if(func->getGenericDecl()) - return; - - // We also don't want to emit declarations for operations + // We don't want to emit declarations for operations // that only appear in the IR as stand-ins for built-in // operations on that target. if (isTargetIntrinsic(ctx, func)) @@ -4361,7 +4258,7 @@ struct EmitVisitor // and as a result it *also* doesn't have the IR `param` instructions, // so we need to emit a declaration entirely from the type. - auto funcType = func->getType(); + auto funcType = func->getDataType(); auto resultType = func->getResultType(); auto name = getIRFuncName(func); @@ -4432,9 +4329,9 @@ struct EmitVisitor if(!value) return nullptr; - if(value->op == kIROp_specialize) + while (auto specInst = as<IRSpecialize>(value)) { - value = ((IRSpecialize*) value)->genericVal.get(); + value = getSpecializedValue(specInst); } if(value->op != kIROp_Func) @@ -4451,11 +4348,6 @@ struct EmitVisitor EmitContext* ctx, IRFunc* func) { - if(func->getGenericDecl()) - { - return; - } - if(!isDefinition(func)) { // This is just a function declaration, @@ -4479,27 +4371,39 @@ struct EmitVisitor } } -#if 0 void emitIRStruct( - EmitContext* context, - IRStructDecl* structType) + EmitContext* ctx, + IRStructType* structType) { emit("struct "); - emit(getName(structType)); + emit(getIRName(structType)); emit("\n{\n"); + indent(); - for(auto ff = structType->getFirstField(); ff; ff = ff->getNextField()) + for(auto ff : structType->getFields()) { + auto fieldKey = ff->getKey(); auto fieldType = ff->getFieldType(); - emitIRType(context, fieldType, getName(ff)); - emitIRSemantics(context, ff); + // Filter out fields with `void` type that might + // have been introduced by legalization. + if(as<IRVoidType>(fieldType)) + continue; + // Note: GLSL doesn't support interpolation modifiers on `struct` fields + if( ctx->shared->target != CodeGenTarget::GLSL ) + { + emitInterpolationModifiers(ctx, fieldKey, fieldType); + } + + emitIRType(ctx, fieldType, getIRName(fieldKey)); + emitIRSemantics(ctx, fieldKey); emit(";\n"); } + + dedent(); emit("};\n"); } -#endif void emitIRMatrixLayoutModifiers( EmitContext* ctx, @@ -4552,7 +4456,7 @@ struct EmitVisitor default: break; } - + } } @@ -4561,26 +4465,22 @@ struct EmitVisitor // of the variable is an integer type. void maybeEmitGLSLFlatModifier( EmitContext*, - Type* valueType) + IRType* valueType) { auto tt = valueType; - if(auto vecType = tt->As<VectorExpressionType>()) - tt = vecType->elementType; - if(auto vecType = tt->As<MatrixExpressionType>()) + if(auto vecType = as<IRVectorType>(tt)) + tt = vecType->getElementType(); + if(auto vecType = as<IRMatrixType>(tt)) tt = vecType->getElementType(); - auto baseType = tt->As<BasicExpressionType>(); - if(!baseType) - return; - - switch(baseType->baseType) + switch(tt->op) { default: break; - case BaseType::Int: - case BaseType::UInt: - case BaseType::UInt64: + case kIROp_IntType: + case kIROp_UIntType: + case kIROp_UInt64Type: Emit("flat "); break; } @@ -4588,36 +4488,51 @@ struct EmitVisitor void emitInterpolationModifiers( EmitContext* ctx, - VarDeclBase* decl, - Type* valueType) + IRInst* varInst, + IRType* valueType) { bool isGLSL = (ctx->shared->target == CodeGenTarget::GLSL); bool anyModifiers = false; - if(decl->FindModifier<HLSLNoInterpolationModifier>()) - { - anyModifiers = true; - Emit(isGLSL ? "flat " : "nointerpolation "); - } - else if(decl->FindModifier<HLSLNoPerspectiveModifier>()) - { - anyModifiers = true; - Emit("noperspective "); - } - else if(decl->FindModifier<HLSLLinearModifier>()) - { - anyModifiers = true; - Emit(isGLSL ? "smooth " : "linear "); - } - else if(decl->FindModifier<HLSLSampleModifier>()) - { - anyModifiers = true; - Emit("sample "); - } - else if(decl->FindModifier<HLSLCentroidModifier>()) + anyModifiers = true; + for(auto dd = varInst->firstDecoration; dd; dd = dd->next) { - anyModifiers = true; - Emit("centroid "); + if(dd->op != kIRDecorationOp_InterpolationMode) + continue; + + auto decoration = (IRInterpolationModeDecoration*)dd; + auto mode = decoration->mode; + + switch(mode) + { + case IRInterpolationMode::NoInterpolation: + anyModifiers = true; + Emit(isGLSL ? "flat " : "nointerpolation "); + break; + + case IRInterpolationMode::NoPerspective: + anyModifiers = true; + Emit("noperspective "); + break; + + case IRInterpolationMode::Linear: + anyModifiers = true; + Emit(isGLSL ? "smooth " : "linear "); + break; + + case IRInterpolationMode::Sample: + anyModifiers = true; + Emit("sample "); + break; + + case IRInterpolationMode::Centroid: + anyModifiers = true; + Emit("centroid "); + break; + + default: + break; + } } // If the user didn't explicitly qualify a varying @@ -4629,18 +4544,11 @@ struct EmitVisitor } } - void emitInterpolationModifiers( - EmitContext* ctx, - VarLayout* layout, - Type* valueType) - { - emitInterpolationModifiers(ctx, layout->varDecl, valueType); - } - void emitIRVarModifiers( EmitContext* ctx, VarLayout* layout, - Type* valueType) + IRInst* varDecl, + IRType* varType) { if (!layout) return; @@ -4651,7 +4559,7 @@ struct EmitVisitor // for an HLSL `RWTexture*` then we need to emit a `format` layout qualifier. if(getTarget(context) == CodeGenTarget::GLSL) { - if(auto resourceType = unwrapArray(valueType).As<TextureType>()) + if(auto resourceType = as<IRTextureType>(unwrapArray(varType))) { switch(resourceType->getAccess()) { @@ -4676,6 +4584,12 @@ struct EmitVisitor } } + if(layout->FindResourceInfo(LayoutResourceKind::VaryingInput) + || layout->FindResourceInfo(LayoutResourceKind::VaryingOutput)) + { + emitInterpolationModifiers(ctx, varDecl, varType); + } + if (ctx->shared->target == CodeGenTarget::GLSL) { // Layout-related modifiers need to come before the declaration, @@ -4696,20 +4610,12 @@ struct EmitVisitor case LayoutResourceKind::VaryingInput: { emit("in "); - if(layout->stage == Stage::Fragment) - { - maybeEmitGLSLFlatModifier(ctx, valueType); - } } break; - case LayoutResourceKind::FragmentOutput: + case LayoutResourceKind::VaryingOutput: { emit("out "); - if(layout->stage != Stage::Fragment) - { - maybeEmitGLSLFlatModifier(ctx, valueType); - } } break; @@ -4723,9 +4629,9 @@ struct EmitVisitor } void emitHLSLParameterBlock( - EmitContext* ctx, - IRGlobalVar* varDecl, - ParameterBlockType* type) + EmitContext* ctx, + IRGlobalVar* varDecl, + IRParameterBlockType* type) { emit("cbuffer "); @@ -4768,11 +4674,11 @@ struct EmitVisitor } void emitHLSLParameterGroup( - EmitContext* ctx, - IRGlobalVar* varDecl, - UniformParameterGroupType* type) + EmitContext* ctx, + IRGlobalVar* varDecl, + IRUniformParameterGroupType* type) { - if(auto parameterBlockType = type->As<ParameterBlockType>()) + if(auto parameterBlockType = as<IRParameterBlockType>(type)) { emitHLSLParameterBlock(ctx, varDecl, parameterBlockType); return; @@ -4805,45 +4711,52 @@ struct EmitVisitor auto elementType = type->getElementType(); - - if(auto declRefType = elementType->As<DeclRefType>()) + if(auto structType = as<IRStructType>(elementType)) { - if(auto structDeclRef = declRefType->declRef.As<StructDecl>()) + auto structTypeLayout = typeLayout.As<StructTypeLayout>(); + assert(structTypeLayout); + + UInt fieldIndex = 0; + for(auto ff : structType->getFields()) { - auto structTypeLayout = typeLayout.As<StructTypeLayout>(); - assert(structTypeLayout); + // 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. + // - 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++]; - auto fieldLayout = structTypeLayout->fields[fieldIndex++]; + auto fieldKey = ff->getKey(); + auto fieldType = ff->getFieldType(); - auto fieldType = GetType(ff); - if(fieldType->Equals(getSession()->getVoidType())) - continue; + // Fields of `void` type aren't valid in HLSL/GLSL. + // + // TODO: legalization should get rid of any fields that have + // empty, or effectively empty types (e.g., emptry structs + // should be translated over to `void`). + if(as<IRVoidType>(fieldType)) + continue; - emitIRVarModifiers(ctx, fieldLayout, fieldType); + emitIRVarModifiers(ctx, fieldLayout, fieldKey, fieldType); - emitIRType(ctx, fieldType, getIRName(ff)); + emitIRType(ctx, fieldType, getIRName(fieldKey)); - emitHLSLParameterGroupFieldLayoutSemantics(fieldLayout, &elementChain); + emitHLSLParameterGroupFieldLayoutSemantics(fieldLayout, &elementChain); - emit(";\n"); - } + emit(";\n"); } } else { + // TODO: during legalization we should turn `ParameterGroup<X>` where `X` + // is not a `struct` type into `ParameterGroup<S>` where `S` is defined + // as something like `struct S { X _; };` + // emit("/* unexpected */"); } @@ -4852,9 +4765,9 @@ struct EmitVisitor } void emitGLSLParameterBlock( - EmitContext* ctx, - IRGlobalVar* varDecl, - ParameterBlockType* type) + EmitContext* ctx, + IRGlobalVar* varDecl, + IRParameterBlockType* type) { auto varLayout = getVarLayout(ctx, varDecl); assert(varLayout); @@ -4893,11 +4806,11 @@ struct EmitVisitor } void emitGLSLParameterGroup( - EmitContext* ctx, - IRGlobalVar* varDecl, - UniformParameterGroupType* type) + EmitContext* ctx, + IRGlobalVar* varDecl, + IRUniformParameterGroupType* type) { - if(auto parameterBlockType = type->As<ParameterBlockType>()) + if(auto parameterBlockType = as<IRParameterBlockType>(type)) { emitGLSLParameterBlock(ctx, varDecl, parameterBlockType); return; @@ -4922,7 +4835,7 @@ struct EmitVisitor emitGLSLLayoutQualifier(LayoutResourceKind::DescriptorTableSlot, &containerChain); - if(type->As<GLSLShaderStorageBufferType>()) + if(as<IRGLSLShaderStorageBufferType>(type)) { emit("layout(std430) buffer "); } @@ -4939,52 +4852,50 @@ struct EmitVisitor auto elementType = type->getElementType(); - if(auto declRefType = elementType->As<DeclRefType>()) + if(auto structType = as<IRStructType>(elementType)) { - if(auto structDeclRef = declRefType->declRef.As<StructDecl>()) - { - auto structTypeLayout = typeLayout.As<StructTypeLayout>(); - assert(structTypeLayout); + 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. - // + UInt fieldIndex = 0; + for(auto ff : structType->getFields()) + { + // 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++]; + auto fieldLayout = structTypeLayout->fields[fieldIndex++]; - auto fieldType = GetType(ff); - if(fieldType->Equals(getSession()->getVoidType())) - continue; + auto fieldKey = ff->getKey(); + auto fieldType = ff->getFieldType(); + if(as<IRVoidType>(fieldType)) + continue; - // Note: we will emit matrix-layout modifiers here, but - // we will refrain from emitting other modifiers that - // might not be appropriate to the context (e.g., we - // shouldn't go emitting `uniform` just because these - // things are uniform...). - // - // TODO: we need a more refined set of modifiers that - // we should allow on fields, because we might end - // up supporting layout that isn't the default for - // the given block type (e.g., something other than - // `std140` for a uniform block). - // - emitIRMatrixLayoutModifiers(ctx, fieldLayout); + // Note: we will emit matrix-layout modifiers here, but + // we will refrain from emitting other modifiers that + // might not be appropriate to the context (e.g., we + // shouldn't go emitting `uniform` just because these + // things are uniform...). + // + // TODO: we need a more refined set of modifiers that + // we should allow on fields, because we might end + // up supporting layout that isn't the default for + // the given block type (e.g., something other than + // `std140` for a uniform block). + // + emitIRMatrixLayoutModifiers(ctx, fieldLayout); - emitIRType(ctx, fieldType, getIRName(ff)); + emitIRType(ctx, fieldType, getIRName(fieldKey)); // emitHLSLParameterGroupFieldLayoutSemantics(layout, fieldLayout); - emit(";\n"); - } + emit(";\n"); } } else @@ -5002,9 +4913,9 @@ struct EmitVisitor } void emitIRParameterGroup( - EmitContext* ctx, - IRGlobalVar* varDecl, - UniformParameterGroupType* type) + EmitContext* ctx, + IRGlobalVar* varDecl, + IRUniformParameterGroupType* type) { switch (ctx->shared->target) { @@ -5042,8 +4953,8 @@ struct EmitVisitor // Need to emit appropriate modifiers here. auto layout = getVarLayout(ctx, varDecl); - - emitIRVarModifiers(ctx, layout, varType); + + emitIRVarModifiers(ctx, layout, varDecl, varType); #if 0 switch (addressSpace) @@ -5067,12 +4978,12 @@ struct EmitVisitor emit(";\n"); } - RefPtr<Type> unwrapArray(Type* type) + IRType* unwrapArray(IRType* type) { - Type* t = type; - while( auto arrayType = t->As<ArrayExpressionType>() ) + IRType* t = type; + while( auto arrayType = as<IRArrayTypeBase>(t) ) { - t = arrayType->baseType; + t = arrayType->getElementType(); } return t; } @@ -5080,7 +4991,7 @@ struct EmitVisitor void emitIRStructuredBuffer_GLSL( EmitContext* ctx, IRGlobalVar* varDecl, - HLSLStructuredBufferTypeBase* structuredBufferType) + IRHLSLStructuredBufferTypeBase* structuredBufferType) { // Shader storage buffer is an OpenGL 430 feature // @@ -5145,7 +5056,7 @@ struct EmitVisitor // Emit a blank line so that the formatting is nicer. emit("\n"); - if (auto paramBlockType = varType->As<UniformParameterGroupType>()) + if (auto paramBlockType = as<IRUniformParameterGroupType>(varType)) { emitIRParameterGroup( ctx, @@ -5158,7 +5069,7 @@ struct EmitVisitor { // When outputting GLSL, we need to transform any declaration of // a `*StructuredBuffer<T>` into an ordinary `buffer` declaration. - if( auto structuredBufferType = unwrapArray(varType)->As<HLSLStructuredBufferTypeBase>() ) + if( auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(unwrapArray(varType)) ) { emitIRStructuredBuffer_GLSL( ctx, @@ -5205,7 +5116,7 @@ struct EmitVisitor } } - emitIRVarModifiers(ctx, layout, varType); + emitIRVarModifiers(ctx, layout, varDecl, varType); emitIRType(ctx, varType, getIRName(varDecl)); @@ -5282,11 +5193,11 @@ struct EmitVisitor emitIRFunc(ctx, (IRFunc*) inst); break; - case kIROp_global_var: + case kIROp_GlobalVar: emitIRGlobalVar(ctx, (IRGlobalVar*) inst); break; - case kIROp_global_constant: + case kIROp_GlobalConstant: emitIRGlobalConstant(ctx, (IRGlobalConstant*) inst); break; @@ -5294,202 +5205,158 @@ struct EmitVisitor emitIRVar(ctx, (IRVar*) inst); break; + case kIROp_StructType: + emitIRStruct(ctx, cast<IRStructType>(inst)); + break; + default: break; } } - void ensureStructDecl( - EmitContext* ctx, - DeclRef<StructDecl> declRef) + // An action to be performed during code emit. + struct EmitAction { - auto mangledName = getMangledName(declRef); - if(ctx->shared->irDeclsVisited.Contains(mangledName)) - return; - - ctx->shared->irDeclsVisited.Add(mangledName); - - // First emit any types used by fields of this type - for( auto ff : GetFields(declRef) ) + enum Level { - if(ff.getDecl()->HasModifier<HLSLStaticModifier>()) - continue; + ForwardDeclaration, + Definition, + }; + Level level; + IRInst* inst; + }; - auto fieldType = GetType(ff); - emitIRUsedType(ctx, fieldType); - } + struct ComputeEmitActionsContext + { + IRInst* moduleInst; + HashSet<IRInst*> openInsts; + Dictionary<IRInst*, EmitAction::Level> mapInstToLevel; + List<EmitAction>* actions; + }; - // Don't emit declarations for types that should be built-in on the target. - // - // TODO: This should really be checking if the type is a target intrinsic - // for the chosen target, and not just whether it is globally declared - // as a builtin (so that we can have types that are builtin in some cases, - // but not others). - if(declRef.getDecl()->HasModifier<BuiltinModifier>()) - return; + void ensureInstOperand( + ComputeEmitActionsContext* ctx, + IRInst* inst, + EmitAction::Level requiredLevel = EmitAction::Level::Definition) + { + if(!inst) return; - Emit("\nstruct "); - EmitDeclRef(declRef); - Emit("\n{\n"); - indent(); - for( auto ff : GetFields(declRef) ) + if(inst->getParent() == ctx->moduleInst) { - if(ff.getDecl()->HasModifier<HLSLStaticModifier>()) - continue; - - auto fieldType = GetType(ff); - - // Skip `void` fields that might have been created by legalization. - if(fieldType->Equals(getSession()->getVoidType())) - continue; - - // Note: GLSL doesn't support interpolation modifiers on `struct` fields - if( ctx->shared->target != CodeGenTarget::GLSL ) - { - emitInterpolationModifiers(ctx, ff.getDecl(), fieldType); - } - emitIRType(ctx, fieldType, getIRName(ff)); - - EmitSemantics(ff.getDecl()); - - emit(";\n"); + ensureGlobalInst(ctx, inst, requiredLevel); } - dedent(); - Emit("};\n"); } - void emitIRUsedDeclRef( - EmitContext* ctx, - DeclRef<Decl> declRef) + void ensureInstOperandsRec( + ComputeEmitActionsContext* ctx, + IRInst* inst) { - auto decl = declRef.getDecl(); + ensureInstOperand(ctx, inst->getFullType()); - if(decl->HasModifier<BuiltinTypeModifier>() - || decl->HasModifier<MagicTypeModifier>()) + UInt operandCount = inst->operandCount; + for(UInt ii = 0; ii < operandCount; ++ii) { - return; + // TODO: there are some special cases we can add here, + // to avoid outputting full definitions in cases that + // can get by with forward declarations. + // + // For example, true pointer types should (in principle) + // only need the type they point to to be forward-declared. + // Similarly, a `call` instruction only needs the callee + // to be forward-declared, etc. + + ensureInstOperand(ctx, inst->getOperand(ii)); } - if( auto structDeclRef = declRef.As<StructDecl>() ) + if(auto parentInst = as<IRParentInst>(inst)) { - // - ensureStructDecl(ctx, structDeclRef); + for(auto child : parentInst->getChildren()) + { + ensureInstOperandsRec(ctx, child); + } } } - // A type is going to be used by the IR, so - // make sure that we have emitted whatever - // it needs. - void emitIRUsedType( - EmitContext* ctx, - Type* type) + void ensureGlobalInst( + ComputeEmitActionsContext* ctx, + IRInst* inst, + EmitAction::Level requiredLevel) { - if(type->As<BasicExpressionType>()) - {} - else if(type->As<VectorExpressionType>()) - {} - else if(type->As<MatrixExpressionType>()) - {} - else if(auto arrayType = type->As<ArrayExpressionType>()) - { - emitIRUsedType(ctx, arrayType->baseType); - } - else if( auto textureType = type->As<TextureTypeBase>() ) - { - emitIRUsedType(ctx, textureType->elementType); - } - else if( auto genericType = type->As<BuiltinGenericType>() ) - { - emitIRUsedType(ctx, genericType->elementType); - } - else if( auto ptrType = type->As<PtrTypeBase>() ) - { - emitIRUsedType(ctx, ptrType->getValueType()); - } - else if(type->As<SamplerStateType>() ) - { - } - else if( auto declRefType = type->As<DeclRefType>() ) + // Skip certain instrutions, since they + // don't affect output. + switch(inst->op) { - auto declRef = declRefType->declRef; - emitIRUsedDeclRef(ctx, declRef); + case kIROp_WitnessTable: + case kIROp_Generic: + return; + + default: + break; } - else - {} - } - void emitIRUsedTypesForGlobalValueWithCode( - EmitContext* ctx, - IRGlobalValueWithCode* value) - { - for( auto bb = value->getFirstBlock(); bb; bb = bb->getNextBlock() ) + // Have we already processed this instruction? + EmitAction::Level existingLevel; + if(ctx->mapInstToLevel.TryGetValue(inst, existingLevel)) { - for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() ) - { - emitIRUsedTypesForValue(ctx, pp); - } - - for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() ) - { - emitIRUsedTypesForValue(ctx, ii); - } + // If we've already emitted it suitably, + // then don't worry about it. + if(existingLevel >= requiredLevel) + return; } - } - void emitIRUsedTypesForValue( - EmitContext* ctx, - IRInst* value) - { - if(!value) return; - switch( value->op ) + EmitAction action; + action.level = requiredLevel; + action.inst = inst; + + if(requiredLevel == EmitAction::Level::Definition) { - case kIROp_Func: + if(ctx->openInsts.Contains(inst)) { - auto irFunc = (IRFunc*) value; + SLANG_UNEXPECTED("circularity during codegen"); + return; + } - // Don't emit anything for a generic function, - // since we only care about the types used by - // the actual specializations. - if (irFunc->getGenericDecl()) - return; + ctx->openInsts.Add(inst); - emitIRUsedType(ctx, irFunc->getResultType()); + ensureInstOperandsRec(ctx, inst); - emitIRUsedTypesForGlobalValueWithCode(ctx, irFunc); - } - break; + ctx->openInsts.Remove(inst); + } - case kIROp_global_var: - { - auto irGlobal = (IRGlobalVar*) value; - emitIRUsedType(ctx, irGlobal->type); - emitIRUsedTypesForGlobalValueWithCode(ctx, irGlobal); - } - break; + ctx->mapInstToLevel[inst] = requiredLevel; + ctx->actions->Add(action); + } - case kIROp_global_constant: - { - auto irGlobal = (IRGlobalConstant*) value; - emitIRUsedType(ctx, irGlobal->type); - emitIRUsedTypesForGlobalValueWithCode(ctx, irGlobal); - } - break; + void computeIREmitActions( + IRModule* module, + List<EmitAction>& ioActions) + { + ComputeEmitActionsContext ctx; + ctx.moduleInst = module->getModuleInst(); + ctx.actions = &ioActions; - default: - { - emitIRUsedType(ctx, value->type); - } - break; + for(auto inst : module->getGlobalInsts()) + { + ensureGlobalInst(&ctx, inst, EmitAction::Level::Definition); } } - void emitIRUsedTypesForModule( - EmitContext* ctx, - IRModule* module) + void executeIREmitActions( + EmitContext* ctx, + List<EmitAction> const& actions) { - for(auto ii : module->getGlobalInsts()) + for(auto action : actions) { - emitIRUsedTypesForValue(ctx, ii); + switch(action.level) + { + case EmitAction::Level::ForwardDeclaration: + emitIRFuncDecl(ctx, cast<IRFunc>(action.inst)); + break; + + case EmitAction::Level::Definition: + emitIRGlobalInst(ctx, action.inst); + break; + } } } @@ -5497,27 +5364,16 @@ struct EmitVisitor EmitContext* ctx, IRModule* module) { - emitIRUsedTypesForModule(ctx, module); + // The IR will usually come in an order that respects + // dependencies between global declarations, but this + // isn't guaranteed, so we need to be careful about + // the order in which we emit things. - // Before we emit code, we need to forward-declare - // all of our functions so that we don't have to - // sort them by dependencies. - for(auto ii : module->getGlobalInsts()) - { - if(ii->op != kIROp_Func) - continue; + List<EmitAction> actions; - auto func = (IRFunc*) ii; - emitIRFuncDecl(ctx, func); - } - - for(auto ii : module->getGlobalInsts()) - { - emitIRGlobalInst(ctx, ii); - } + computeIREmitActions(module, actions); + executeIREmitActions(ctx, actions); } - - }; // @@ -5614,7 +5470,7 @@ String emitEntryPoint( TargetRequest* targetRequest) { auto translationUnit = entryPoint->getTranslationUnit(); - + SharedEmitContext sharedContext; sharedContext.target = target; sharedContext.finalTarget = targetRequest->target; @@ -5651,19 +5507,26 @@ String emitEntryPoint( target, targetRequest); { - TypeLegalizationContext typeLegalizationContext; - typeLegalizationContext.session = entryPoint->compileRequest->mSession; - IRModule* irModule = getIRModule(irSpecializationState); auto compileRequest = translationUnit->compileRequest; + auto session = compileRequest->mSession; - typeLegalizationContext.irModule = irModule; + TypeLegalizationContext typeLegalizationContext; + initialize(&typeLegalizationContext, + session, + irModule); specializeIRForEntryPoint( irSpecializationState, entryPoint, &sharedContext.extensionUsageTracker); +#if 0 + fprintf(stderr, "### CLONED:\n"); + dumpIR(irModule); + fprintf(stderr, "###\n"); +#endif + validateIRModuleIfEnabled(compileRequest, irModule); // If the user specified the flag that they want us to dump @@ -5685,15 +5548,16 @@ String emitEntryPoint( // Debugging code for IR transformations... #if 0 fprintf(stderr, "### SPECIALIZED:\n"); - dumpIR(lowered); + dumpIR(irModule); fprintf(stderr, "###\n"); #endif + validateIRModuleIfEnabled(compileRequest, irModule); // After we've fully specialized all generics, and // "devirtualized" all the calls through interfaces, // we need to ensure that the code only uses types // that are legal on the chosen target. - // + // legalizeTypes( &typeLegalizationContext, irModule); @@ -5701,9 +5565,10 @@ String emitEntryPoint( // Debugging output of legalization #if 0 fprintf(stderr, "### LEGALIZED:\n"); - dumpIR(lowered); + dumpIR(irModule); fprintf(stderr, "###\n"); #endif + validateIRModuleIfEnabled(compileRequest, irModule); // Once specialization and type legalization have been performed, // we should perform some of our basic optimization steps again, @@ -5712,6 +5577,11 @@ String emitEntryPoint( // so that we can work with the individual fields). constructSSA(irModule); +#if 0 + fprintf(stderr, "### AFTER SSA:\n"); + dumpIR(irModule); + fprintf(stderr, "###\n"); +#endif validateIRModuleIfEnabled(compileRequest, irModule); // After all of the required optimization and legalization @@ -5721,9 +5591,9 @@ String emitEntryPoint( // TODO: do we want to emit directly from IR, or translate the // IR back into AST for emission? visitor.emitIRModule(&context, irModule); - + // retain the specialized ir module, because the current - // GlobalGenericParamSubstitution implementation may reference ir objects + // GlobalGenericParamSubstitution implementation may reference ir objects targetRequest->compileRequest->compiledModules.Add(irModule); } destroyIRSpecializationState(irSpecializationState); @@ -5755,7 +5625,7 @@ String emitEntryPoint( finalResultBuilder << code; String finalResult = finalResultBuilder.ProduceString(); - + return finalResult; } |
