Skip to content

failure to emit mandatory write barriers for memoryref store in v1.12 (regression) #59547

@vtjnash

Description

@vtjnash

After store atomic ptr %box_Int64, ptr %memory_data release the write barrier code fails to be emitted by the optimizer (it was present after codegen), which is a correctness regression for gc-safety in v1.12 compared to v1.11. Since ijl_box_int64 allocates, it may change memoryref_mem to old, but the optimizer sees store atomic i64 140630014290416, ptr %memoryref_mem.tag_addr unordered and noalias and inaccessiblememonly knows that either of those prove the value cannot change.

julia> code_llvm(raw=true, (NTuple{10,Int},)) do t; x = Memory{Any}(undef, length(t)); for i in eachindex(t); @inbounds x[i] = t[i]; end; x; end                                                                                                                             
; Function Signature: var"#6"(NTuple{10, Int64})                       
;  @ REPL[1]:1 within `#6`                                                                                                                            
define swiftcc nonnull ptr @"julia_#6_934"(ptr nonnull swiftself "gcstack" %pgcstack_arg, ptr nocapture noundef nonnull readonly align 8 dereferenceable(80) %"t::Tuple") local_unnamed_addr #0 !dbg !4 {                                                                                                    
top:                                                                                                                                                  
  %jlcallframe1 = alloca [10 x ptr], align 8                                                                                                          
  %gcframe2 = alloca [12 x ptr], align 16                                
  call void @llvm.memset.p0.i64(ptr align 16 %gcframe2, i8 0, i64 96, i1 true)                                                                        
  store i64 40, ptr %gcframe2, align 8, !tbaa !21                                                                                                     
  %frame.prev = getelementptr inbounds nuw i8, ptr %gcframe2, i64 8                                                                                   
  %task.gcstack = load ptr, ptr %pgcstack_arg, align 8                                                                                                
  store ptr %task.gcstack, ptr %frame.prev, align 8, !tbaa !21           
  store ptr %gcframe2, ptr %pgcstack_arg, align 8                       
  %ptls_field = getelementptr inbounds nuw i8, ptr %pgcstack_arg, i64 16                                                                              
  %ptls_load = load ptr, ptr %ptls_field, align 8, !tbaa !21                                                                                          
  %0 = getelementptr inbounds nuw i8, ptr %ptls_load, i64 16                                                                                          
  %safepoint = load atomic ptr, ptr %0 monotonic, align 8, !tbaa !25, !invariant.load !14                                                             
  fence syncscope("singlethread") seq_cst                                
  %1 = load volatile i64, ptr %safepoint, align 8                                                                                                     
  fence syncscope("singlethread") seq_cst                                                                                                             
    #dbg_declare(ptr %"t::Tuple", !20, !DIExpression(), !27)                                                                                          
; ┌ @ boot.jl:588 within `GenericMemory`                                                                                                              
   %ptls_load230 = load ptr, ptr %ptls_field, align 8, !dbg !28, !tbaa !21
   %memoryref_mem = call noalias nonnull align 8 dereferenceable(112) ptr @ijl_gc_small_alloc(ptr %ptls_load230, i32 648, i32 112, i64 140630014290416) #11, !dbg !28                                                                                                                                        
   %memoryref_mem.tag_addr = getelementptr inbounds i8, ptr %memoryref_mem, i64 -8, !dbg !28                                                          
   store atomic i64 140630014290416, ptr %memoryref_mem.tag_addr unordered, align 8, !dbg !28, !tbaa !32                                              
   %memory_ptr = getelementptr inbounds nuw i8, ptr %memoryref_mem, i64 8, !dbg !28                                                                   
   %memory_data = getelementptr inbounds nuw i8, ptr %memoryref_mem, i64 16, !dbg !28                                                                 
   store ptr %memory_data, ptr %memory_ptr, align 8, !dbg !28, !tbaa !35, !alias.scope !38, !noalias !41                                              
   store i64 10, ptr %memoryref_mem, align 8, !dbg !28, !tbaa !46, !alias.scope !38, !noalias !41                                                     
   call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(80) %memory_data, i8 0, i64 80, i1 false), !dbg !28                      
; └                                                                                                                                                   
; ┌ @ essentials.jl:974 within `setindex!`                                                                                                            
   %.unbox = load i64, ptr %"t::Tuple", align 8, !dbg !48, !tbaa !25, !alias.scope !51, !noalias !52                                                  
   %gc_slot_addr_9 = getelementptr inbounds nuw i8, ptr %gcframe2, i64 88
   store ptr %memoryref_mem, ptr %gc_slot_addr_9, align 8                                                                                             
   %box_Int64 = call nonnull align 8 dereferenceable(8) ptr @ijl_box_int64(i64 signext %.unbox) #13, !dbg !48                                         
   store atomic ptr %box_Int64, ptr %memory_data release, align 8, !dbg !48, !tbaa !53, !alias.scope !55, !noalias !56                                
; └                                                                                                                                                   

Metadata

Metadata

Assignees

Labels

GCGarbage collectorbugIndicates an unexpected problem or unintended behaviorregression 1.12Regression in the 1.12 release

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions