diff options
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 348 |
1 files changed, 282 insertions, 66 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index b0ec6cbf0..7e22c4694 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1247,6 +1247,14 @@ void addVarDecorations( { builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Centroid; } + else if(mod.As<VulkanRayPayloadAttribute>()) + { + builder->addDecoration<IRVulkanRayPayloadDecoration>(inst); + } + else if(mod.As<VulkanHitAttributesAttribute>()) + { + builder->addDecoration<IRVulkanHitAttributesDecoration>(inst); + } // TODO: what are other modifiers we need to propagate through? } @@ -3419,13 +3427,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // A type alias declaration may be generic, if it is // nested under a generic type/function/etc. // - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; - IRGeneric* outerGeneric = emitOuterGenerics(subBuilder, decl, decl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + NestedContext nested(this); + auto subBuilder = nested.getBuilder(); + auto subContext = nested.getContet(); + IRGeneric* outerGeneric = emitOuterGenerics(subContext, decl, decl); // TODO: if a type alias declaration can have linkage, // we will need to lower it to some kind of global @@ -3624,13 +3629,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // declaration (either a type declaration or an `extension`) // is generic. // - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; - emitOuterGenerics(subBuilder, inheritanceDecl, inheritanceDecl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + NestedContext nested(this); + auto subBuilder = nested.getBuilder(); + auto subContext = nested.getContet(); + emitOuterGenerics(subContext, inheritanceDecl, inheritanceDecl); // Lower the super-type to force its declaration to be lowered. // @@ -3784,6 +3786,236 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return globalVal; } + bool isFunctionStaticVarDecl(VarDeclBase* decl) + { + // Only a variable marked `static` can be static. + if(!decl->FindModifier<HLSLStaticModifier>()) + return false; + + // The immediate parent of a function-scope variable + // declaration will be a `ScopeDecl`. + // + // TODO: right now the parent links for scopes are *not* + // set correctly, so we can't just scan up and look + // for a function in the parent chain... + auto parent = decl->ParentDecl; + if( dynamic_cast<ScopeDecl*>(parent) ) + { + return true; + } + + return false; + } + + IRInst* defaultSpecializeOuterGeneric( + IRInst* outerVal, + IRType* type, + GenericDecl* genericDecl) + { + auto builder = getBuilder(); + + // We need to specialize any generics that are further out... + auto specialiedOuterVal = defaultSpecializeOuterGenerics( + outerVal, + builder->getGenericKind(), + genericDecl); + + List<IRInst*> genericArgs; + + // Walk the parameters of the generic, and emit an argument for each, + // which will be a reference to binding for that parameter in the + // current scope. + // + // First we start with type and value parameters, + // in the order they were declared. + for (auto member : genericDecl->Members) + { + if (auto typeParamDecl = member.As<GenericTypeParamDecl>()) + { + genericArgs.Add(getSimpleVal(context, ensureDecl(context, typeParamDecl))); + } + else if (auto valDecl = member.As<GenericValueParamDecl>()) + { + genericArgs.Add(getSimpleVal(context, ensureDecl(context, valDecl))); + } + } + // Then we emit constraint parameters, again in + // declaration order. + for (auto member : genericDecl->Members) + { + if (auto constraintDecl = member.As<GenericTypeConstraintDecl>()) + { + genericArgs.Add(getSimpleVal(context, ensureDecl(context, constraintDecl))); + } + } + + return builder->emitSpecializeInst(type, specialiedOuterVal, genericArgs.Count(), genericArgs.Buffer()); + } + + IRInst* defaultSpecializeOuterGenerics( + IRInst* val, + IRType* type, + Decl* decl) + { + if(!val) return nullptr; + + auto parentVal = val->getParent(); + while(parentVal) + { + if(as<IRGeneric>(parentVal)) + break; + parentVal = parentVal->getParent(); + } + if(!parentVal) + return val; + + for(auto pp = decl->ParentDecl; pp; pp = pp->ParentDecl) + { + if(auto genericAncestor = dynamic_cast<GenericDecl*>(pp)) + { + return defaultSpecializeOuterGeneric(parentVal, type, genericAncestor); + } + } + + return val; + } + + struct NestedContext + { + IRGenEnv subEnvStorage; + IRBuilder subBuilderStorage; + IRGenContext subContextStorage; + + NestedContext(DeclLoweringVisitor* outer) + : subBuilderStorage(*outer->getBuilder()) + , subContextStorage(*outer->context) + { + auto outerContext = outer->context; + + subEnvStorage.outer = outerContext->env; + + subContextStorage.irBuilder = &subBuilderStorage; + subContextStorage.env = &subEnvStorage; + } + + IRBuilder* getBuilder() { return &subBuilderStorage; } + IRGenContext* getContet() { return &subContextStorage; } + }; + + + LoweredValInfo lowerFunctionStaticVarDecl( + VarDeclBase* decl) + { + // A global variable may need to be generic, if one + // of the outer declarations is generic. + NestedContext nestedContext(this); + auto subBuilder = nestedContext.getBuilder(); + auto subContext = nestedContext.getContet(); + subBuilder->setInsertInto(subBuilder->getModule()->getModuleInst()); + emitOuterGenerics(subContext, decl, decl); + + IRType* subVarType = lowerType(subContext, decl->getType()); + + IRGlobalValueWithCode* irGlobal = subBuilder->createGlobalVar(subVarType); + addVarDecorations(subContext, irGlobal, decl); + + addNameHint(context, irGlobal, decl); + maybeSetRate(context, irGlobal, decl); + + subBuilder->addHighLevelDeclDecoration(irGlobal, decl); + + // We are inside of a function, and that function might be generic, + // in which case the `static` variable will be lowered to another + // generic. Let's start with a terrible example: + // + // interface IHasCount { int getCount(); } + // int incrementCounter<T : IHasCount >(T val) { + // static int counter = 0; + // counter += val.getCount(); + // return counter; + // } + // + // In this case, `incrementCounter` will lower to a function + // nested in a generic, while `counter` will be lowered to + // a global variable nested in a *different* generic. + // The net result is something like this: + // + // int counter<T:IHasCount> = 0; + // + // int incrementCounter<T:IHasCount>(T val) { + // counter<T> += val.getCount(); + // return counter<T>; + // + // The references to `counter` inside of `incrementCounter` + // become references to `counter<T>`. + // + // At the IR level, this means that the value we install + // for `decl` needs to be a specialized reference to `irGlobal`, + // for any outer generics. + // + IRType* varType = lowerType(context, decl->getType()); + IRType* varPtrType = getBuilder()->getPtrType(varType); + auto irSpecializedGlobal = defaultSpecializeOuterGenerics(irGlobal, varPtrType, decl); + LoweredValInfo globalVal = LoweredValInfo::ptr(irSpecializedGlobal); + setValue(context, decl, globalVal); + + // A `static` variable with an initializer needs special handling, + // at least if the initializer isn't a compile-time constant. + if( auto initExpr = decl->initExpr ) + { + // We must create an ordinary global `bool isInitialized = false` + // to represent whether we've initialized this before. + // Then emit code like: + // + // if(!isInitialized) { <globalVal> = <initExpr>; isInitialized = true; } + // + // TODO: we could conceivably optimize this by detecting + // when the `initExpr` lowers to just a reference to a constant, + // and then either deleting the extra code structure there, + // or not generating it in the first place. That is a bit + // more complexity than I'm ready for at the moment. + // + + // Of course, if we are under a generic, then the Boolean + // variable need to be generic as well! + NestedContext nestedBoolContext(this); + auto boolBuilder = nestedBoolContext.getBuilder(); + auto boolContext = nestedBoolContext.getContet(); + boolBuilder->setInsertInto(boolBuilder->getModule()->getModuleInst()); + emitOuterGenerics(boolContext, decl, decl); + + auto irBoolType = boolBuilder->getBoolType(); + auto irBool = boolBuilder->createGlobalVar(irBoolType); + boolBuilder->setInsertInto(irBool); + boolBuilder->setInsertInto(boolBuilder->createBlock()); + boolBuilder->emitReturn(boolBuilder->getBoolValue(false)); + + auto boolVal = LoweredValInfo::ptr(defaultSpecializeOuterGenerics(irBool, irBoolType, decl)); + + + // Okay, with our global Boolean created, we can move on to + // generating the code we actually care about, back in the original function. + + auto builder = getBuilder(); + auto initBlock = builder->createBlock(); + auto afterBlock = builder->createBlock(); + + builder->emitIfElse(getSimpleVal(context, boolVal), afterBlock, initBlock, afterBlock); + + builder->setInsertInto(initBlock); + LoweredValInfo initVal = lowerLValueExpr(context, initExpr); + assign(context, globalVal, initVal); + assign(context, boolVal, LoweredValInfo::simple(builder->getBoolValue(true))); + builder->emitBranch(afterBlock); + + builder->setInsertInto(afterBlock); + } + + irGlobal->moveToEnd(); + finishOuterGenerics(subBuilder, irGlobal); + return globalVal; + } + LoweredValInfo visitGenericValueParamDecl(GenericValueParamDecl* decl) { return emitDeclRef(context, makeDeclRef(decl), @@ -3799,6 +4031,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return lowerGlobalVarDecl(decl); } + if(isFunctionStaticVarDecl(decl)) + { + return lowerFunctionStaticVarDecl(decl); + } + // A user-defined variable declaration will usually turn into // an `alloca` operation for the variable's storage, // plus some code to initialize it and then store to the variable. @@ -3913,16 +4150,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // TODO: a bit more work will be needed if we allow for // enum cases that have payloads, because then we need // a function that constructs the value given arguments. - - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; + // + NestedContext nestedContext(this); + auto subContext = nestedContext.getContet(); // Emit any generics that should wrap the actual type. - emitOuterGenerics(subBuilder, decl, decl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + emitOuterGenerics(subContext, decl, decl); return lowerRValueExpr(subContext, decl->initExpr); } @@ -3937,13 +4170,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> ensureDecl(context, inheritanceDecl); } - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; - emitOuterGenerics(subBuilder, decl, decl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + NestedContext nestedContext(this); + auto subBuilder = nestedContext.getBuilder(); + auto subContext = nestedContext.getContet(); + emitOuterGenerics(subContext, decl, decl); // An `enum` declaration will currently lower directly to its "tag" // type, so that any references to the `enum` become referenes to @@ -3977,15 +4207,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // We are going to create nested IR building state // to use when emitting the members of the type. // - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; + NestedContext nestedContext(this); + auto subBuilder = nestedContext.getBuilder(); + auto subContext = nestedContext.getContet(); // Emit any generics that should wrap the actual type. - emitOuterGenerics(subBuilder, decl, decl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + emitOuterGenerics(subContext, decl, decl); IRStructType* irStruct = subBuilder->createStructType(); addNameHint(context, irStruct, decl); @@ -4032,6 +4259,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> irStruct->moveToEnd(); + addTargetIntrinsicDecorations(irStruct, decl); + + return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irStruct)); } @@ -4426,17 +4656,14 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } IRGeneric* emitOuterGeneric( - IRBuilder* subBuilder, + IRGenContext* subContext, GenericDecl* genericDecl, Decl* leafDecl) { - // Of course, a generic might itself be nested inside of other generics... - auto nextOuterGeneric = emitOuterGenerics(subBuilder, genericDecl, leafDecl); - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; + auto subBuilder = subContext->irBuilder; + // Of course, a generic might itself be nested inside of other generics... + auto nextOuterGeneric = emitOuterGenerics(subContext, genericDecl, leafDecl); // We need to create an IR generic @@ -4498,13 +4725,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // The `leafDecl` represents the inner-most declaration we are actually // trying to emit, which is the one that should receive the mangled name. // - IRGeneric* emitOuterGenerics(IRBuilder* subBuilder, Decl* decl, Decl* leafDecl) + IRGeneric* emitOuterGenerics(IRGenContext* subContext, Decl* decl, Decl* leafDecl) { for(auto pp = decl->ParentDecl; pp; pp = pp->ParentDecl) { if(auto genericAncestor = dynamic_cast<GenericDecl*>(pp)) { - return emitOuterGeneric(subBuilder, genericAncestor, leafDecl); + return emitOuterGeneric(subContext, genericAncestor, leafDecl); } } @@ -4584,16 +4811,16 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> { // We are going to use a nested builder, because we will // change the parent node that things get nested into. - - IRBuilder subBuilderStorage = *getBuilder(); - IRBuilder* subBuilder = &subBuilderStorage; - + // + NestedContext nestedContext(this); + auto subBuilder = nestedContext.getBuilder(); + auto subContext = nestedContext.getContet(); // The actual `IRFunction` that we emit needs to be nested // inside of one `IRGeneric` for every outer `GenericDecl` // in the declaration hierarchy. - emitOuterGenerics(subBuilder, decl, decl); + emitOuterGenerics(subContext, decl, decl); // Collect the parameter lists we will use for our new function. ParameterLists parameterLists; @@ -4621,11 +4848,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } } - - IRGenContext subContextStorage = *context; - IRGenContext* subContext = &subContextStorage; - subContext->irBuilder = subBuilder; - // need to create an IR function here IRFunc* irFunc = subBuilder->createFunc(); @@ -4980,17 +5202,8 @@ LoweredValInfo lowerDecl( { IRBuilderSourceLocRAII sourceLocInfo(context->irBuilder, decl->loc); - IRGenEnv subEnv; - subEnv.outer = context->env; - - IRGenContext subContext = *context; - subContext.env = &subEnv; - - DeclLoweringVisitor visitor; - visitor.context = &subContext; - - + visitor.context = context; try { @@ -5030,9 +5243,12 @@ LoweredValInfo ensureDecl( subIRBuilder.sharedBuilder = context->irBuilder->sharedBuilder; subIRBuilder.setInsertInto(subIRBuilder.sharedBuilder->module->getModuleInst()); - IRGenContext subContext = *context; + IRGenEnv subEnv; + subEnv.outer = context->env; + IRGenContext subContext = *context; subContext.irBuilder = &subIRBuilder; + subContext.env = &subEnv; result = lowerDecl(&subContext, decl); |
