Jeroen Dobbelaere via llvm-dev
2020-Jul-15 10:42 UTC
[llvm-dev] Using full restrict to map sets of variables to a universe
Hi Kelvin, Tarique, Based on what I understood from your explanation yesterday in the LLVM AA Technical call, you can probably use following technique to map 'sets of global variables' to their own 'alias scope': The (rough) c equivalent code looks like: --- // Conceptual example of mapping an access to a generic set: // set A int tgtA01, tgtA02, tgtA03; int * __restrict pSetA; // restrict to setA // set B int tgtB01, tgtB02, tgtB03; int * __restrict pSetB; // restrict to setB int* addSingleRestrictInfo(int* p, int * __restrict* pSet) { *pSet = p; return *pSet; } extern int _g2RestrictI; // must not be 'known' int* addTwoRestrictInfo(int *p, int *__restrict* pSet0, int *__restrict* pSet1) { int * retP; if (_g2RestrictI == 0) { *pSet0 = p; retP = *pSet0; } else { *pSet1 = p; retP = *pSet1; } return retP; } void test(int *pA, int *pB, int *pAB) { *addSingleRestrictInfo(pA, &pSetA) = 42; *addSingleRestrictInfo(pB, &pSetB) = 43; *addTwoRestrictInfo(pAB, &pSetA, &pSetB) = 44; } ---- It is based on: - pSetA and pSetB representing two different 'object P', each specifying its own set of objects - they work at global level (depending on the "unknown function" scope) -> after inlining, its information will still apply. - addSingleRestrictInfo / addTwoRestrictInfo are used to introduce restrict information to a pointer 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: ---- ; Function Attrs: nofree nounwind uwtable define dso_local void @test(i32* %pA, i32* %pB, i32* %pAB) local_unnamed_addr #1 !noalias !14 { entry: %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 store i32 42, i32* %pA, ptr_provenance i32* %0, align 4, !tbaa !12, !noalias !14 %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 store i32 43, i32* %pB, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !14 %2 = load i32, i32* @_g2RestrictI, align 4, !tbaa !12, !noalias !14 ;; NOTE: unnecessary load %cmp.i = icmp eq i32 %2, 0 %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 %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 %prov.retP.0.i = select i1 %cmp.i, i32* %3, i32* %4 store i32 44, i32* %pAB, ptr_provenance i32* %prov.retP.0.i, align 4, !tbaa !12, !noalias !14 ret void } ---- This still contains an unnecessary load from '_g2RestrictI' (which should be optimized away at MIR level). For these kind of use cases, it makes sense to introduce a new intrinsic that joins the possible @llvm.provenance.noalias paths. It should replace the load/cmp/select; something like: %prov.retP.0.i = call i32* @llvm.provenance.depends i32* %3, i32* %4 You also do not need to map 'pSetA' and 'pSetB' to real memory locations. After lowering to MIR, those dependencies should be gone. Greetings, Jeroen Dobbelaere
Tarique Islam via llvm-dev
2020-Jul-15 19:23 UTC
[llvm-dev] Using full restrict to map sets of variables to a universe
Hi Jeroen, 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. Regards, Tarique Islam XL Fortran Compiler Development IBM Toronto Software Lab From: Jeroen Dobbelaere <Jeroen.Dobbelaere at synopsys.com> To: Kelvin Li <kli at ca.ibm.com>, Tarique Islam <tislam at ca.ibm.com>, "llvm-dev at lists.llvm.org" <llvm-dev at lists.llvm.org> Date: 2020-07-15 06:42 AM Subject: [EXTERNAL] Using full restrict to map sets of variables to a universe Hi Kelvin, Tarique, Based on what I understood from your explanation yesterday in the LLVM AA Technical call, you can probably use following technique to map 'sets of global variables' to their own 'alias scope': The (rough) c equivalent code looks like: --- // Conceptual example of mapping an access to a generic set: // set A int tgtA01, tgtA02, tgtA03; int * __restrict pSetA; // restrict to setA // set B int tgtB01, tgtB02, tgtB03; int * __restrict pSetB; // restrict to setB int* addSingleRestrictInfo(int* p, int * __restrict* pSet) { *pSet = p; return *pSet; } extern int _g2RestrictI; // must not be 'known' int* addTwoRestrictInfo(int *p, int *__restrict* pSet0, int *__restrict* pSet1) { int * retP; if (_g2RestrictI == 0) { *pSet0 = p; retP = *pSet0; } else { *pSet1 = p; retP = *pSet1; } return retP; } void test(int *pA, int *pB, int *pAB) { *addSingleRestrictInfo(pA, &pSetA) = 42; *addSingleRestrictInfo(pB, &pSetB) = 43; *addTwoRestrictInfo(pAB, &pSetA, &pSetB) = 44; } ---- It is based on: - pSetA and pSetB representing two different 'object P', each specifying its own set of objects - they work at global level (depending on the "unknown function" scope) -> after inlining, its information will still apply. - addSingleRestrictInfo / addTwoRestrictInfo are used to introduce restrict information to a pointer 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: ---- ; Function Attrs: nofree nounwind uwtable define dso_local void @test(i32* %pA, i32* %pB, i32* %pAB) local_unnamed_addr #1 !noalias !14 { entry: %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 store i32 42, i32* %pA, ptr_provenance i32* %0, align 4, !tbaa !12, !noalias !14 %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 store i32 43, i32* %pB, ptr_provenance i32* %1, align 4, !tbaa !12, !noalias !14 %2 = load i32, i32* @_g2RestrictI, align 4, !tbaa !12, !noalias !14 ;; NOTE: unnecessary load %cmp.i = icmp eq i32 %2, 0 %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 %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 %prov.retP.0.i = select i1 %cmp.i, i32* %3, i32* %4 store i32 44, i32* %pAB, ptr_provenance i32* %prov.retP.0.i, align 4, !tbaa !12, !noalias !14 ret void } ---- This still contains an unnecessary load from '_g2RestrictI' (which should be optimized away at MIR level). For these kind of use cases, it makes sense to introduce a new intrinsic that joins the possible @llvm.provenance.noalias paths. It should replace the load/cmp/select; something like: %prov.retP.0.i = call i32* @llvm.provenance.depends i32* %3, i32* %4 You also do not need to map 'pSetA' and 'pSetB' to real memory locations. After lowering to MIR, those dependencies should be gone. Greetings, Jeroen Dobbelaere -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200715/a06f74ac/attachment.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: graycol.gif Type: image/gif Size: 105 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200715/a06f74ac/attachment.gif>