[AMD Official Use Only - Internal Distribution Only] Hi, Following issue is observed with Type Based Alias Analysis(TBAA). ####################################################### struct P { float f1; float f2; float f3[3]; float f4; }; void foo(struct P* p1, struct P* p2) { p1->f2 = 1.2; p2->f1 = 3.7; } int callFoo() { struct P p; foo(&p, &(p.f2)); } ###################################################### Printing alias-sets using commands: clang -O1 -S -emit-llvm struct_tbaa.c opt -basicaa -tbaa -print-alias-sets -disable-output struct_tbaa.ll yields: Alias sets for function 'foo': Alias Set Tracker: 2 alias sets for 2 pointer values. AliasSet[0x563d8f6a8bd0, 1] must alias, Mod Pointers: (i32* %f2, LocationSize::precise(4)) AliasSet[0x563d8f6bc080, 1] must alias, Mod Pointers: (float* %f1, LocationSize::precise(4)) IR of foo: ; Function Attrs: nofree norecurse nounwind uwtable writeonly define dso_local void @foo(%struct.P* nocapture %p1, %struct.P* nocapture %p2) local_unnamed_addr #0 { entry: %f2 = getelementptr inbounds %struct.P, %struct.P* %p1, i64 0, i32 1 store float 0x3FF3333340000000, float* %f2, align 4, !tbaa !2 %f1 = getelementptr inbounds %struct.P, %struct.P* %p2, i64 0, i32 0 store float 0x400D9999A0000000, float* %f1, align 4, !tbaa !7 ret void } !2 = !{!3, !4, i64 4} !3 = !{!"P", !4, i64 0, !4, i64 4, !5, i64 8, !4, i64 20} !4 = !{!"float", !5, i64 0} !5 = !{!"omnipotent char", !6, i64 0} !6 = !{!"Simple C/C++ TBAA"} !7 = !{!3, !4, i64 0} TBAA returns p1->f2 and p2->f1 in different alias-sets. But p1->f2 and p2->f1 do actually have the same address! Shouldn't the alias result be conservative while doing TBAA, especially when it needs interprocedural analysis? If instead of the above, p1->f2 and p2->f2 are the ones being accessed, then p1->f2 and p2->f2 are returned in same alias-sets. So, in second case, it is indeed conservative! Could someone please explain the rationale behind above behavior? Thanks, Siddharth -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200227/2a0136cb/attachment.html>
This is happening because there is undefined behaviour in your example. In C, a `struct P*` must point to the start of a `struct P`, so the compiler can assume references to two different members do not alias. In your example, you've constructed `p2` to point to the second member of the struct, which is not correct. Clang reports this as a warning: *######################################################* $ /work/llvm/build/bin/clang -fsyntax-only -c test.c test.c:15:11: warning: incompatible pointer types passing 'float *' to parameter of type 'struct P *' [-Wincompatible-pointer-types] foo(&p, &(p.f2)); ^~~~~~~ test.c:8:34: note: passing argument to parameter 'p2' here void foo(struct P *p1, struct P *p2) { ^ test.c:16:1: warning: non-void function does not return a value [-Wreturn-type] } ^ 2 warnings generated. *######################################################* Oliver On Fri, 28 Feb 2020 at 06:18, Tiwary, Siddharth via llvm-dev < llvm-dev at lists.llvm.org> wrote:> [AMD Official Use Only - Internal Distribution Only] > > Hi, > > > > Following issue is observed with Type Based Alias Analysis(TBAA). > > > > ####################################################### > > *struct P {* > > * float f1;* > > * float f2;* > > * float f3[3];* > > * float f4;* > > *};* > > > > *void foo(struct P* p1, struct P* p2) {* > > * p1->f2 = 1.2;* > > * p2->f1 = 3.7;* > > *}* > > > > *int callFoo() {* > > * struct P p;* > > * foo(&p, &(p.f2));* > > *}* > > *######################################################* > > > > Printing alias-sets using commands: > > > > * clang -O1 -S -emit-llvm struct_tbaa.c* > > * opt -basicaa -tbaa -print-alias-sets -disable-output struct_tbaa.ll* > > > > yields: > > > > *Alias sets for function 'foo':* > > *Alias Set Tracker: 2 alias sets for 2 pointer values.* > > * AliasSet[0x563d8f6a8bd0, 1] must alias, Mod Pointers: (i32* %f2, > LocationSize::precise(4))* > > * AliasSet[0x563d8f6bc080, 1] must alias, Mod Pointers: (float* > %f1, LocationSize::precise(4))* > > > > IR of foo: > > > > *; Function Attrs: nofree norecurse nounwind uwtable writeonly* > > *define dso_local void @foo(%struct.P* nocapture %p1, %struct.P* nocapture > %p2) local_unnamed_addr #0 {* > > *entry:* > > * %f2 = getelementptr inbounds %struct.P, %struct.P* %p1, i64 0, i32 1* > > * store float 0x3FF3333340000000, float* %f2, align 4, !tbaa !2* > > * %f1 = getelementptr inbounds %struct.P, %struct.P* %p2, i64 0, i32 0* > > * store float 0x400D9999A0000000, float* %f1, align 4, !tbaa !7* > > * ret void* > > *}* > > *!2 = !{!3, !4, i64 4}* > > *!3 = !{!"P", !4, i64 0, !4, i64 4, !5, i64 8, !4, i64 20}* > > *!4 = !{!"float", !5, i64 0}* > > *!5 = !{!"omnipotent char", !6, i64 0}* > > *!6 = !{!"Simple C/C++ TBAA"}* > > *!7 = !{!3, !4, i64 0}* > > > > TBAA returns p1->f2 and p2->f1 in different alias-sets. But p1->f2 and > p2->f1 do actually have the same address! Shouldn't the alias result be > conservative while doing TBAA, especially when it needs interprocedural > analysis? > > If instead of the above, p1->f2 and p2->f2 are the ones being accessed, > then p1->f2 and p2->f2 are returned in same alias-sets. So, in second case, > it is indeed conservative! > > > > Could someone please explain the rationale behind above behavior? > > > > Thanks, > > Siddharth > > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200228/1ee410c6/attachment-0001.html>
[AMD Public Use] Hi Oliver, I get rid of the warnings by explicitly type-casting it to struct*, and still get similar results. ####################################################### struct P { float f1; float f2; float f3[3]; float f4; }; void foo(struct P* p1, struct P* p2) { p1->f2 = 1.2; p2->f1 = 3.7; } int callFoo() { struct P p; foo(&p, (struct P*)(&(p.f2))); return 0; } ####################################################### Shouldn’t any alias analysis(including TBAA) be conservative in interprocedural context, and consider all aliasing possibilities between different fields? As mentioned before, if instead of the above, p1->f2 and p2->f2 are the ones being accessed, then p1->f2 and p2->f2 are returned in same alias-sets. So, in second case, it is indeed conservative. This too is in interprocedural context! I ask this because as a result of the above, following happens: ########################################## struct P { float f1; float f2; float f3[3]; float f4; }; float foo(struct P* p1, struct P* p2) { float sum = 0; for( int i = 0; i < 1000; i++) { sum += p1->f2; p2->f1 += i*7; } return sum; } int callFoo() { struct P p; p.f1 = 3.0; p.f2 = 7.0; printf("foo = %f\n", foo(&p, (struct P*)&(p.f2))); return 0; } int main() { callFoo(); return 0; } ########################################### Clang O0 and gcc O0/O1/O2 give the same expected result. For Clang, O1 onwards results are wrong! This is because the load and store get hoisted and sinked in the loop in foo, respectively. That happens even though load(p1->f2) and store(p2->f1) are same address, but LLVM doesn’t find it. Thanks, Siddharth ________________________________ From: Oliver Stannard <oliver.stannard at linaro.org> Sent: Friday, February 28, 2020 4:55 PM To: Tiwary, Siddharth <Siddharth.Tiwary at amd.com> Cc: llvm-dev at lists.llvm.org <llvm-dev at lists.llvm.org> Subject: Re: [llvm-dev] TBAA for struct fields [CAUTION: External Email] This is happening because there is undefined behaviour in your example. In C, a `struct P*` must point to the start of a `struct P`, so the compiler can assume references to two different members do not alias. In your example, you've constructed `p2` to point to the second member of the struct, which is not correct. Clang reports this as a warning: ###################################################### $ /work/llvm/build/bin/clang -fsyntax-only -c test.c test.c:15:11: warning: incompatible pointer types passing 'float *' to parameter of type 'struct P *' [-Wincompatible-pointer-types] foo(&p, &(p.f2)); ^~~~~~~ test.c:8:34: note: passing argument to parameter 'p2' here void foo(struct P *p1, struct P *p2) { ^ test.c:16:1: warning: non-void function does not return a value [-Wreturn-type] } ^ 2 warnings generated. ###################################################### Oliver On Fri, 28 Feb 2020 at 06:18, Tiwary, Siddharth via llvm-dev <llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org>> wrote: [AMD Official Use Only - Internal Distribution Only] Hi, Following issue is observed with Type Based Alias Analysis(TBAA). ####################################################### struct P { float f1; float f2; float f3[3]; float f4; }; void foo(struct P* p1, struct P* p2) { p1->f2 = 1.2; p2->f1 = 3.7; } int callFoo() { struct P p; foo(&p, &(p.f2)); } ###################################################### Printing alias-sets using commands: clang -O1 -S -emit-llvm struct_tbaa.c opt -basicaa -tbaa -print-alias-sets -disable-output struct_tbaa.ll yields: Alias sets for function 'foo': Alias Set Tracker: 2 alias sets for 2 pointer values. AliasSet[0x563d8f6a8bd0, 1] must alias, Mod Pointers: (i32* %f2, LocationSize::precise(4)) AliasSet[0x563d8f6bc080, 1] must alias, Mod Pointers: (float* %f1, LocationSize::precise(4)) IR of foo: ; Function Attrs: nofree norecurse nounwind uwtable writeonly define dso_local void @foo(%struct.P* nocapture %p1, %struct.P* nocapture %p2) local_unnamed_addr #0 { entry: %f2 = getelementptr inbounds %struct.P, %struct.P* %p1, i64 0, i32 1 store float 0x3FF3333340000000, float* %f2, align 4, !tbaa !2 %f1 = getelementptr inbounds %struct.P, %struct.P* %p2, i64 0, i32 0 store float 0x400D9999A0000000, float* %f1, align 4, !tbaa !7 ret void } !2 = !{!3, !4, i64 4} !3 = !{!"P", !4, i64 0, !4, i64 4, !5, i64 8, !4, i64 20} !4 = !{!"float", !5, i64 0} !5 = !{!"omnipotent char", !6, i64 0} !6 = !{!"Simple C/C++ TBAA"} !7 = !{!3, !4, i64 0} TBAA returns p1->f2 and p2->f1 in different alias-sets. But p1->f2 and p2->f1 do actually have the same address! Shouldn't the alias result be conservative while doing TBAA, especially when it needs interprocedural analysis? If instead of the above, p1->f2 and p2->f2 are the ones being accessed, then p1->f2 and p2->f2 are returned in same alias-sets. So, in second case, it is indeed conservative! Could someone please explain the rationale behind above behavior? Thanks, Siddharth _______________________________________________ LLVM Developers mailing list llvm-dev at lists.llvm.org<mailto:llvm-dev at lists.llvm.org> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev<https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.llvm.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fllvm-dev&data=02%7C01%7CSiddharth.Tiwary%40amd.com%7C55cbbbb7e1a94c96e95a08d7bc410071%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637184859677188070&sdata=FWe7e9hyGnK0Sfg01akjq9oYWzN2cJi%2BvorGSyvlx4A%3D&reserved=0> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200303/b1644936/attachment.html>