Issue 123462
Summary Functions merging doesn't respect TBAA metadata on store instructions
Labels new issue
Assignees
Reporter Panzerschrek
    See https://github.com/llvm/llvm-project/blob/58326f1d5b5b379590af92dd129b2f3b3e96af46/llvm/lib/Transforms/Utils/FunctionComparator.cpp#L698

Metadata for `store` instructions (including TBAA) isn't compared in function comparator. This may lead to merging functions with different TBAA metadata. This means breaking further optimizations based on TBAA, including removing loads and stores wrongly assumed to be redundant and optimized-out.

Example generated by my language compiler:
```llvm
%"1A" = type { i64 }
%"1B" = type { i64 }

; Function Attrs: nounwind
define private void @_Z6BStoreR1By(ptr noalias nonnull dereferenceable(8) %_arg_b, i64 %_arg_x) unnamed_addr #0 {
allocations:
  %x = alloca i64, align 8
  %0 = getelementptr inbounds %"1B", ptr %_arg_b, i32 0, i32 0
  br label %func_code

func_code: ; preds = %allocations
  store i64 %_arg_x, ptr %x, align 8, !tbaa !7
  %1 = load i64, ptr %x, align 8, !tbaa !7
 store i64 %1, ptr %0, align 8, !tbaa !7
  ret void
}

; Function Attrs: nounwind
define private void @_Z6AStoreR1Ax(ptr noalias nonnull dereferenceable(8) %_arg_a, i64 %_arg_x) unnamed_addr #0 {
allocations:
 %x = alloca i64, align 8
  %0 = getelementptr inbounds %"1A", ptr %_arg_a, i32 0, i32 0
  br label %func_code

func_code: ; preds = %allocations
  store i64 %_arg_x, ptr %x, align 8, !tbaa !0
  %1 = load i64, ptr %x, align 8, !tbaa !0
  store i64 %1, ptr %0, align 8, !tbaa !0
  ret void
}

; Function Attrs: nounwind
define hidden ptr @GetAStore() unnamed_addr #0 {
allocations:
  br label %func_code

func_code:                                        ; preds = %allocations
  ret ptr @_Z6AStoreR1Ax
}

; Function Attrs: nounwind
define hidden ptr @GetBStore() unnamed_addr #0 {
allocations:
 br label %func_code

func_code:                                        ; preds = %allocations
  ret ptr @_Z6BStoreR1By
}

attributes #0 = { nounwind }

!0 = !{!1, !1, i64 0}
!1 = !{!"i64", !2, i64 0}
!2 = !{!"byte64", !3, i64 0}
!3 = !{!"byte32", !4, i64 0}
!4 = !{!"byte16", !5, i64 0}
!5 = !{!"byte8", !6, i64 0}
!6 = !{!"__U_tbaa_root"}
!7 = !{!8, !8, i64 0}
!8 = !{!"u64", !2, i64 0}
```
Functions `BStore` and `AStore` have almost identical code - they store a value in memory, but using different TBAA tags - for `i64` and `u64` language types (which are in my language distinct from each other).

After running optimization passes (including functions merge pass) I get following code:
```llvm
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
define private void @_Z6AStoreR1Ax(ptr noalias nocapture nonnull writeonly dereferenceable(8) %_arg_a, i64 %_arg_x) unnamed_addr #0 {
allocations:
  store i64 %_arg_x, ptr %_arg_a, align 8, !tbaa !0
  ret void
}

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define hidden nonnull ptr @GetAStore() unnamed_addr #1 {
allocations:
  ret ptr @_Z6AStoreR1Ax
}

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define hidden nonnull ptr @GetBStore() unnamed_addr #1 {
allocations:
  ret ptr @_Z6AStoreR1Ax
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }

!0 = !{!1, !1, i64 0}
!1 = !{!"i64", !2, i64 0}
!2 = !{!"byte64", !3, i64 0}
!3 = !{!"byte32", !4, i64 0}
!4 = !{!"byte16", !5, i64 0}
!5 = !{!"byte8", !6, i64 0}
!6 = !{!"__U_tbaa_root"}
``` 

Two functions were merged, but this is incorrect behavior. In such example it's not a big deal, but in cases where such functions may be inlined later this may cause a bug leading to miscompilation and crashes in result binary code.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to