Comments (7)
Solution 2:
For outlining in OpenMP, ROSE enables useParameterWrapper
and useStructureWrapper
to include the variables into a data structure and pass it to the outlined function.
Another flag useNewFile
is to store the outlined function in a new file. However, ROSE doesn't support using useNewFile
and useStructureWrapper
at the same time. Otherwise, it will complain that Outliner::generateParameterStructureDeclaration() separated file case is not yet handled.
The source code that throws the error message is: https://github.com/passlab/rexompiler/blob/master/src/midend/programTransformation/astOutlining/Transform.cc#L140
It means solution 2 requires us to:
- either explore the details of the error and implements any missing feature in ROSE,
- or significantly change the workflow in omplowering to not using structure wrapper.
The OpenMP transformation for FORTRAN doesn't use useStructureWrapper
. It's possible that we borrow the same workflow to C/C++. However, there are much code in ROSE specifically for FORTRAN in omplowering, outliner, and so on. To do that, we have to change many original modules. It's probably not a good idea.
from rexompiler.
Solution 1:
So far, a new file with a given name could be created for the outlined function. However, it seems only the function SgNode itself is copied but not its full subtree.
The new file and the original one belong to the same SgProject. The unparsing will performed to a project so that the two files will be both unparsed.
Given a simple input:
#include <stdio.h>
int main (int argc, char** argv) {
int i = 1;
#pragma omp parallel if(i == 1)
{
#pragma omp single
printf("Test\n");
}
}
The regular transformed code is:
#include <stdio.h>
#include "rex_kmp.h"
static void OUT__1__5599__(int *__global_tid,int *__bound_tid,void *__out_argv);
int main(int argc,char **argv)
{
int __global_tid_value = __kmpc_global_thread_num(0);
int *__global_tid = &__global_tid_value;
int status = 0;
int i = 1;
if (i == 1)
__kmpc_fork_call(0,1,OUT__1__5599__,0);
else {
OUT__1__5599__(&( *__global_tid),0,0);
}
}
static void OUT__1__5599__(int *__global_tid,int *__bound_tid,void *__out_argv)
{
if (__kmpc_single(0, *__global_tid)) {
printf("Test\n");
__kmpc_end_single(0, *__global_tid);
}
__kmpc_barrier(0, *__global_tid);
}
The current implementation of solution 1 produces a separate file. The printf
line is missing here.
static void OUT__1__5599__(int *__global_tid,int *__bound_tid,void *__out_argv)
{
if (__kmpc_single(0, *__global_tid)) {
__kmpc_end_single(0, *__global_tid);
}
__kmpc_barrier(0, *__global_tid);
}
There are several problems:
The separated file also needs to includerex_kmp.h
.The modifierstatic
in the separated file should be removed.The modifierstatic
in the main file should be changed toextern
.The separated file should have the complete outlined function definition.The outlined function definition in the main file should be removed. Its SgNode may or may not be kept, but it shouldn't be unparsed for sure.- This simple case doesn't have a parameter structure, but we expect the structure will encounter a similar issue with the outlined function.
- Should we store all the outlined functions in one file and multiple files (one function per file)?
- Other headers and functions that the outlined function depends on should also be added to the new file.
There are several ROSE builder APIs that could be used to find a forward declaration.
Work-in-progress output
rose-compiler -rose:openmp:lowering -rose:skipfinalCompileStep foo.c
The main file rose_foo.c
:
#include <stdio.h>
#define N 1
#include "rex_kmp.h"
extern void OUT__1__5599__(int *__global_tid,int *__bound_tid,void *__out_argv);
int main(int argc,char **argv)
{
int __global_tid_value = __kmpc_global_thread_num(0);
int *__global_tid = &__global_tid_value;
int status = 0;
int i = 1;
if (i == 1)
__kmpc_fork_call(0,1,OUT__1__5599__,0);
else {
OUT__1__5599__(&( *__global_tid),0,0);
}
}
The new file having the outlined function definition rose_foo_lib.c
:
#include <stdio.h>
#define N 1
#include "rex_kmp.h"
int main(int ,char **);
void OUT__1__5599__(int *__global_tid,int *__bound_tid,void *__out_argv)
{
if (__kmpc_single(0, *__global_tid)) {
printf("Test\n");
__kmpc_end_single(0, *__global_tid);
}
__kmpc_barrier(0, *__global_tid);
}
from rexompiler.
@ouankou Thank you for explore this in details. I could not find the code I created before, more than 10 years ago. I vaguely recall that it will need a deepcopy of AST in order to duplicate the AST. Did you try sageInterface::deepCopyNode (const SgNode *subtree). We can ask Liao for details.
I am thinking of two options for files vs regions: 1) a new file for each outlined function, or 2) one file for all the outlined function. It seems both are ok for me. Considering that we will support offloading (CUDA GPU) and vectorization (simd instruction or intrinsics), we can have one file for each architecture (CPU, CUDA, simd) that includes the outlined function for all the regions of a file, or one file per outlined region per architecture.
With either option, there are some details that need to be handled for the new file to be compilable, e.g. for the signatures of several things:
- header include, we can copy the original include to the new file.
- typedef, extern, #define can all be copied to the new file.
- global variable needs to be added to the new file as extern-ed variable
- all the function used by the outlined function body needs to have correct function signature in the new file
- others (?). There might be other corner cases.
We can create a new header that include the above info and include this header in the file for the outline function, if we need to create several files for all the outline regions. This approach just simply copy all the signature definition of the original file. A better approach is just to extract the signature declaration of those symbols used in the outlined body, as well as the macro used.
from rexompiler.
@yanyh15 Yes, I used the similar API deepCopy
. I tried both and got the same full subtree. They are probably the same thing. Currently, the first 5 problems have been solved. I'm working on problem 7. For simple cases, it works fine. The function declarations are all copied to the new file and the two generated files can be compiled to get the correct executable.
However, I'm sure there will be issues for normal cases due to the points you listed. Additionally, since some ROSE APIs don't work in my code, there must be something wrong underneath. I'll wrap up the current implementation and push a commit. Then we can keep updating the design from there.
This is only an initial implementation to simply store the outlined function on CPU in a new file. In the meantime, I'll start to look at the target
transformation to see how to create a CUDA kernel properly. If that works, we can take your hand-wrtitten AXPY offloading code and create a complete prototype in REX compiler.
from rexompiler.
This is a general problem: how to split a file into multiple files. It is not an easy job if we need to do perfect because of the situation we need to consider:
1.
from rexompiler.
According to Dr. Liao, ROSE does keep all the definitions of global variables in the separate file having outlined functions. The compiler will complain that they are redeclared. We may need to manually scan those variables and mark them as extern declarations.
from rexompiler.
Issues:
There could be multiple issues when we create a new file to hold the outlined functions.
-
Global variables (commit 3a7c6cf)
The main file may have global variables. If they are static, they need to be copied. Otherwise, we have to set them to be extern without definition.
For example,int a = 1;
should beextern int a;
, butstatic int b = 2;
should be preserved as-is. -
Preprocessing macros
#define
(commit 3a7c6cf)
They should be copied exactly as-is because they are not shared across source files. -
Function declaration
Functions other than the outlined ones should only have the extern declaration in the new file if they are not static. Otherwise, they should be copied with the definition.
The outline functions should have the forward declaration in the new file in case they are calling each other.
In the main file, the outline functions only have the extern declaration there.
Solutions:
-
Generate a new header:
We may need to analyze the source code and move the portion required by the outline functions into a new header. Then both the main file and new file include this header. The drawback of this solution is that the original source code could be modified heavily and additional compiler analysis is required. -
Duplicate the required symbol signatures
We cherry-pick the used symbol signatures into the new file and set up the storage modifier accordingly. The details are described in the issues above.
Implementation:
Solution 2 is preferred. For its implementation, we follow the procedure:
- Duplicate the original source file.
- Remove the unnecessary definitions.
- Move the outlined functions and structures.
from rexompiler.
Related Issues (20)
- [Fortran] Incorrect unparsing for omp parallel HOT 2
- [Fortran]: The generated file for outlined function is empty HOT 1
- Move getFile and getStatement call of src/roseSupport/transformationSupport.h/C to SageInterface
- Warning of yacc for omp_exprparser_parser.yy HOT 1
- Warning from not following automake naming structure
- Remove src/frontend/SageIII/astFromString HOT 1
- Add directive-name-modifer to all OpenMP clauses
- Lost the declaration of omp loop control variable during transformation. HOT 1
- Incorrect outlining for C++ OpenMP code HOT 1
- command line processing: not able to report unrecognized command line option
- Reduction clause bug HOT 3
- Change the sage calss of OpenMP clause
- Reconsider parameter passing in outlined function
- Scoping concern about outlining an OpenMP loop
- deBOOST: Removing BOOST dependency HOT 1
- deSawyer: removing the dependency on Sawyer library and clean up utility HOT 5
- Data sharing in dynamic parallelism
- Cleanup and use the new MLOG_* message and logging utilities HOT 1
- Refactoring or removing enum stringify HOT 2
- Optimize transformation of firstprivate clause in OpenMP GPU offloading HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rexompiler.