<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p><br>
</p>
<div class="moz-cite-prefix">On 9/26/19 11:27 AM, Das, Dibyendu via flang-dev wrote:<br>
</div>
<blockquote type="cite" cite="mid:DM6PR12MB32908AF79ED74F6E1E8A54D989860@DM6PR12MB3290.namprd12.prod.outlook.com">
<meta name="Generator" content="Microsoft Word 15 (filtered
medium)">
<!--[if !mso]><style>v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style><![endif]--><style><!--
/* Font Definitions */
@font-face
{font-family:"MS Gothic";
panose-1:2 11 6 9 7 2 5 8 2 4;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:"\@MS Gothic";
panose-1:2 11 6 9 7 2 5 8 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
{mso-style-name:msonormal;
margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
p.xxxxmsonormal, li.xxxxmsonormal, div.xxxxmsonormal
{mso-style-name:x_x_x_x_msonormal;
margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle21
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:#1F497D;
font-weight:normal;
font-style:normal;
text-decoration:none none;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D">Hi Kiran-<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D">So, the entire lowering to LLVM IR will happen in the frontend itself right ? That would mean that high level opts on OpenMP loops will now need to happen in the frontend ?</span></p>
</div>
</blockquote>
<p><br>
</p>
<p>I don't know that we know yet where these need to happen, but based on my discussions with Johannes, the loop transformations can be implemented in the OpenMPIRBuilder.</p>
<p> -Hal<br>
</p>
<p><br>
</p>
<blockquote type="cite" cite="mid:DM6PR12MB32908AF79ED74F6E1E8A54D989860@DM6PR12MB3290.namprd12.prod.outlook.com">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D"><o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D">-Thx<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D">dd<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;color:#1F497D"><o:p> </o:p></span></p>
<div>
<div style="border:none;border-top:solid #E1E1E1
1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> Kiran Chandramohan <a class="moz-txt-link-rfc2396E" href="mailto:Kiran.Chandramohan@arm.com">
<Kiran.Chandramohan@arm.com></a> <br>
<b>Sent:</b> Thursday, September 26, 2019 8:14 PM<br>
<b>To:</b> <a class="moz-txt-link-abbreviated" href="mailto:flang-dev@lists.flang-compiler.org">
flang-dev@lists.flang-compiler.org</a>; <a class="moz-txt-link-abbreviated" href="mailto:flang-dev@lists.llvm.org">
flang-dev@lists.llvm.org</a><br>
<b>Cc:</b> Eric Schweitz <a class="moz-txt-link-rfc2396E" href="mailto:eschweitz@nvidia.com">
<eschweitz@nvidia.com></a>; Doerfert, Johannes <a class="moz-txt-link-rfc2396E" href="mailto:jdoerfert@anl.gov">
<jdoerfert@anl.gov></a>; Das, Dibyendu <a class="moz-txt-link-rfc2396E" href="mailto:Dibyendu.Das@amd.com">
<Dibyendu.Das@amd.com></a><br>
<b>Subject:</b> Re: Flang Technical Call : Summary of presentation on OpenMP for Flang<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">[CAUTION: External Email] <o:p></o:p></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">Handling of Target construct<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">++++++++++++++++++++++<br>
Target construct in OpenMP is used to execute code on devices like GPUs. For this construct, the design I am proposing uses the OpenMP IRBuilder. The handling in MLIR will be minimal and will only involve passing through the information and processing loop
specific clauses like collapse. I expect that the driver will invoke flang multiple times for handling copies of the source for the targets and the host and clang-offload-bundler will be called to bundle and unbundle wherever necessary.
<br>
Note: I realise that there might be other opinions regarding this, if so please respond to this mail. <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
Below I summarize the various steps in the proposed F18 flow from Fortran source to LLVM IR.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">1) Fortran source. Consider the sample program below with a parallel do inside a target region.<br>
subroutine target_add(a, b, c, N)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> integer:: N<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> real:: a(N)<br>
real:: b(N)<br>
real:: c(N)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> !$omp target<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> !$omp parallel do<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> do i=1, N<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> c(i) = a(i) + b(i)<br>
end do<o:p></o:p></span></p>
</div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt;color:black">end subroutine<br>
<br>
2) Parse tree: Omitted to keep it short<br>
<br>
3) The parse tree is lowered to a mix of OpenMP and FIR dialects in MLIR. There are operations in the OpenMP dialect for representing the target, parallel, and parallel do constructs. Rest of the code is lowered to FIR.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">omp.target {<o:p></o:p></span></p>
</div>
<div>
<div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> omp.do {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> fir.do %i = 1 to %n : !fir.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> %a_val = fir.load %a_addr[%i] : memref<nxf32><br>
<span style="background:white">%b_val = fir.load %b_addr[%i] : memref<nxf32></span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> %c_val = addf %a_val, %b_val : !fir.float<br>
fir.store %c_val, %c_addr[%i] : memref<nxf32></span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> }<br>
}<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
4) The next conversion is to a mix of OpenMP and LLVM dialects in MLIR. Here the loop is now lowered to LLVM dialect of MLIR while the OpenMP constructs are retained. This is possible since the OpenMP dialect is designed to exist with other dialects including
FIR and LLVM.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">omp.target {<o:p></o:p></span></p>
</div>
<div>
<div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> omp.do {<o:p></o:p></span></p>
</div>
</div>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> ^body:<br>
....<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> %a_val = llvm.load %a_addr : !llvm<"float*"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> %b_val = llvm.load %b_addr : !llvm<"float*"></span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> %c_val = llvm.fadd %a_val, %b_val : !llvm.float</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> llvm.store %c_val, %c_addr : !llvm<"float*"></span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> ...</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black;background:white"> llvm.cond_br %check, ^s_exit, ^body</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> ^s_exit:<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<br>
<br>
5) At the translation stage, the mix of OpenMP and LLVM dialect is converted to LLVM IR using the OpenMP IRBuilder and the existing translation library for LLVM dialect. The OpenMP IRBuilder will be fed with the basic blocks constituting the loop and asked
to generate IR containing calls to the OpenMP runtime (tgt_target, kmpc_fork_call) for the parallel do construct in a target region.
<br>
Note: Only the host-side code is shown here.<br>
<br>
<span style="background:white">define internal void @target_add() {</span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<br>
call void _omp_offloading_target_add()<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<br>
}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">define internal void @__omp_offloading_target_add() {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> call i32 @__tgt_target( ...)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white"> call void kmpc_fork_call(__omp_outined_target_add)</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<br>
}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">define internal void @__omp_outined_target_add() {</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">...<o:p></o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">body:<br>
...<br>
%a_val = load float, float *a_addr<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">%b_val = load float, float *b_addr<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">%c_val = fadd %a_val, %b_val<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">store float %c_val, float *c_add<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">...<br>
br i1 %check, label %s_exit, label %body<br>
...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="background:white"><span style="font-size:12.0pt;color:black">s_exit:<o:p></o:p></span></p>
</div>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">--Kiran<o:p></o:p></span></p>
</div>
<div class="MsoNormal" style="text-align:center" align="center">
<hr align="center" width="98%" size="2">
</div>
<div id="divRplyFwdMsg">
<p class="MsoNormal"><b><span style="color:black">From:</span></b><span style="color:black"> flang-dev <<a href="mailto:flang-dev-bounces@lists.flang-compiler.org" moz-do-not-send="true">flang-dev-bounces@lists.flang-compiler.org</a>> on behalf of Kiran Chandramohan
<<a href="mailto:Kiran.Chandramohan@arm.com" moz-do-not-send="true">Kiran.Chandramohan@arm.com</a>><br>
<b>Sent:</b> 12 September 2019 16:43<br>
<b>To:</b> <a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">
flang-dev@lists.flang-compiler.org</a> <<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a>>;
<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a> <<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a>>; Eric Schweitz <<a href="mailto:eschweitz@nvidia.com" moz-do-not-send="true">eschweitz@nvidia.com</a>><br>
<b>Subject:</b> Re: [Flang-dev] Flang Technical Call : Summary of presentation on OpenMP for Flang</span>
<o:p></o:p></p>
<div>
<p class="MsoNormal"> <o:p></o:p></p>
</div>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">This mail summarises the handling of the simd construct.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">!$omp simd: The simd construct tells the compiler that the loop can be vectorised. Since vectorisation is performed by LLVM (See Note 1), the frontend passes the simd information
to LLVM through metadata. Since the simd construct is all handled by metadata we can skip the OpenMP IRBuilder for handling this construct (See Note 2).</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">1) Consider the following source which has a loop which adds two arrays and stores the result in another array. Assume that this loop is not trivially vectorisable due to some alias issues (the
arrays being pointers for e.g). An omp simd construct is used to inform the compiler that this loop can be vectorised.<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> !$omp simd simdlen(4)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> do i=1,n<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> c(i) = a(i) + b(i)<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> end do<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
2) The Fortran program will be parsed and represented as a parse tree. Skipping the parse tree representation to keep it short.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> <br>
3) The parse tree is lowered to a mix of OpenMP and FIR dialects in MLIR. <span style="background:white">
A representation for this code mix is given below. </span>We have an operation omp.simd in the dialect which represents OpenMP simd. It has attributes for the various constant clauses like simdlen, safelen etc. Reduction if present in the omp simd statement
can be represented by another operation omp.reduction. <span style="background:white">Any transformation necessary to expose reduction operations/variables (as specified in the reduction clause) can be performed in OpenMP MLIR layer itself. The fir do loop
is nested inside the simd region.<br>
<br>
<br>
</span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">omp.simd {simdlen=4} {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> fir.do %i = 1 to %n : !fir.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %a_val = fir.load %a_addr[%i] : memref<nxf32><br>
<span style="background:white">%a_val = fir.load %a_addr[%i] : memref<nxf32></span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white"> %c_val = addf %a_val, %b_val : !fir.float<br>
fir.store %c_val, %c_addr[%i] : memref<nxf32></span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">4) For this construct, the next step is to lower the OpenMP and FIR dialects to LLVM dialect. During this lowering, information is added via attributes to the memory instructions and loop branch
instruction in the loop.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">a) the memory access instructions have an attribute which denotes that they can be executed in parallel.
<br>
b) the loop branch instruction has attributes for enabling vectorisation, setting the vectorisation width and pointing to all memory access operations via the access_group which can be parallelised.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
^body:<br>
....<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">%a_val = llvm.load %a_addr : !llvm<"float*"> <span style="background:white">{access_group=1}</span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">%b_val = llvm.load %b_addr : !llvm<"float*"> {access_group=1}</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">%c_val = llvm.fadd %a_val, %b_val : !llvm.float</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">llvm.store %c_val, %c_addr : !llvm<"float*"> {access_group=1}</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">...</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black;background:white">llvm.cond_br %check, ^s_exit, ^body {vectorize_width=4, vectorize_enable=1,parallel_loop_accesses=1}</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">^s_exit:<o:p></o:p></span></p>
</div>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">llvm.cond_br %7, ^bb6, ^bb7<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">5) The LLVM MLIR is translated to LLVM IR. In this stage, all the attributes from (4) will be translated to metadata.<br>
<br>
body:<br>
...<br>
%a_val = load float, float *a_addr, !llvm.access.group !1<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">%b_val = load float, float *b_addr, <span style="background:white">!llvm.access.group !1</span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">%c_val = fadd %a_val, %b_val<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">store float %c_val, float *c_add, <span style="background:white"> !llvm.access.group !1</span><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">...<br>
br i1 %check, label %s_exit, label %body, !llvm.loop !2<br>
...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">s_exit:<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
!1 = !{}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">!2 = !distinct{!2,!3,!4,!5}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">!3 = !{!"llvm.loop.vectorize.width", i32 4}<br>
!4 = !{!"llvm.loop.vectorize.enable", i1 true}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt;color:black">!5 = !{!"llvm.loop.parallel_accesses", !1}<br>
<br>
<span style="background:white">Note:</span></span><span style="font-size:10.5pt;font-family:"Arial",sans-serif;color:#333333"><br>
</span><span style="font-size:12.0pt;color:black;background:white">1) There is support for vectorization in MLIR also, I am assuming that it is not as good as the LLVM vectoriser</span><span style="font-size:12.0pt;color:black;background:white"> </span><span style="font-size:12.0pt;color:black;background:white">and
hence not using</span><span style="font-size:12.0pt;color:black;background:white"> </span><span style="font-size:12.0pt;color:black;background:white">MLIR vectorization.</span><span style="font-size:10.5pt;font-family:"Arial",sans-serif;color:#333333"><br>
</span><span style="font-size:12.0pt;color:black;background:white">2) For this construct, we have chosen to not use the OpenMP IRBuilder. There is still one possible reason for using the OpenMP IRBuilder even for this simple use case. The use case being, if
LLVM decided to change the loop metadata then they have to change it only in the OpenMP IRBuilder. If we do not use the IRBuilder then the developers will have to change the metadata generation in Clang and Flang. I assume that this happens rarely and hence
is OK.</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div class="MsoNormal" style="text-align:center" align="center">
<hr align="center" width="98%" size="2">
</div>
<div id="x_divRplyFwdMsg">
<p class="MsoNormal"><b><span style="color:black">From:</span></b><span style="color:black"> flang-dev <<a href="mailto:flang-dev-bounces@lists.flang-compiler.org" moz-do-not-send="true">flang-dev-bounces@lists.flang-compiler.org</a>> on behalf of Kiran Chandramohan
<<a href="mailto:Kiran.Chandramohan@arm.com" moz-do-not-send="true">Kiran.Chandramohan@arm.com</a>><br>
<b>Sent:</b> 03 September 2019 23:02<br>
<b>To:</b> <a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">
flang-dev@lists.flang-compiler.org</a> <<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a>>;
<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a> <<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a>><br>
<b>Cc:</b> nd <<a href="mailto:nd@arm.com" moz-do-not-send="true">nd@arm.com</a>><br>
<b>Subject:</b> Re: [Flang-dev] Flang Technical Call : Summary of presentation on OpenMP for Flang</span>
<o:p></o:p></p>
<div>
<p class="MsoNormal"> <o:p></o:p></p>
</div>
</div>
<div>
<div id="x_x_divtagdefaultwrapper">
<div id="x_x_divtagdefaultwrapper">
<div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt;color:black"><br>
A walkthrough for the collapse clause on an OpenMP loop construct is given below. This is an example where the transformation (collapse) is performed in the MLIR layer itself.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">1)Fortran OpenMP code with collapse <br>
!$omp parallel do private(j) collapse(2)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">do i=lb1,ub1<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> do j=lb2,ub2<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> end do<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">end do<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">2) The Fortran source with OpenMP will be converted to an AST by the F18 parser. Parse tree not shown here to keep it short.<br>
<br>
3) <br>
3.a)The Parse tree will be lowered to a mix of FIR and OpenMP dialects. There are omp.parallel and omp.do operations in the OpenMP dialect which represents parallel and OpenMP loop constructs. The omp.do operation has an attribute "collapse" which specifies
the number of loops to be collapsed.<br>
omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> omp.do {collapse = 2} %i = %lb1 to %ub1 : !fir.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> fir.do %j = %lb2 to %ub2 : !fir.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
3.b) A transformation pass in MLIR will perform the collapsing. The collapse operation will cause the omp.do loop to be coalesced with the loop immediately following it. Note : There exists loop coalescing passes in MLIR transformation passes. We should try
to make use of it.<o:p></o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %ub3 = <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> omp.do %i = 0 to %ub3 : !fir.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
4) Next conversion will be to a mix of LLVM and OpenMP dialect.<o:p></o:p></span></p>
</div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %ub3 = <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> omp.do %i = 0 to %ub3 : !llvm.integer {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
5) Finally, LLVM IR will be generated for this code. The translation to LLVM IR can make use of the OpenMP IRBuilder. LLVM IR not shown here to keep it short.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">Thanks,<br>
Kiran<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div class="MsoNormal" style="text-align:center" align="center"><span style="font-size:12.0pt;color:black">
<hr align="center" width="98%" size="2">
</span></div>
<div id="x_x_divRplyFwdMsg">
<p class="MsoNormal"><b><span style="color:black">From:</span></b><span style="color:black"> Kiran Chandramohan <<a href="mailto:Kiran.Chandramohan@arm.com" moz-do-not-send="true">Kiran.Chandramohan@arm.com</a>><br>
<b>Sent:</b> 21 August 2019 13:15:04<br>
<b>To:</b> Eric Schweitz (PGI) <<a href="mailto:eric.schweitz@pgroup.com" moz-do-not-send="true">eric.schweitz@pgroup.com</a>>;
<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a> <<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a>>;
<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a> <<a href="mailto:flang-dev@lists.llvm.org" moz-do-not-send="true">flang-dev@lists.llvm.org</a>><br>
<b>Cc:</b> nd <<a href="mailto:nd@arm.com" moz-do-not-send="true">nd@arm.com</a>><br>
<b>Subject:</b> Re: Flang Technical Call : Summary of presentation on OpenMP for Flang</span><span style="font-size:12.0pt;color:black">
<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
</div>
<div>
<div id="x_x_x_divtagdefaultwrapper">
<div id="x_x_x_divtagdefaultwrapper">
<p><span style="font-size:12.0pt;color:black">Thanks, Eric for the clarification.<br>
<br>
Also, sharing this write up of the flow through the compiler for an OpenMP construct. The first one (Proposed Plan) is as per the presentation. The second one (Modified Plan) incorporates Eric's feedback to lower the F18 AST to a mix of OpenMP and FIR dialect.<br>
<br>
<br>
<b>I Proposed plan</b><o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">1) Example OpenMP code</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><br>
<Fortran code><br>
</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">!$omp parallel<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">c = a + b</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><br>
!$omp end parallel</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><More Fortran code></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">
</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><br>
<br>
2) Parse tree (Copied relevant section from -fdebug-dump-parse-tree)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><Fortran parse tree></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">| | ExecutionPartConstruct
-> ExecutableConstruct -> OpenMPConstruct -> OpenMPBlockConstruct<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | OmpBlockDirective -> Directive = Parallel<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | OmpClauseList -><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | Block<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | | | Variable -> Designator -> DataRef -> Name = 'c'<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | | | Expr -> Add<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | | | | Expr -> Designator -> DataRef -> Name = 'a'<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | | | | Expr -> Designator -> DataRef -> Name = 'b'<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">| | | OmpEndBlockDirective -> OmpBlockDirective -> Directive = Parallel<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><More Fortran parse tree><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">3) The first lowering will be to FIR dialect and the dialect has a pass-through operation for OpenMP. This operation has a nested region which contains the region of code influenced by the OpenMP
directive. The contained region will have other FIR (or standard dialect) operations.</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><br>
Mlir.region(…) {</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">
<br>
%1 = fir.x(…)</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> …</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">
<br>
%20 = fir.omp attribute:parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = addf %2, %3 : f32<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %21 = <more fir></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">…</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">4) The next lowering will be to OpenMP and LLVM dialect. The OpenMP dialect has an operation called parallel with a nested region of code. The nested region will have llvm dialect operations.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">Mlir.region(…) {</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">
<br>
%1 = llvm.xyz(...)</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> …</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">%20 = omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = llvm.fadd %2, %3 : !llvm.float<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %21 = <more llvm dialect></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">…</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">5) The next conversion will be to LLVM IR. Here the OpenMP dialect will be lowered using
the OpenMP IRBuilder and the translation library of the LLVM dialect. The IR Builder will see that there is a region under the OpenMP construct omp.parallel. It will collect all the basic blocks inside that region and then generate outlined code using those
basic blocks. Suitable calls will be inserted to the OpenMP API. </span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">
</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">define @outlined_parallel_fn(...)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">{<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ....<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = fadd float %2, %3<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ...<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> </span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">define @xyz(…)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">{ <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = alloca float<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> ....<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> call kmpc_fork_call(...,outlined_parallel_fn,...)<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><br>
<b>II Modified plan</b><o:p></o:p></span></p>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt;color:black"><br>
The differences are only in steps 3 and 4. Other steps remain the same.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">3) The first lowering will be to a mix of FIR dialect and OpenMP dialect. The OpenMP dialect has an operation called parallel with a nested region of code. The nested region will have FIR (and
standard dialect) operations.</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><br>
Mlir.region(…) {</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <br>
%1 = fir.x(…)</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> …</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <br>
%20 = omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = addf %2, %3 : f32<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %21 = <more fir></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">…</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">4) The next lowering will be to OpenMP and LLVM dialect<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black">Mlir.region(…) {</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <br>
%1 = llvm.xyz(...)</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> …</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">%20 = omp.parallel {<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %1 = llvm.fadd %2, %3 : !llvm.float<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> }<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> %21 = <more llvm dialect></span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">…</span><span style="font-size:12.0pt;font-family:"MS
Gothic";color:black">
</span><span style="font-size:12.0pt;color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">}<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">Thanks,<br>
Kiran<o:p></o:p></span></p>
</div>
<div class="MsoNormal" style="text-align:center" align="center"><span style="font-size:12.0pt;color:black">
<hr align="center" width="98%" size="2">
</span></div>
<div id="x_x_x_divRplyFwdMsg">
<p class="MsoNormal"><b><span style="color:black">From:</span></b><span style="color:black"> Eric Schweitz (PGI) <<a href="mailto:eric.schweitz@pgroup.com" moz-do-not-send="true">eric.schweitz@pgroup.com</a>><br>
<b>Sent:</b> 19 August 2019 17:35:04<br>
<b>To:</b> Kiran Chandramohan <<a href="mailto:Kiran.Chandramohan@arm.com" moz-do-not-send="true">Kiran.Chandramohan@arm.com</a>>;
<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a> <<a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">flang-dev@lists.flang-compiler.org</a>><br>
<b>Subject:</b> RE: Flang Technical Call : Summary of presentation on OpenMP for Flang</span><span style="font-size:12.0pt;color:black">
<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
</div>
<div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Re: And would like the FIR to have nothing to do with OpenMP.<o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">This seems stronger than what I meant, so I’ll clarify a bit.<o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">FIR should have no dependence on OpenMP, since it is possible to write (vanilla) Fortran programs without OpenMP. However FIR clearly must also co-exist with an OpenMP dialect. Stated another
way, we don’t want a circular dependence between “vanilla Fortran” and OpenMP. Since OpenMP is a directive-based meta-language that impacts the code gen of a program (whether it is Fortran or some other language), it seems quite natural and necessary that
OpenMP be able to operate upon the substrate language (whether that substrate is FIR or LLVM IR or something else). Fortunately, MLIR allows one to mix dialects, and thus each dialect can focus on the problems it’s trying to solve.<o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">--<o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Eric<o:p></o:p></span></p>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
<div>
<div style="border:none;border-top:solid
#E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="xxxxmsonormal"><b><span style="font-size:12.0pt;color:black">From:</span></b><span style="font-size:12.0pt;color:black"> flang-dev <<a href="mailto:flang-dev-bounces@lists.flang-compiler.org" moz-do-not-send="true">flang-dev-bounces@lists.flang-compiler.org</a>>
<b>On Behalf Of </b>Kiran Chandramohan<br>
<b>Sent:</b> Friday, August 16, 2019 9:13 AM<br>
<b>To:</b> <a href="mailto:flang-dev@lists.flang-compiler.org" moz-do-not-send="true">
flang-dev@lists.flang-compiler.org</a><br>
<b>Subject:</b> [Flang-dev] Flang Technical Call : Summary of presentation on OpenMP for Flang<o:p></o:p></span></p>
</div>
</div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
<div id="x_x_x_x_divtagdefaultwrapper">
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Hi,<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">This mail is a summary of the presentation that I gave on 31st August about supporting OpenMP in Flang (F18). Link to presentation: <a href="https://drive.google.com/open?id=1Q2Y2fIavewq9oxRDruWoi8TaItlq1g9l" moz-do-not-send="true">https://drive.google.com/open?id=1Q2Y2fIavewq9oxRDruWoi8TaItlq1g9l</a><o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The mail follows the contents of the presentation and should be read in conjunction with the slides. It also includes feedback provided during and outside the presentation. It would be great
to receive further feedback.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">This presentation discusses the design of how OpenMP can be represented in the IR and how it can be translated to LLVM IR. The design is intended to be modular so that other frontends (C/C++)
can reuse it in the future. The design should also enable reuse of OpenMP code from Clang (LLVM IR generation, Outlining etc). It should also be acceptable to Flang, MLIR, Clang communities. And most importantly should allow for any OpenMP optimisation desired.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The designs presented uses the following two components.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">a) MLIR [3]: Necessary since MLIR has already been chosen as the framework for building the Fortran IR (FIR) for Flang.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">b) OpenMP IRBuilder [2]: For sharing of OpenMP code with Clang.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The current sequential code flow in Flang (Slide 5) can be summarised as follows,<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">[Fortran code] -> Parser -> [AST] -> Lowering -> [FIR MLIR] -> Conversion -> [LLVM MLIR] -> Translation -> [LLVM IR]<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Four design plans are presented. These plans add OpenMP support to the sequential code flow. All the plans assume that FIR is augmented with a pass-through operation which represents OpenMP
constructs. <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Plan 1 (Slide 6)<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The first plan extends LLVM MLIR with OpenMP operations. The pass-through OpenMP operation in FIR is converted to the OpenMP operation in LLVM MLIR. The OpenMP operation in LLVM MLIR can be
converted to LLVM IR during translation. The translation process can call the OpenMP IR Builder to generated the LLVM IR code.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Pros: Easy to implement, Can reuse Clang OpenMP code.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Cons: Not acceptable to MLIR community [1]. By design LLVM MLIR should be similar to LLVM IR (OpenMP is a form of parallelism. Has concepts of nested regions etc which do not map directly to
LLVM IR and hence to LLVM MLIR).<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Plan 2 (Slide 7)<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">In the second plan, LLVM MLIR is not extended. Here the pass-through OpenMP operation in FIR has to be converted to existing LLVM MLIR. This would involve outlining, privatisation etc during
the conversion of FIR to LLVM MLIR.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Pros: Easy to implement.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Cons: Cannot be shared with other users (C/C++) and non-LLVM targets (accelerators). Cannot re-use Clang OpenMP code.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Plan 3 (Slide 8)<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The third plan defines a separate MLIR dialect for OpenMP. The pass-through OpenMP operation in FIR can be converted to Operations in the OpenMP MLIR dialect. OpenMP specific optimisations
can be performed in this dialect. This dialect will be lowered to the LLVM dialect and outlining etc will happen at this time.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Pros: MLIR dialect can be used by other users. Acceptable to MLIR community [1].<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Cons: Cannot reuse code from Clang for OpenMP<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Plan 4: The proposed design (Slide 9)<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The proposed design also involves creating an OpenMP dialect in MLIR. The difference lies in the fact that the OpenMP dialect has some ties to the LLVM dialect like sharing the types and using
the translation library of the LLVM dialect. The Fortran IR (FIR) will be lowered to a mix of OpenMP and LLVM dialect. The translation library of LLVM dialect will be extended to create a new translation library which can then lower the mix to LLVM IR. The
new translation library can make use of the LLVM IRBuilder.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Pros: Other users (C/C++) can use it. Can reuse Clang OpenMP code. Acceptable to MLIR community [1].<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Cons: Has some ties to the LLVM dialect. <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">OpenMP dialect<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">The proposed plan involves writing an MLIR dialect for OpenMP. An MLIR dialect has types and operations. Types will be based on the LLVM dialect. Operations will be a mix of fine and coarse-grained.
e.g. Coarse: omp.parallel, omp.target, Fine: omp.flush. The detailed design of the dialect is TBD and will be based on what should be optimized. The OpenMP dialect creation in the proposed plan is from FIR, this would require pass-through OpenMP operations
in FIR. Another approach would be to lower F18 AST with OpenMP directly to a mix of OpenMP and FIR dialects. This would require that FIR co-exist with the OpenMP dialect.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"><br>
Next Steps<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Address feedback provided after the presentation. And reach an agreement on a plan<br>
-> Design a minimum viable MLIR dialect and get community acceptance.<br>
-> Help with progressing the OpenMP IRBuilder.<br>
-> Implement the accepted plan. Implementation would follow a vertical plan (going construct by construct).<o:p></o:p></span></p>
</div>
<blockquote style="margin-left:30.0pt;margin-top:5.0pt;margin-right:0in;margin-bottom:5.0pt">
<div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Represent construct in OpenMP MLIR<o:p></o:p></span></p>
</div>
</div>
<div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Refactor the code for the construct in OpenMP IRBuilder<o:p></o:p></span></p>
</div>
</div>
<div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Set up the translation library for OpenMP in MLIR to call the IRBuilder<o:p></o:p></span></p>
</div>
</div>
<div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Set up the transformation from the frontend to OpenMP MLIR for this construct<o:p></o:p></span></p>
</div>
</div>
</blockquote>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"> <o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Feedback (during the call):<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Johaness agrees with this proposed plan (Plan 4) and does not see the ties to LLVM as being a disadvantage.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Hal Finkel informs that the OpenMP IRBuilder proposal does not have any opposition in the Clang community and hence that probably is not a major risk.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Feedback (other):<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Eric Schweitz: "I like the idea of adding OpenMP as its own dialect. I think the design should allow this dialect to coexist with FIR and other dialects. The dialect should be informed
by the specific optimizations you plan to perform on the OpenMP semantic level, of course." Would prefer to lower F18 AST to a mix of OpenMP and FIR dialects. And would like the FIR to have nothing to do with OpenMP.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">-> Steve Scalpone: "I think the design needs to be vetted against some of the scenarios that’ll be encountered when generating executable OpenMP code. I have no reason to doubt what you’ve
proposed will work but I do think it is important to consider how certain scenarios will be implemented.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">Some topics to consider:<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- How to implement loop collapse?<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- How to implement loop distribution?<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- How to implement simd?<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- Is an outliner needed? In MLIR, before, after? Model to reference shared variables?<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- How will target offload be implemented?<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">- Where will the OpenMP runtime API be exposed?"<br>
<br>
References<o:p></o:p></span></p>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">1. OpenMP MLIR dialect discussion.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"><a href="https://groups.google.com/a/tensorflow.org/forum/#!topic/mlir/4Aj_eawdHiw" moz-do-not-send="true">https://groups.google.com/a/tensorflow.org/forum/#!topic/mlir/4Aj_eawdHiw</a><br>
2. Johaness’ OpenMP IRBuilder proposal.<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"><a href="http://lists.flang-compiler.org/pipermail/flang-dev_lists.flang-compiler.org/2019-May/000197.html" moz-do-not-send="true">http://lists.flang-compiler.org/pipermail/flang-dev_lists.flang-compiler.org/2019-May/000197.html</a><br>
3. MLIR<o:p></o:p></span></p>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black"><a href="https://github.com/tensorflow/mlir" moz-do-not-send="true">https://github.com/tensorflow/mlir</a><br>
<br>
Thanks,<br>
Kiran<o:p></o:p></span></p>
</div>
</div>
</div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and
do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
<o:p></o:p></span></p>
<div>
<div class="MsoNormal" style="text-align:center" align="center"><span style="font-size:12.0pt;color:black">
<hr align="center" width="100%" size="2">
</span></div>
</div>
<div>
<p class="xxxxmsonormal"><span style="font-size:12.0pt;color:black">This email message is for the sole use of the intended recipient(s) and may contain confidential information. Any unauthorized review, use, disclosure or distribution is prohibited. If you
are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message.
<o:p></o:p></span></p>
</div>
<div>
<div class="MsoNormal" style="text-align:center" align="center"><span style="font-size:12.0pt;color:black">
<hr align="center" width="100%" size="2">
</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<p class="MsoNormal">IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person,
use it for any purpose, or store or copy the information in any medium. Thank you.
<o:p></o:p></p>
</div>
<p class="MsoNormal">IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person,
use it for any purpose, or store or copy the information in any medium. Thank you.
<o:p></o:p></p>
</div>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<pre class="moz-quote-pre" wrap="">_______________________________________________
flang-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:flang-dev@lists.llvm.org">flang-dev@lists.llvm.org</a>
<a class="moz-txt-link-freetext" href="https://lists.llvm.org/cgi-bin/mailman/listinfo/flang-dev">https://lists.llvm.org/cgi-bin/mailman/listinfo/flang-dev</a>
</pre>
</blockquote>
<pre class="moz-signature" cols="72">--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory</pre>
</body>
</html>