<html><body><p><font size="2">Hi </font><font size="2">Jeroen,</font><br><br><font size="2">  Thanks very much for the suggestion. We are going to explore the idea. We need to think a bit more about representing partially overlapping groups. </font><br><br><font size="2">Regards,<br>Tarique Islam<br>XL Fortran Compiler Development<br>IBM Toronto Software Lab<br><br><br></font><br><br><img width="16" height="16" src="cid:1__=8FBB0F35DFFA668A8f9e8a93df938690918c8FB@" border="0" alt="Inactive hide details for Jeroen Dobbelaere ---2020-07-15 06:42:53 AM---Hi Kelvin, Tarique, Based on what I understood from you"><font size="2" color="#424282">Jeroen Dobbelaere ---2020-07-15 06:42:53 AM---Hi Kelvin, Tarique, Based on what I understood from your explanation yesterday in the LLVM AA Techni</font><br><br><font size="2" color="#5F5F5F">From:        </font><font size="2">Jeroen Dobbelaere <Jeroen.Dobbelaere@synopsys.com></font><br><font size="2" color="#5F5F5F">To:        </font><font size="2">Kelvin Li <kli@ca.ibm.com>, Tarique Islam <tislam@ca.ibm.com>, "llvm-dev@lists.llvm.org" <llvm-dev@lists.llvm.org></font><br><font size="2" color="#5F5F5F">Date:        </font><font size="2">2020-07-15 06:42 AM</font><br><font size="2" color="#5F5F5F">Subject:        </font><font size="2">[EXTERNAL] Using full restrict to map sets of variables to a universe</font><br><hr width="100%" size="2" align="left" noshade style="color:#8091A5; "><br><br><br><tt><font size="2">Hi Kelvin, Tarique,<br><br>Based on what I understood from your explanation yesterday in the LLVM AA Technical call,<br>you can probably use following technique to map 'sets of global variables' to their own 'alias scope':<br><br>The (rough) c equivalent code looks like:<br><br>---<br>// Conceptual example of mapping an access to a generic set:<br>// set A<br>int tgtA01, tgtA02, tgtA03;<br>int * __restrict pSetA; // restrict to setA<br><br>// set B<br>int tgtB01, tgtB02, tgtB03;<br>int * __restrict pSetB; // restrict to setB<br><br><br>int* addSingleRestrictInfo(int* p, int * __restrict* pSet) {<br>  *pSet = p;<br>  return *pSet;<br>}<br><br>extern int _g2RestrictI; // must not be 'known'<br>int* addTwoRestrictInfo(int *p, int *__restrict* pSet0, int *__restrict* pSet1) {<br>  int * retP;<br>  if (_g2RestrictI == 0) {<br>    *pSet0 = p;<br>    retP = *pSet0;<br>  } else {<br>    *pSet1 = p;<br>    retP = *pSet1;<br>  }<br>  return retP;<br>}<br><br>void test(int *pA, int *pB, int *pAB) {<br>  *addSingleRestrictInfo(pA, &pSetA) = 42;<br>  *addSingleRestrictInfo(pB, &pSetB) = 43;<br>  *addTwoRestrictInfo(pAB, &pSetA, &pSetB) = 44;<br>}<br>----<br><br>It is based on:<br>- pSetA and pSetB representing two different 'object P', each specifying its own set of objects<br>- they work at global level (depending on the "unknown function" scope) -> after inlining, its information will still apply.<br>- addSingleRestrictInfo / addTwoRestrictInfo are used to introduce restrict information to a pointer<br><br><br>Of course, this conceptual example will introduce unnecessary stores to 'pSetA' and 'pSetB', so the actual llvm-ir you would want to produce for your fortran mapping should look something like:<br><br>----<br>; Function Attrs: nofree nounwind uwtable<br>define dso_local void @test(i32* %pA, i32* %pB, i32* %pAB) local_unnamed_addr #1 !noalias !14 {<br>entry:<br>  %0 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %pA, i8* null, i32** nonnull @pSetA, i32** undef, i64 0, metadata !14) #3, !tbaa !5, !noalias !14<br>  store i32 42, i32* %pA, ptr_provenance i32* %0, align 4, !tbaa !12, !noalias !14<br>  %1 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %pB, i8* null, i32** nonnull @pSetB, i32** undef, i64 0, metadata !14) #3, !tbaa !5, !noalias !14<br>  store i32 43, i32* %pB, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !14<br>  %2 = load i32, i32* @_g2RestrictI, align 4, !tbaa !12, !noalias !14                                           ;; NOTE: unnecessary load<br>  %cmp.i = icmp eq i32 %2, 0<br>  %3 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %pAB, i8* null, i32** nonnull @pSetA, i32** undef, i64 0, metadata !14) #4, !tbaa !5, !noalias !14<br>  %4 = tail call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %pAB, i8* null, i32** nonnull @pSetB, i32** undef, i64 0, metadata !14) #4, !tbaa !5, !noalias !14<br>  %prov.retP.0.i = select i1 %cmp.i,  i32* %3, i32*  %4<br>  store i32 44, i32* %pAB, ptr_provenance i32* %prov.retP.0.i, align 4, !tbaa !12, !noalias !14<br>  ret void<br>}<br>---- <br><br>This still contains an unnecessary load from '_g2RestrictI' (which should be optimized away at MIR level).<br><br>For these kind of use cases, it makes sense to introduce a new intrinsic that joins the possible @llvm.provenance.noalias paths.<br>It should replace the load/cmp/select; something like:<br>    %prov.retP.0.i = call i32* @llvm.provenance.depends i32* %3, i32* %4<br><br>You also do not need to map 'pSetA' and 'pSetB' to real memory locations. After lowering to MIR, those dependencies should be gone.<br><br>Greetings,<br><br>Jeroen Dobbelaere<br><br></font></tt><br><br><BR>
</body></html>