jeroen.dobbelaere added a comment. Just to give an example:
int foo(int* restrict *pA, int* restrict *pB) { int tmp=**pB; **pA=42; return tmp - **pB; // **pA and **pB can refer to the same objects } This gives following llvm-ir code with the 'full noalias' clang version (after optimizations): ; Function Attrs: nofree nounwind uwtable define dso_local i32 @foo(i32** nocapture %pA, i32** nocapture readonly %pB) local_unnamed_addr #0 !noalias !2 { entry: %0 = load i32*, i32** %pB, noalias_sidechannel i32** undef, align 8, !tbaa !5, !noalias !2 %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pB, i32** undef, i64 0, metadata !2), !tbaa !5, !noalias !2 %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 %3 = load i32*, i32** %pA, noalias_sidechannel i32** undef, align 8, !tbaa !5, !noalias !2 %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %3, i8* null, i32** %pA, i32** undef, i64 0, metadata !2), !tbaa !5, !noalias !2 store i32 42, i32* %3, noalias_sidechannel i32* %4, align 4, !tbaa !9, !noalias !2 %5 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 %sub = sub nsw i32 %2, %5 ret i32 %sub } When adding 'noalias' to the arguments (my understanding is that this is what the attributer would deduce, as pA and pB are only read): ; Function Attrs: nofree nounwind uwtable define dso_local i32 @foo(i32** noalias nocapture %pA, i32** noalias nocapture readonly %pB) local_unnamed_addr #0 !noalias !2 { entry: %0 = load i32*, i32** %pB, noalias_sidechannel i32** undef, align 8, !tbaa !5, !noalias !2 %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pB, i32** undef, i64 0, metadata !2), !tbaa !5, !noalias !2 %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 %3 = load i32*, i32** %pA, noalias_sidechannel i32** undef, align 8, !tbaa !5, !noalias !2 %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %3, i8* null, i32** %pA, i32** undef, i64 0, metadata !2), !tbaa !5, !noalias !2 store i32 42, i32* %3, noalias_sidechannel i32* %4, align 4, !tbaa !9, !noalias !2 %5 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 %sub = sub nsw i32 %2, %5 ret i32 %sub } and reoptimizing, we now get: ; Function Attrs: nofree nounwind uwtable define dso_local i32 @foo(i32** noalias nocapture %pA, i32** noalias nocapture readonly %pB) local_unnamed_addr #0 !noalias !2 { entry: %0 = load i32*, i32** %pA, noalias_sidechannel i32** undef, align 8, !tbaa !5, !noalias !2 %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pA, i32** undef, i64 0, metadata !2), !tbaa !5, !noalias !2 store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 ret i32 0 } '%sub' is optimized away because the now the alias analyzer deduces that '%pA' and '%pB' cannot refer to the same objects. This implies (because of restrict) that '*%pA' and '*%pB' cannot refer to the same objects and because of that, the 'store i32' could not have interfered with the 'load i32'. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74935/new/ https://reviews.llvm.org/D74935 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits