@@ -3108,7 +3108,6 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
31083108 // This looks for cases where the copy can be elided. To generate valid
31093109 // SPIR-V, the argument must be a memory declaration.
31103110 //
3111- //
31123111
31133112 // If argInfo is nullptr and argInst is a rvalue, we do not have a proper
31143113 // pointer to pass to the function. we need a temporary variable in that
@@ -3118,7 +3117,32 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
31183117 // create a temporary variable for it because the function definition
31193118 // expects are point-to-pointer argument for resources, which will be
31203119 // resolved by legalization.
3121- if ((argInfo || (argInst && argInst->getopcode() == spv::Op::OpVariable)) &&
3120+
3121+ // Workaround for Nabla STL `NBL_REF_ARG(T)` macro
3122+ bool preliminaryInOutCanBeReference = false;
3123+ if (argInst) {
3124+ // new behaviour
3125+ preliminaryInOutCanBeReference =
3126+ argInst->getopcode() == spv::Op::OpVariable;
3127+ // old behaviour, but gated behind `vk::ext_reference`
3128+ if (param->hasAttr<VKReferenceExtAttr>()) {
3129+ if (argInst->isRValue()) {
3130+ emitError("argument for a parameter with vk::ext_reference attribute "
3131+ "must be a reference",
3132+ arg->getExprLoc());
3133+ return nullptr;
3134+ }
3135+ if (!canActAsOutParmVar(param)) {
3136+ emitError("argument for a non SPIR-V intrinsic parameter with vk::ext_reference attribute "
3137+ "must be a applied to `inout`",
3138+ arg->getExprLoc());
3139+ return nullptr;
3140+ }
3141+ preliminaryInOutCanBeReference = true;
3142+ }
3143+ }
3144+
3145+ if ((argInfo || preliminaryInOutCanBeReference) &&
31223146 canActAsOutParmVar(param) && !isArgGlobalVarWithResourceType &&
31233147 paramTypeMatchesArgType(paramType, arg->getType())) {
31243148 // Based on SPIR-V spec, function parameter must be always Function
0 commit comments