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>