Does `@atomic` syntax support non-primitive-type fields in a `mutable struct`?

Does this mean that @atomic recursively applies the atomic version of setproperty! to the fields of a composite-type field object?

Not quite there is nothing recursive about the use of @atomic here.
t1.a contains a reference to an array. t1.a = b replaces that reference with another one. Only the update of the reference needs to be atomic.

Now if you have:

t1 = TT((1,2))

@atomic t1.a = (2, 1)

Tuples are stored inline

julia> sizeof(TT((1,2)))
32

and so the question is. How does Julia make sure that this
is done atomically?

julia> f(t1, b) =  @atomic t1.a = b 
f (generic function with 1 method)

julia> @code_llvm f(TT((1,2)), (2, 3))
; Function Signature: f(Main.TT{Tuple{Int64, Int64}}, Tuple{Int64, Int64})
;  @ REPL[4]:1 within `f`
define void @julia_f_1185(ptr noalias nocapture noundef nonnull sret([2 x i64]) align 8 dereferenceable(16) %sret_return, ptr noundef nonnull align 8 dereferenceable(32) %"t1::TT", ptr nocapture noundef nonnull readonly align 8 dereferenceable(16) %"b::Tuple") #0 {
top:
; ┌ @ Base.jl:75 within `setproperty!`
   %.a_ptr = getelementptr inbounds i8, ptr %"t1::TT", i64 16
   call void @jl_lock_value(ptr nonnull %"t1::TT")
   call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %.a_ptr, ptr noundef nonnull align 8 dereferenceable(16) %"b::Tuple", i64 16, i1 false)
   call void @jl_unlock_value(ptr nonnull %"t1::TT")
   call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %sret_return, ptr noundef nonnull align 8 dereferenceable(16) %"b::Tuple", i64 16, i1 false)
   ret void
; └
}

So if we can’t use an atomic instruction, because your CPU may not support the use of them, Julia falls back to using locks transparently.