@@ -442,7 +442,7 @@ impl TypedGlobalVariable<'_> {
442442 } ;
443443 let ( coherent, space, access, reference) = match ( var. space . to_msl_name ( ) , var. space ) {
444444 ( Some ( space) , crate :: AddressSpace :: WorkGroup ) => {
445- ( "" , space, access, if self . reference { "& " } else { "" } )
445+ ( "" , space, access, if self . reference { "* " } else { "" } )
446446 }
447447 ( Some ( space) , _) if self . reference => {
448448 let coherent = if var
@@ -3143,6 +3143,31 @@ impl<W: Write> Writer<W> {
31433143 Ok ( check_written)
31443144 }
31453145
3146+ fn is_root_workgroup_pointer (
3147+ & self ,
3148+ chain : Handle < crate :: Expression > ,
3149+ context : & ExpressionContext ,
3150+ ) -> bool {
3151+ match context. function . expressions [ chain] {
3152+ crate :: Expression :: GlobalVariable ( handle) => {
3153+ let var = & context. module . global_variables [ handle] ;
3154+ var. space == crate :: AddressSpace :: WorkGroup
3155+ }
3156+ crate :: Expression :: FunctionArgument ( index) => {
3157+ let arg = & context. function . arguments [ index as usize ] ;
3158+ let type_inner = & context. module . types [ arg. ty ] . inner ;
3159+ matches ! (
3160+ type_inner,
3161+ crate :: TypeInner :: Pointer {
3162+ space: crate :: AddressSpace :: WorkGroup ,
3163+ ..
3164+ }
3165+ )
3166+ }
3167+ _ => false ,
3168+ }
3169+ }
3170+
31463171 /// Write the access chain `chain`.
31473172 ///
31483173 /// `chain` is a subtree of [`Access`] and [`AccessIndex`] expressions,
@@ -3201,13 +3226,22 @@ impl<W: Write> Writer<W> {
32013226 // indexing a struct with an expression.
32023227 match * base_ty {
32033228 crate :: TypeInner :: Struct { .. } => {
3229+ let is_workgroup = self . is_root_workgroup_pointer ( base, context) ;
3230+ let op = if is_workgroup { "->" } else { "." } ;
32043231 let base_ty = base_ty_handle. unwrap ( ) ;
32053232 self . put_access_chain ( base, policy, context) ?;
32063233 let name = & self . names [ & NameKey :: StructMember ( base_ty, index) ] ;
3207- write ! ( self . out, ". {name}" ) ?;
3234+ write ! ( self . out, "{op} {name}" ) ?;
32083235 }
32093236 crate :: TypeInner :: ValuePointer { .. } | crate :: TypeInner :: Vector { .. } => {
3237+ let is_workgroup_ptr = self . is_root_workgroup_pointer ( base, context) ;
3238+ if is_workgroup_ptr {
3239+ write ! ( self . out, "(*" ) ?;
3240+ }
32103241 self . put_access_chain ( base, policy, context) ?;
3242+ if is_workgroup_ptr {
3243+ write ! ( self . out, ")" ) ?;
3244+ }
32113245 // Prior to Metal v2.1 component access for packed vectors wasn't available
32123246 // however array indexing is
32133247 if context. get_packed_vec_kind ( base) . is_some ( ) {
@@ -3267,9 +3301,18 @@ impl<W: Write> Writer<W> {
32673301 let accessing_wrapped_binding_array =
32683302 matches ! ( * base_ty, crate :: TypeInner :: BindingArray { .. } ) ;
32693303
3304+ let is_workgroup = self . is_root_workgroup_pointer ( base, context) ;
3305+
3306+ if is_workgroup && !accessing_wrapped_array {
3307+ write ! ( self . out, "(*" ) ?;
3308+ }
32703309 self . put_access_chain ( base, policy, context) ?;
3310+ if is_workgroup && !accessing_wrapped_array {
3311+ write ! ( self . out, ")" ) ?;
3312+ }
32713313 if accessing_wrapped_array {
3272- write ! ( self . out, ".{WRAPPED_ARRAY_FIELD}" ) ?;
3314+ let op = if is_workgroup { "->" } else { "." } ;
3315+ write ! ( self . out, "{op}{WRAPPED_ARRAY_FIELD}" ) ?;
32733316 }
32743317 write ! ( self . out, "[" ) ?;
32753318
@@ -3350,16 +3393,21 @@ impl<W: Write> Writer<W> {
33503393 . is_atomic_pointer ( & context. module . types ) ;
33513394
33523395 if is_atomic_pointer {
3353- write ! (
3354- self . out,
3355- "{NAMESPACE}::atomic_load_explicit({ATOMIC_REFERENCE}"
3356- ) ?;
3396+ write ! ( self . out, "{NAMESPACE}::atomic_load_explicit(" ) ?;
3397+ let is_workgroup_ptr = self . is_root_workgroup_pointer ( pointer, context) ;
3398+ if !is_workgroup_ptr {
3399+ write ! ( self . out, "{ATOMIC_REFERENCE}" ) ?;
3400+ }
33573401 self . put_access_chain ( pointer, policy, context) ?;
33583402 write ! ( self . out, ", {NAMESPACE}::memory_order_relaxed)" ) ?;
33593403 } else {
33603404 // We don't do any dereferencing with `*` here as pointer arguments to functions
33613405 // are done by `&` references and not `*` pointers. These do not need to be
3362- // dereferenced.
3406+ // dereferenced, except for workgroups pointers.
3407+ let is_workgroup_ptr = self . is_root_workgroup_pointer ( pointer, context) ;
3408+ if is_workgroup_ptr {
3409+ write ! ( self . out, "*" ) ?;
3410+ }
33633411 self . put_access_chain ( pointer, policy, context) ?;
33643412 }
33653413
@@ -4006,9 +4054,13 @@ impl<W: Write> Writer<W> {
40064054 }
40074055
40084056 // Put the atomic function invocation.
4057+ let is_workgroup_atomic = self . is_root_workgroup_pointer ( pointer, context) ;
40094058 match * fun {
40104059 crate :: AtomicFunction :: Exchange { compare : Some ( cmp) } => {
4011- write ! ( self . out, "{ATOMIC_COMP_EXCH_FUNCTION}({ATOMIC_REFERENCE}" ) ?;
4060+ write ! ( self . out, "{ATOMIC_COMP_EXCH_FUNCTION}(" ) ?;
4061+ if !is_workgroup_atomic {
4062+ write ! ( self . out, "{ATOMIC_REFERENCE}" ) ?;
4063+ }
40124064 self . put_access_chain ( pointer, policy, context) ?;
40134065 write ! ( self . out, ", " ) ?;
40144066 self . put_expression ( cmp, context, true ) ?;
@@ -4017,10 +4069,10 @@ impl<W: Write> Writer<W> {
40174069 write ! ( self . out, ")" ) ?;
40184070 }
40194071 _ => {
4020- write ! (
4021- self . out ,
4022- "{NAMESPACE}::atomic_{fun_key}_explicit({ ATOMIC_REFERENCE}"
4023- ) ? ;
4072+ write ! ( self . out , "{NAMESPACE}::atomic_{fun_key}_explicit(" ) ? ;
4073+ if !is_workgroup_atomic {
4074+ write ! ( self . out , "{ ATOMIC_REFERENCE}") ? ;
4075+ }
40244076 self . put_access_chain ( pointer, policy, context) ?;
40254077 write ! ( self . out, ", " ) ?;
40264078 self . put_expression ( value, context, true ) ?;
@@ -4274,16 +4326,21 @@ impl<W: Write> Writer<W> {
42744326 . is_atomic_pointer ( & context. expression . module . types ) ;
42754327
42764328 if is_atomic_pointer {
4277- write ! (
4278- self . out,
4279- "{level}{NAMESPACE}::atomic_store_explicit({ATOMIC_REFERENCE}"
4280- ) ?;
4329+ write ! ( self . out, "{level}{NAMESPACE}::atomic_store_explicit(" ) ?;
4330+ let is_workgroup_atomic = self . is_root_workgroup_pointer ( pointer, & context. expression ) ;
4331+ if !is_workgroup_atomic {
4332+ write ! ( self . out, "{ATOMIC_REFERENCE}" ) ?;
4333+ }
42814334 self . put_access_chain ( pointer, policy, & context. expression ) ?;
42824335 write ! ( self . out, ", " ) ?;
42834336 self . put_expression ( value, & context. expression , true ) ?;
42844337 writeln ! ( self . out, ", {NAMESPACE}::memory_order_relaxed);" ) ?;
42854338 } else {
42864339 write ! ( self . out, "{level}" ) ?;
4340+ let is_workgroup_ptr = self . is_root_workgroup_pointer ( pointer, & context. expression ) ;
4341+ if is_workgroup_ptr {
4342+ write ! ( self . out, "*" ) ?;
4343+ }
42874344 self . put_access_chain ( pointer, policy, & context. expression ) ?;
42884345 write ! ( self . out, " = " ) ?;
42894346 self . put_expression ( value, & context. expression , true ) ?;
@@ -7449,7 +7506,8 @@ template <typename A>
74497506 }
74507507 _ => {
74517508 if var. space == crate :: AddressSpace :: WorkGroup
7452- && ep. stage == crate :: ShaderStage :: Mesh
7509+ && ( ep. stage == crate :: ShaderStage :: Mesh
7510+ || ep. stage == crate :: ShaderStage :: Task )
74537511 {
74547512 continue ;
74557513 }
@@ -7548,7 +7606,7 @@ template <typename A>
75487606 }
75497607 writeln ! ( self . out) ?;
75507608 }
7551- if ep. stage == crate :: ShaderStage :: Mesh {
7609+ if ep. stage == crate :: ShaderStage :: Mesh || ep . stage == crate :: ShaderStage :: Task {
75527610 for ( handle, var) in module. global_variables . iter ( ) {
75537611 if var. space != crate :: AddressSpace :: WorkGroup || fun_info[ handle] . is_empty ( ) {
75547612 continue ;
@@ -7567,7 +7625,7 @@ template <typename A>
75677625 } ;
75687626 writeln ! (
75697627 self . out,
7570- "threadgroup {ty_context}& {}" ,
7628+ "threadgroup {ty_context}* {}" ,
75717629 self . names[ & NameKey :: GlobalVariable ( handle) ]
75727630 ) ?;
75737631 }
@@ -8043,19 +8101,54 @@ mod workgroup_mem_init {
80438101 }
80448102
80458103 impl Access {
8104+ fn is_pointer_type ( & self , module : & crate :: Module ) -> bool {
8105+ match * self {
8106+ Access :: GlobalVariable ( handle) => {
8107+ let var = & module. global_variables [ handle] ;
8108+ // workgroup variables are passed as pointers to the kernel
8109+ var. space == crate :: AddressSpace :: WorkGroup
8110+ || matches ! ( module. types[ var. ty] . inner, crate :: TypeInner :: Pointer { .. } )
8111+ }
8112+ Access :: StructMember ( struct_handle, member_index) => {
8113+ // check if the member's type is a pointer
8114+ if let crate :: TypeInner :: Struct { ref members, .. } =
8115+ module. types [ struct_handle] . inner
8116+ {
8117+ if let Some ( member) = members. get ( member_index as usize ) {
8118+ matches ! (
8119+ module. types[ member. ty] . inner,
8120+ crate :: TypeInner :: Pointer { .. }
8121+ )
8122+ } else {
8123+ false
8124+ }
8125+ } else {
8126+ false
8127+ }
8128+ }
8129+ Access :: Array ( _) => false ,
8130+ }
8131+ }
8132+
80468133 fn write < W : Write > (
80478134 & self ,
80488135 writer : & mut W ,
80498136 names : & FastHashMap < NameKey , String > ,
8137+ op : & str ,
80508138 ) -> Result < ( ) , core:: fmt:: Error > {
80518139 match * self {
80528140 Access :: GlobalVariable ( handle) => {
80538141 write ! ( writer, "{}" , & names[ & NameKey :: GlobalVariable ( handle) ] )
80548142 }
80558143 Access :: StructMember ( handle, index) => {
8056- write ! ( writer, ".{}" , & names[ & NameKey :: StructMember ( handle, index) ] )
8144+ write ! (
8145+ writer,
8146+ "{}{}" ,
8147+ op,
8148+ & names[ & NameKey :: StructMember ( handle, index) ]
8149+ )
80578150 }
8058- Access :: Array ( depth) => write ! ( writer, ".{WRAPPED_ARRAY_FIELD} [__i{depth}]" ) ,
8151+ Access :: Array ( depth) => write ! ( writer, "{}{} [__i{depth}]" , op , WRAPPED_ARRAY_FIELD ) ,
80598152 }
80608153 }
80618154 }
@@ -8094,12 +8187,33 @@ mod workgroup_mem_init {
80948187 & self ,
80958188 writer : & mut W ,
80968189 names : & FastHashMap < NameKey , String > ,
8190+ module : & crate :: Module ,
80978191 ) -> Result < ( ) , core:: fmt:: Error > {
8098- for next in self . stack . iter ( ) {
8099- next. write ( writer, names) ?;
8192+ for ( i, next) in self . stack . iter ( ) . enumerate ( ) {
8193+ let op = if i == 0 {
8194+ // root item doesn't get an operator prefix
8195+ ""
8196+ } else {
8197+ // check if the previous item is a pointer to determine the operator for this item
8198+ let prev = & self . stack [ i - 1 ] ;
8199+ if prev. is_pointer_type ( module) {
8200+ "->"
8201+ } else {
8202+ "."
8203+ }
8204+ } ;
8205+ next. write ( writer, names, op) ?;
81008206 }
81018207 Ok ( ( ) )
81028208 }
8209+
8210+ fn root_is_workgroup_pointer ( & self , module : & crate :: Module ) -> bool {
8211+ if let Some ( Access :: GlobalVariable ( handle) ) = self . stack . first ( ) . as_deref ( ) {
8212+ let var = & module. global_variables [ * handle] ;
8213+ return var. space == crate :: AddressSpace :: WorkGroup ;
8214+ }
8215+ false
8216+ }
81038217 }
81048218
81058219 impl < W : Write > Writer < W > {
@@ -8174,16 +8288,25 @@ mod workgroup_mem_init {
81748288 ) -> BackendResult {
81758289 if module_info[ ty] . contains ( valid:: TypeFlags :: CONSTRUCTIBLE ) {
81768290 write ! ( self . out, "{level}" ) ?;
8177- access_stack. write ( & mut self . out , & self . names ) ?;
8291+ // workgroup variables are always pointers; add * to dereference at root level.
8292+ // Nested accesses use -> operator from the access stack.
8293+ let is_root_workgroup = access_stack. root_is_workgroup_pointer ( module) ;
8294+ let is_nested = access_stack. stack . len ( ) > 1 ;
8295+ if is_root_workgroup && !is_nested {
8296+ write ! ( self . out, "*" ) ?;
8297+ }
8298+ access_stack. write ( & mut self . out , & self . names , module) ?;
81788299 writeln ! ( self . out, " = {{}};" ) ?;
81798300 } else {
81808301 match module. types [ ty] . inner {
81818302 crate :: TypeInner :: Atomic { .. } => {
8182- write ! (
8183- self . out,
8184- "{level}{NAMESPACE}::atomic_store_explicit({ATOMIC_REFERENCE}"
8185- ) ?;
8186- access_stack. write ( & mut self . out , & self . names ) ?;
8303+ write ! ( self . out, "{level}{NAMESPACE}::atomic_store_explicit(" ) ?;
8304+ // only skip & for direct access to workgroup atomic
8305+ let is_nested = access_stack. stack . len ( ) > 1 ;
8306+ if !access_stack. root_is_workgroup_pointer ( module) || is_nested {
8307+ write ! ( self . out, "{ATOMIC_REFERENCE}" ) ?;
8308+ }
8309+ access_stack. write ( & mut self . out , & self . names , module) ?;
81878310 writeln ! ( self . out, ", 0, {NAMESPACE}::memory_order_relaxed);" ) ?;
81888311 }
81898312 crate :: TypeInner :: Array { base, size, .. } => {
0 commit comments