• Tidak ada hasil yang ditemukan

IMOPSlides-2021 copy - CSE-IITM - IIT Madras

N/A
N/A
Protected

Academic year: 2024

Membagikan "IMOPSlides-2021 copy - CSE-IITM - IIT Madras"

Copied!
67
0
0

Teks penuh

(1)

IMOP

I IT M adras O penM P Compiler Framework

A tutorial at CGO 2021 on

PACE Lab

Dept of CS&E, IIT Madras

Aman Nougrahiya V. Krishna Nandivada

February 27th, 2021

(2)

bit.ly/imop-iitm

A World of Compiler Frameworks

Famous compiler frameworks, with diverse compilation goals[1].

Wow, so many! These must be enough..

New Compiler Framework!

We don’t need any

(3)

bit.ly/imop-iitm

IMOP

Welcome to this CGO Tutorial on a New Compiler Framework!

Okay, but… WHY?!

(4)

bit.ly/imop-iitm

WHY?!

Major issues with existing compiler frameworks for OpenMP :

Most of them (like GCC and LLVM) work at low-level of program representations.

OpenMP is expressed and better understood at higher-level representations.

Originally built for serial programs, hence their implementations of analyses and transformations may yield incorrect results under

parallel semantics, as

-

static analyses do not assume multiple threads of execution, and

-

inter-task/inter-thread data flow is not modelled.

Further, significant manual efforts are required by the compiler writers to keep the compiler stable (or, consistent) in response to program changes.

Do the current ones not suffice?

(5)

bit.ly/imop-iitm

IMOP

To address these issues, we have developed

Pro-automation

Source-to-source OpenMP C

Open-source

Key Guiding Principle:

Ease the task of implementing various analyses and

transformation tools for (OpenMP) C programs, by

(6)

bit.ly/imop-iitm

Pedagogical Usage of IMOP

IMOP in a graduate-level course assignment

In a graduate-level course, “Program Analysis, EVEN 16” (offered by Dr.

Rupesh Nasre, Dept of CSE, IIT Madras), we used IMOP as an alternative framework for LLVM in one of the assignments.

In the assignment, students had to remove unsafe pointer dereferences from the program.

Total 10 out of 25 students used IMOP; rest used LLVM.

None of the students had more than 1 lecture-hour exposure to IMOP in the past; all students had used LLVM for previous 3 assignments in that course.

Average marks obtained by students who used IMOP were comparable to (rather, negligibly higher than) that of students who used LLVM.

Submission-size in IMOP ranged between 30-100 LOC; in contrast, for LLVM, the range was 350-550 LOC.

(7)

bit.ly/imop-iitm

Pedagogical Usage of IMOP

Feedback scores from the students

Average Ratings from the Survey:

• On readability of code written in IMOP versus that of LLVM: 4.14/5

• On ease of coding in IMOP over that in LLVM: 4.57/5

• On ease of debugging in IMOP over that in LLVM: 4/5

We conducted a survey, asking students about their experiences working with IMOP.

Total 7 out of 10 students took the survey.

(8)

bit.ly/imop-iitm

Pedagogical Usage of IMOP

Feedback comments from the students.

Following were the comments given by 4 out of 10 students who used IMOP:

✦ “…I’d say working with it is less difficult than LLVM…"

✦ “...the ratio of how much one can achieve using the framework vs

initial overhead of learning it, seems to be much higher for IMOP from my experience…"

✦ “...the nested CFG structure allowed easy traversals of the CFG…"

✦ “...I think the main aim of IMOP to make writing compiler passes

very easy has been achieved compared to LLVM...IMOP increases

developer productivity.”

(9)

bit.ly/imop-iitm

IMOP in Published Projects

(1) Jyothi Krishna Viswakaran Sreelatha, and Shankar Balachandran. IIT Madras.

Compiler Enhanced Scheduling for OpenMP for Heterogeneous

Multiprocessors. In Workshop on Energy Efficiency with Heterogeneous Computing (EEHCO 2016). ACM, Prague, Czech Republic.

(2) Jyothi Krishna Viswakaran Sreelatha, Shankar Balachandran, and Rupesh Nasre.

IIT Madras. CHOAMP: Cost Based Hardware Optimization for Asymmetric Multicore Processors. IEEE Transactions on Multi-Scale Computing Systems 4, 2 (TMSCS 2018), 163-176.

(3) Jyothi Krishna Viswakaran Sreelatha, and Rupesh Nasre. IIT Madras. Optimizing Graph Algorithms in Asymmetric Multicore Processors. IEEE Transactions on CAD of Integrated Circuits and Systems 37, 11 (2018), 2673-2684.

(4) Gnanambikai Krishnakumar, Alekhya Reddy Kommuru, Chester Rebeiro. IIT Madras. ALEXIA: A Processor with Light Weight Extensions for Memory Safety. ACM Transactions on Embedded Computing Systems, (2019).

IMOP has been used in the following published works, by other research groups:

(10)

bit.ly/imop-iitm

Tutorial Objectives

By the end of this tutorial, the participants shall be able to…

• Use IMOP to prototype program analyses/optimizations discussed in this tutorial, and

• Consider IMOP for fast prototyping of their custom program

analyses/optimizations.

(11)

bit.ly/imop-iitm

Tutorial Objectives

In this tutorial, the participants will…

Understand (some of) the key design principles and implementation details of IMOP.

Write

- a loop-unrolling pass for while-loops in just about 8 lines of code;

- a code-instrumentation pass for adding write barriers for a variable in just about 12 lines of code;

- an OpenMP optimization pass, in about 30 lines of code, for

simple removal of redundant OpenMP barriers; and much more.

(12)

bit.ly/imop-iitm

Let us begin, then..

(13)

https://bit.ly/imop-vnc

Hands-On Session #0

Testing the setup

We have already created ready-to-use virtual machines for your use during this tutorial.

(A) Setup IMOP.


Kindly read the instructions at: https://bit.ly/imop-vnc

(B) Run the project Demo0 to test the setup.

(14)

bit.ly/imop-iitm

Parser

1 while (x < 11) { 2 printf("%d", x);

3 x++;

4 }

Input Program

Grammar

WhileStatement ::== <WHILE> "(" Expression ")" Statement Statement :== ExpressionStatement | CompoundStatement

| IfStatement | . . .

Abstract Syntax Tree

WhileStatement

<WHILE>

"("

Expression

")"

Statement

x "<" 11

Abstract Syntax Tree

(15)

bit.ly/imop-iitm

Grammar and Parser of IMOP

• IMOP accepts programs written in standard C (ANSI), and (almost all of) OpenMP 4.0.


• Can handle all standard benchmarks— 


NPB, SPECOMP, Sequoia, etc. 


• IMOP is itself written in Java.


• Parser of IMOP has been created using JavaCC/JTB

[3]

.

(16)

bit.ly/imop-iitm

Invoking the parser

Abstract Syntax Tree

WhileStatement

<WHILE>

"("

Expression

")"

Statement

x "<" 11 Program.parseNormalizeInput(args);

Input Program

1 while (x < 11) { 2 printf("%d", x);

3 x++;

4 }

(17)

bit.ly/imop-iitm

public static void main(String[] args) {

}

Invoking the parser

Preprocessed OpenMP C file

Program.parseNormalizeInput(args);

Command-line arguments

3

$ java imop.Main -f foo.i

2

$ gcc -P -E foo.c -o foo.i 1

4

Stores root of the parsed AST in Program.root

(18)

bit.ly/imop-iitm

1 public static void main(String[] args) { 2

3

4 // Print the program to the terminal.

5 System.out.println(Program.getRoot());

6

7 // Print to a new file named foo-f1.i 8 DumpSnapshot.dumpRoot("f1");

9 }

Output Program

1 while (x < 11) { 2 printf("%d", x);

3 x++;

4 }

Print my program!

Abstract Syntax Tree

Program.parseNormalizeInput(args);

WhileStatement

<WHILE>

"("

Expression

")"

Statement

x "<" 11

(19)

bit.ly/imop-iitm

Information Objects

With each important AST node, we maintain a specific subclass of NodeInfo .

- Contains node-specific information and operations.

- Obtained using getInfo( ) invocation on the node.

n1

int x = y + 3;

n2

n1.getInfo().getInitializer() n2

Declaration

DeclarationInfo

Initializer

(20)

bit.ly/imop-iitm

Information Objects

With each important AST node, we maintain a specific subclass of NodeInfo .

- Contains node-specific information and operations.

- Obtained using getInfo( ) invocation on the node.

n1.getInfo().unrollLoop(1);

1 while (x < 11) { 2 printf("%d", x);

3 x++;

4 if (!(x < 11)) break;

5 printf("%d", x);

6 x++;

7 } WhileStatement

WhileStatementInfo 1 while (x < 11) { n1

2 printf("%d", x);

3 x++;

4 }

(21)

bit.ly/imop-iitm

Simple depth-first traversals over the AST.

- Too low-level; not recommended.

Better alternative: Use higher-level query functions, such as:

Get all functions of a program

Get statement with label L within a node n

Get all nodes of some type (say if-statement)

Querying the AST

Misc.getInheritedEnclosee(n, IfStatement.class) Program.getRoot().getInfo().

getAllFunctionDefinitions()

n.getInfo().getStatementWithLabel("L")

(22)

bit.ly/imop-iitm

Example: Querying the AST

// Print all statements having the given label.

public static void demo1(String label) {

for (FunctionDefinition func : Program.getRoot().getInfo().

getAllFunctionDefinitions()) {

Statement stmt = func.getInfo().getStatementWithLabel(label);

if (stmt != null) System.out.println(stmt);

}

System.exit(0);

}

Suggestion:

Look into the other methods present in various subclasses of NodeInfo.

Iterate over all the function definitions.

1

2

Get statement with the given label.

Print the statement.

3

(23)

https://bit.ly/imop-vnc

Hands-On Session #1

Working with the AST

(A) Parse a sample program using IMOP.

(B) From the generated AST, print the program to a file/terminal.

Note that IMOP performs some simplifications.

(C) Find and print all those statements that have a given label.

(D) Invoke loop unrolling on the given while-statement, and print.

(24)

bit.ly/imop-iitm

Control-flow graphs (CFGs) — approximations of how control would flow among executable nodes of a function in runtime.

Useful for performing static analyses.

Unlike traditional frameworks, IMOP uses nested CFGs.

- Resembles higher-level representation of (OpenMP) C programs.

- Useful in modeling scope information (used by OpenMP clauses).

Control-Flow Graphs

(25)

bit.ly/imop-iitm

Begin FunctionDefinition

CompoundStatement

WhileStatement

int x = 0;

x > 10

x++;

Begin

End

End Begin

Example CFG

1 int main() { 2 int x = 0;

3 while (x > 10) x++;

4 }

Do not contain nested CFG

Leaf nodes

Contain other CFG nodes.

Entry/Exit points denoted by special nodes: Begin/End.

Define control flow as per the semantics of OpenMP and C.

Non-leaf nodes

(26)

bit.ly/imop-iitm

Types of nodes in Nested CFGs

IMOP models two types of CFG nodes:

- Non-leaf nodes, corresponding to nesting constructs of C and OpenMP, such as

FunctionDefinition, WhileStatement, and CriticalConstruct.

- Leaf nodes, for other executable nodes in the program, such as,

ExpressionStatement, GotoStatement, and BarrierDirective.

(27)

bit.ly/imop-iitm

Example CFG

• IMOP automatically creates CFG upon parsing.

• A DOT-file representation of the CFG can be dumped at output-dump/

foonestedDotGraph.gv

1 int main() { 2 int x = 0;

3 while (x > 10) x++;

4 }

Begin FunctionDefinition

CompoundStatement

WhileStatement

int x = 0;

x > 10

x++;

Begin

End

End Begin

(28)

bit.ly/imop-iitm

x > 10

WhileStatement

End x++;

Begin

n

CompoundStatement

int x = 0;

Begin

End

c1

c2

c3

Intra-procedural traversals

node.getInfo().getCFGInfo().

getSuccessors()

n c1 c2

Successors of a node

node.getInfo().getCFGInfo().

getPredecessors()

n c3 c2

Predecessors of a node

Traversals on CFG

(29)

bit.ly/imop-iitm

Different parts of a non-leaf node, such as body and

predicate of various

constructs, are termed as its CFG components.

Note: Each CFG component is a CFG node.

Begin

WhileStatement

x > 10

End x++;

1

2

4 3

Four CFG components of a WhileStatement Begin node.

Predicate node.

Body node.

End node.

1 2 3 4

CFG Components

(30)

bit.ly/imop-iitm

CFG components of a non-leaf node can be obtained using pre-defined methods in its CFGInfo object.

Get predicate of a

while-statement whileStmt.getInfo().getCFGInfo().getPredicate()

Get elements of a compound-statement

compStmt.getInfo().

getCFGInfo().getElementList()

Get false branch of an

if-statement ifStmt.getInfo().getCFGInfo().getElseBody()

Querying CFG Components

(31)

bit.ly/imop-iitm

Example: Querying the CFG Components

// Query CFG components

public static void demo2() {

for (WhileStatement whileStmt : Misc.getInheritedEnclosee(Program.getRoot(), WhileStatement.class)) {

System.out.println(whileStmt.getInfo().getCFGInfo().getPredicate());

}

for (IfStatement ifStmt : Misc.getInheritedEnclosee(Program.getRoot(), IfStatement.class)) {

if (!ifStmt.getInfo().getCFGInfo().hasElseBody()) { System.out.println(ifStmt);

} }

} Print predicate of a while-statement.

1

Check whether an else-branch exists for an if-statement.

2

(32)

https://bit.ly/imop-vnc

Note: Detailed walkthrough is present in the provided handouts.

Hands-On Session #2

Working with CFG Components and Traversals

(A) Print predicate and body (separately) of each while-statement in the program.

(B) Print successors of those if-statements which do not have an

else-body.

(33)

bit.ly/imop-iitm

During parsing, IMOP automatically simplifies each call-site to one of the two forms:

foo(s

1

, s

2

, ..., s

n

);

where,

foo is a function designator, x is a temporary, and

s

1

, s

2

, ..., s

n

are compile-time constants or temporaries.

• The call-site is a non-leaf CFG node of type CallStatement.

Call Graphs

Call Statements

x = foo(s

1

, s

2

, ..., s

n

);

(34)

bit.ly/imop-iitm

Structure of a CallStatement

Begin

End

CallStatement

PreCallNode

PostCallNode

Call Graphs

There are two components in a CallStatement:

PreCallNode

Denotes argument reads; after this node, control flows to possible target functions.

PostCallNode

Control flows in from possible targets into this node; it denotes writing of the returned value to the temporary (optional).

Begin

End

FunctionDefinition

foo()

x = foo(s

1

, s

2

, ..., s

n

);

(35)

bit.ly/imop-iitm

Begin

CallStatement

PreCallNode

PostCallNode

Traversals on Call Graphs

Begin

FunctionDefinition c1

n1

n2

node.getInfo().getCFGInfo().

getInterProceduralSuccessors()

n1

Successors of a node

n2

c1

c2 n2

node.getInfo().getCFGInfo().

getInterProceduralPredecessors()

n2 c2

Predecessors of a node

n1

n1

c1

(36)

bit.ly/imop-iitm

Queries on Call Graphs

To obtain all CallStatement’s in a node:

Misc.getInheritedEnclosee(node, CallStatement.class))

To obtain all CallStatement ’s that may target a function:

func.getInfo().getCallersOfThis()

To obtain all target FunctionDefinition ’s of a CallStatement:

callStmt.getInfo().getCalledDefinitions()

To obtain arguments of a CallStatement :

callStmt.getPreCallNode().getArgumentList()

To check if a function is recursive:

func.getInfo().isRecursive()

(37)

https://bit.ly/imop-vnc

Hands-On Session #3

Working with Call Graphs (CGs)

(A) Print all call-sites present lexically within a given function.

(B) Print all call-sites in the program that may have a given function as their target.

(C) For a given call-statement: (i) print its target function(s), and (ii) print all its arguments.

(D) Test whether a given method is recursive.

(38)

bit.ly/imop-iitm

Scopes, Symbols, and Types

There are two kinds of symbols — (i) variables, and (ii) functions.

Each symbol has following key attributes: (i) a name, (ii) a type, (iii) a declaration, and (iv) a scope that declares the symbol.

IMOP models 3 kinds of scopes —

- global ( TranslationUnit ), function ( FunctionDefinition ), and local ( CompoundStatement ).

Each scope maintains a symbol table for symbols defined in it.

scope.getInfo().getSymbolTable()

(39)

bit.ly/imop-iitm

Working with Symbols

Misc.getSymbolEntry(“x”, )n3

.getInfo().getDeclaredSymbol()

n

“x” int Scopeif n2

Symbol sx

getName() getType()

getDefiningScope()

getDeclaringNode()

int foo() {

float x = 0.1;

if (x == 0) { int x = 10;

... y = 10 + x;

bar(x + y);

} }

n3

n2

n1

(40)

https://bit.ly/imop-vnc

Note: Detailed walkthrough is present in the provided handouts.

Hands-On Session #4

On Scopes, Symbols, and Types

(A) Print the names and types of symbols declared in a given function.

(B) Print the scopes for each argument passed to a given call-

statement.

(41)

bit.ly/imop-iitm

Memory Abstractions

There are two main components of the data environment, from the perspective of static analyses: (i) stack, and (ii) heap.

In IMOP, we term each element of these abstract components as Cell.

- A stack-cell corresponding to a scalar is denoted by its Symbol.

- For each syntactic heap-allocation site, we model a single HeapCell.

For efficiency, IMOP also maintains a single fixed GenericCell ,

which is used to model the universal set of cells.

(42)

bit.ly/imop-iitm

Cell Accesses in a Node

For each leaf/non-leaf CFG node, the list of cells that may be

accessed, read, and written, by that node can be obtained using

int main() {

int *a, b = 0;

int c = 10;

a = &b;

*a = 10 + c++;

}

n1

node.getInfo().getReads()

n1

{a, c}

node.getInfo().getWrites()

n1

{b, c}

node.getInfo().getAccesses()

n1

{a, b, c}

(43)

https://bit.ly/imop-vnc

Hands-On Session #5

Working with the Memory Abstractions

(A) Write a pass that prints the set of cells (read and/or written) in a given expression-statement (say, with label “ thisStmt ”).

(B) Write a pass that prints all those expression-statements

which may write to a variable with given name (“thisVar”).

(C) Write a pass that prints the kind of data-dependences (RAW, WAR, or WAW), if any, that given two statements (with labels

“ l1 ” and “ l2 ”) may have.

(44)

bit.ly/imop-iitm

Creating New Code Snippets

Creation of new snippets of code during compiler passes is quite common.

e.g., creation of code snippets to be inserted in the program for instrumentation purposes.

In almost all standard compiler frameworks, such as GCC, LLVM, Cetus, etc., compiler writers need to create the AST denoting the snippet, manually!

IMOP utilizes the underlying parser to automatically create the AST for requested snippet using:

-

string of the snippet to be created,

-

type of the non-terminal at the root of the snippet AST.
(45)

bit.ly/imop-iitm

Creating Snippets: Traditional Way

a[i] = 0;

a[i]

ArrayAccess

0

IntegerLiteral

a

Identifier

i

Expression

new ArrayAccess(.., ..)

new AssignmentExpression(.., ..)

(46)

bit.ly/imop-iitm

Creating Snippets in IMOP

a[i] = 0;

FrontEnd.parseAndNormalize(“a[i] = 0;”, Statement.class);

In IMOP, given the string-equivalent of a snippet to be generated, the actual AST can be obtained in a single step, as shown above.

(47)

bit.ly/imop-iitm

Creating an unrolled loop

Code Snippet Generation: An example

// Print the loop-unrolled form of a while-statement.

public void printUnrolledLoop(WhileStatement loop) {

WhileStatementCFGInfo cfgInfo = loop.getInfo().getCFGInfo();

String snippetStr = “while (” + cfgInfo.getPredicate() + “) {”

+ cfgInfo.getBody() + "if (!("

+ cfgInfo.getPredicate() + ")) {break;}"

+ cfgInfo.getBody() + "}";

Statement newBody = FrontEnd.parseAndNormalize(snippetStr, Statement.class);

CompoundStatementNormalizer.removeExtraScopes(loop);

System.out.println(newBody);

}

Invoke the parser to create AST of the new snippet.

2

Optionally, remove extra { } from the generated code.

3

(48)

bit.ly/imop-iitm

Let us revise the notion of CFG Components.

Different parts of a non-leaf node, such as body and predicate of

various constructs, are termed as its CFG components.

Elementary transformations of a non-leaf node are those which can add/remove/replace its CFG

components. 


For example, one that replaces the predicate of a while-loop.

Begin

WhileStatement

x > 10

End x++;

1

2

4 3

Four CFG components of a WhileStatement Begin node. Predicate node.

Body node. End node.

1 2

3 4

Elementary Transformations

whileSmt.getInfo().getCFGInfo().setPredicate(newPred);

(49)

bit.ly/imop-iitm

Example: Simple Transformations

// Add empty else body to the if-statement if none exists.

public static void addEmptyElse(IfStatement ifStmt) {

IfStatementCFGInfo cfgInfo = ifStmt.getInfo().getCFGInfo();

if (cfgInfo.hasElseBody()) { return;

}

Statement emptyElse = FrontEnd.parseAndNormalize("{}", Statement.class);

cfgInfo.setElseBody(emptyElse);

}

(50)

https://bit.ly/imop-vnc

Note: Detailed walkthrough is present in the provided handouts.

Hands-On Session #6

Simple Program Transformations

(A) Write a pass to perform loop unrolling for while loops.

(B) Write a pass that translates a do-while loop to a while loop.

(Assume that no jump statements exist in the body.)

(51)

bit.ly/imop-iitm

Higher-level CFG transformations

Assume that we wish to add a read

barrier for each read of parameter rb of foo().

There are 3 key tasks involved:

Creation of snippet for read barrier;

simple and straightforward.

Detection of nodes that may be

reading from the parameter rb; this too is simple.

Performing the actual instrumention;

where shall we add the code?

1 int foo(int rb) { 2 int x = rb;

3 while (x < 10 + rb) { 4 x += 2;

5 if (x == 4) { 6 l1: continue;

7 } else {

8 if (x == 5) goto l1;

9 else {x--; continue;}

10 } 11 }

12 }

In this example

There are two reads for rb -- at Line 2 and 3.

For Line 2, we can simply add the read barrier code immediately before the line.

But for Line #3, we need to insert read barriers at 3 positions!

(52)

bit.ly/imop-iitm

Higher-level CFG transformations

1 int foo(int rb) { 2 int x = rb;

3 while (x < 10 + rb) { 4 x += 2;

5 if (x == 4) { 6 l1: continue;

7 } else {

8 if (x == 5) goto l1;

9 else {x--; continue;}

10 } 11 }

12 }

Handling of such corner cases can be

difficult, repetitive, time-consuming, and error-prone.

IMOP resolves this issue by letting the programmer use one of the following five CFG transformations:

1. Insert immediate predecessor.

2. Insert immediate successor.

3. Insert on the edge.

4. Node remover.

5. Node replacer.

These transformations hide the syntactic forms/placements of nodes involved in the process.

In our example, for Line #3, we will require just one invocation of

InsertImmediatePredecessor to (automatically) handle all the possible cases.

InsertImmediatePredecessor.insert(node, instrumentationCode);

(53)

https://bit.ly/imop-vnc

Hands-On Session #7

Using Higher-Level CFG Transformations

Write barrier: Write a pass that instruments a program such that immediately before write to a scalar variable thisVar at runtime, a notification is displayed.

a) Detect all those leaf CFG nodes that may write to thisVar.

b) Create a notification message as a printf() statement.

c) Insert the newly created statement immediately before the

detected node.

(54)

bit.ly/imop-iitm

OpenMP

IMOP has been written with OpenMP semantics in mind, since as early as its design phase.

All program abstractions of IMOP preserve OpenMP semantics.

For data-flow analyses, IMOP provides a framework where

compiler writer needs to provide only that data which is required for serial C programs. OpenMP semantics are handled internally by IMOP.

Many new program abstractions for parallelism, such as

concurrency analysis, and LockSet analysis, are already present

in IMOP.

(55)

bit.ly/imop-iitm

Inter-Task Communications

x = 3;

flush

flush

print x;

1

2

3

4

OpenMP API specifies that following four events are necessary for a

communication to happen between two threads:

(i) T1 writes to a shared location, (ii) T1 flushes that location,

(iii) T2 flushes that location, and

(iv) T2 reads from that location.

We model these communications in IMOP by creating edges betweeen those (implicit/explicit) flushes that may observe this pattern.

T1 T2

(56)

bit.ly/imop-iitm

Concurrency Analysis

Barrier directives are program points where threads of a team wait for each other, before any thread is allowed to proceed.

A phase is defined as a collection of statements from one set of barriers to the next set of barriers.

Two statements can never run in parallel if they do not share any common phase.

This observation helps improve the precision/efficiency of static analyses of parallel programs using phase (or concurrency) analysis.

• IMOP provides various interfaces that can be used for answering

related queries.

(57)

bit.ly/imop-iitm

Concurrency Analysis

To obtain all the static phases that are present in a ParallelConstruct.

parCons.getInfo().getConnectedPhases()

To obtain the set of statements that may belong to a phase.

ph.getNodeSet()

To obtain the set of barriers that may end a phase.

ph.getEndPoints()

To obtain all the phases in which a statement may run.

stmt.getInfo().getNodePhaseInfo().getPhaseSet()

A glimpse into the interface

(58)

https://bit.ly/imop-vnc

Note: Detailed walkthrough is present in the provided handouts.

Hands-On Session #8

Analyzing Concurrency in OpenMP programs

(A) Print the number of static phases in every parallel-construct.

(B) Print the highest number of statements in any static phase in the system.

(C) Print the set of all those CFG leaf nodes that may run in

parallel with the given expression statement.

(59)

https://bit.ly/imop-vnc

Hands-On Session #9

Project: Remove redundant barriers.

Check if a barrier-directive is required to preserve dependeces among phases across it. If not, then delete the barrier.

a) For any given barrier, get the set of phases that it may end, and the set of phases that may start after it.

b) For each pair of phases from the sets in the last step, see if the pair conflicts, i.e. see if there exists any conflicting accesses

between two phases of the pair.

c) If no conflicts are found across a barrier, remove it from the

program.

(60)

Other Key Features of IMOP

(61)

bit.ly/imop-iitm

Data-Flow Analysis

Iterative data-flow analysis is an important class of compiler passes.

IMOP provides a set of generic inter-thread inter-procedural flow- sensitive data-flow analysis passes.

For every existing and new instantiations of these generic passes, following guarantees are automatically ensured:

- They respect the OpenMP semantics.

- Their internal states are self-stable, in response to any existing or new program changes.

Generic Iterative Data-Flow Passes

(62)

bit.ly/imop-iitm

Data-Flow Analysis

To instantiate the generic passes, compiler writers need to provide only the following information:

- Structure of the flow-facts;

- Value of the TOP element of lattice;

- Meet operation on two flow-facts;

- Notion of equality of two flow-facts; and

- Transfer function for various kinds of CFG node.

No additional information is needed from the compiler writers to ensure self-stabilization and adherence to OpenMP semantics.

Various instantiations of the generic passes exist in IMOP — points-to, reaching definitions, liveness, dominator, lockset, copy propagation, etc.

Instantiating Generic IDFA Passes

(63)

bit.ly/imop-iitm

Need for Compiler Stabilization

Optimization passes involve program analyses and transformations.

Transformations rely on program analyses for correctness, efficiency, precision, etc.

In general, mainstream compilers do not automatically update program abstractions (analyses and representations) in response to program

transformations — this can lead to incorrect application of downstream passes!

To resolve this challenge, compiler writers need to manually address these questions:

(a) What abstractions need stabilization in response to transformations?

(b) How to stabilize an abstraction?

(c) Where to write the stabilization code?

(64)

bit.ly/imop-iitm

Tackling Stabilization Behind the Scene

IMOP: a Self-Stabilizing Compiler

In IMOP, compiler writers need not write any code to ensure self-stabilization while adding any

- new transformations, and/or

- any new data-flow passes.

For other kinds of abstractions, compiler writers need to

handle only a subset of stabilization tasks themselves.

(65)

bit.ly/imop-iitm

Other interesting features of IMOP

Lambda-based generic graph collectors.

- Set of functionalities that automate the graph-traversal mechanism for frequently-occurring traversal patterns.

Interface for Z3 SMT solver (by Microsoft).

- Many analyses can be represented as a system of constraints.

- IMOP can automatically generate underlying system of inequations, given one or more seed constraint(s).

- It then internally invokes Z3 SMT solver to return a conservative analysis result.

- Used for auto-parallelization, dead-code removal, adding field-

(66)

bit.ly/imop-iitm

How far have we walked so far?

Used the parser of IMOP, for a simple pretty-printing pass; perform simple queries on the AST.

Understood the nested control-flow graphs (CFGs) and call graphs (CGs) of IMOP; perform traversals and queries on them.

Worked with scopes, symbols, and types.

Learnt how to query various memory abstractions maintained by IMOP.

Created new code snippets, and perform simple transformations on the program.

Performed higher-level (semantic-level) transformations, hiding the sytnactic complexities of C and OpenMP.

Utilized the existing concurrency analysis in IMOP.

Taken a glimpse into some other important features, and use-cases, of IMOP.
(67)

bit.ly/imop-iitm

Miles To Go

IMOP is a source-to-source compiler framework, for OpenMP C programs. 


In this tutorial, we have learnt how to use some of its key features.

Developer of IMOP : Aman Nougrahiya

Project Advisor : V. Krishna Nandivada


Total size of IMOP : ∼154 kLOC (about ∼127 kLOC coded manually; rest generated by JavaCC/JTB).

Release date : 22-February-2020 (during CGO 2020).

Official website : h#ps://bit.ly/imop-iitm

Github public repository: h#ps://bit.ly/imop-compiler

What next?

For further development of IMOP (such as to add support for missing

OpenMP constructs/directives), YOUR contributions would really matter:

Kindly try out IMOP, contribute towards enhancing its quality and capabilities, and let us know your suggestions for improvements.

Referensi

Dokumen terkait