Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
2
2022fall-Compiler_CMinus
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李晓奇
2022fall-Compiler_CMinus
Commits
b1f2b21d
Commit
b1f2b21d
authored
Dec 05, 2022
by
李晓奇
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
finish part
parent
f26d91aa
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
160 additions
and
110 deletions
+160
-110
.gitignore
.gitignore
+1
-0
include/optimization/GVN.h
include/optimization/GVN.h
+21
-10
src/optimization/GVN.cpp
src/optimization/GVN.cpp
+131
-100
tests/4-ir-opt/testcases/GVN/functional/clear.sh
tests/4-ir-opt/testcases/GVN/functional/clear.sh
+4
-0
tests/4-ir-opt/testcases/GVN/performance/clear.sh
tests/4-ir-opt/testcases/GVN/performance/clear.sh
+3
-0
No files found.
.gitignore
View file @
b1f2b21d
...
...
@@ -2,6 +2,7 @@ build
Documentations/1-parser/*.pdf
compile_commands.json
.cache
.vscode
todo.txt
tmp.cminus
include/optimization/GVN.h
View file @
b1f2b21d
...
...
@@ -204,13 +204,15 @@ class UniqueExpression : public Expression {
}
virtual
std
::
string
print
()
{
return
"(UNIQUE "
+
instr_
->
print
()
+
")"
;
}
bool
equiv
(
const
UniqueExpression
*
other
)
const
{
return
false
;
}
bool
equiv
(
const
UniqueExpression
*
other
)
const
{
return
instr_
==
other
->
instr_
;
}
UniqueExpression
(
Instruction
*
instr
)
:
Expression
(
e_unique
),
instr_
(
instr
)
{}
private:
std
::
shared_ptr
<
Instruction
>
instr_
;
Instruction
*
instr_
;
};
}
// namespace GVNExpression
...
...
@@ -277,7 +279,7 @@ class GVN : public Pass {
BasicBlock
*
bb
);
std
::
shared_ptr
<
GVNExpression
::
Expression
>
valueExpr
(
Instruction
*
instr
,
partitions
*
part
=
nullptr
);
const
partitions
&
part
);
std
::
shared_ptr
<
GVNExpression
::
Expression
>
getVN
(
const
partitions
&
pout
,
std
::
shared_ptr
<
GVNExpression
::
Expression
>
ve
);
...
...
@@ -293,11 +295,6 @@ class GVN : public Pass {
return
std
::
make_shared
<
CongruenceClass
>
(
index
);
}
// self add
//
std
::
uint64_t
new_number
()
{
return
next_value_number_
++
;
}
static
int
pretend_copy_stmt
(
Instruction
*
inst
,
BasicBlock
*
bb
);
private:
bool
dump_json_
;
std
::
uint64_t
next_value_number_
=
1
;
...
...
@@ -307,10 +304,24 @@ class GVN : public Pass {
std
::
unique_ptr
<
GVNExpression
::
ConstFolder
>
folder_
;
std
::
unique_ptr
<
DeadCode
>
dce_
;
// self add
// self add
member
std
::
map
<
BasicBlock
*
,
bool
>
_TOP
;
partitions
join_helper
(
BasicBlock
*
pre1
,
BasicBlock
*
pre2
);
BasicBlock
*
curr_bb
;
BasicBlock
*
curr_bb
;
//
// self add function
//
std
::
uint64_t
new_number
()
{
return
next_value_number_
++
;
}
static
int
pretend_copy_stmt
(
Instruction
*
inst
,
BasicBlock
*
bb
);
std
::
shared_ptr
<
GVNExpression
::
Expression
>
search_ve
(
Value
*
v
,
const
partitions
&
part
);
std
::
vector
<
std
::
shared_ptr
<
GVNExpression
::
Expression
>>
core_
(
Instruction
*
instr
,
const
partitions
&
part
,
size_t
count
,
bool
fold_
=
true
);
};
bool
operator
==
(
const
GVN
::
partitions
&
p1
,
const
GVN
::
partitions
&
p2
);
src/optimization/GVN.cpp
View file @
b1f2b21d
...
...
@@ -235,9 +235,8 @@ GVN::join(const partitions &P1, const partitions &P2) {
return
P
;
}
std
::
shared_ptr
<
CongruenceClass
>
GVN
::
intersect
(
std
::
shared_ptr
<
CongruenceClass
>
ci
,
std
::
shared_ptr
<
CongruenceClass
>
cj
)
{
shared_ptr
<
CongruenceClass
>
GVN
::
intersect
(
shared_ptr
<
CongruenceClass
>
ci
,
shared_ptr
<
CongruenceClass
>
cj
)
{
// TODO
auto
c
=
createCongruenceClass
();
std
::
set
<
Value
*>
intersection
;
...
...
@@ -256,15 +255,17 @@ GVN::intersect(std::shared_ptr<CongruenceClass> ci,
*
ci
->
value_phi_
==
*
cj
->
value_phi_
)
c
->
value_phi_
=
ci
->
value_phi_
;
// if (c->members_.size() or c->value_expr_ or c->value_phi_) // not empty
// ??
// What if the ve is nullptr?
if
(
c
->
members_
.
size
())
// not empty
{
if
(
c
->
index_
==
0
)
{
c
->
index_
=
new_number
();
c
->
value_phi_
=
c
->
value_
expr_
=
c
->
value_
phi_
=
PhiExpression
::
create
(
ci
->
value_expr_
,
cj
->
value_expr_
);
}
c
->
leader_
=
*
c
->
members_
.
begin
();
}
return
c
;
}
...
...
@@ -276,7 +277,7 @@ GVN::detectEquivalences() {
for
(
auto
&
bb
:
func_
->
get_basic_blocks
())
{
for
(
auto
&
instr
:
bb
.
get_instructions
())
std
::
cout
<<
&
instr
<<
"
\t
"
<<
instr
.
print
()
<<
std
::
endl
;
}
}
// initialize pout with top
for
(
auto
&
bb
:
func_
->
get_basic_blocks
())
{
...
...
@@ -329,87 +330,119 @@ GVN::detectEquivalences() {
}
while
(
changed
);
}
// if v is already in one congruence set, return that value_expr_
// or return nullptr
shared_ptr
<
Expression
>
GVN
::
valueExpr
(
Instruction
*
instr
,
partitions
*
part
)
{
GVN
::
search_ve
(
Value
*
v
,
const
GVN
::
partitions
&
part
)
{
for
(
auto
c
:
part
)
{
if
(
std
::
find
(
c
->
members_
.
begin
(),
c
->
members_
.
end
(),
v
)
!=
c
->
members_
.
end
())
{
return
c
->
value_expr_
;
}
}
return
nullptr
;
}
// for each op, try to find the
std
::
vector
<
shared_ptr
<
Expression
>>
GVN
::
core_
(
Instruction
*
instr
,
const
partitions
&
part
,
size_t
count
,
bool
fold_
)
{
assert
(
not
(
fold_
and
count
>
2
));
Value
*
v
;
Constant
*
v_const
;
auto
operands
=
instr
->
get_operands
();
std
::
vector
<
shared_ptr
<
Expression
>>
ret
;
// if able to fold, then fold
fold_
&=
bool
(
dynamic_cast
<
Constant
*>
(
operands
[
0
]));
if
(
count
==
2
)
fold_
&=
bool
(
dynamic_cast
<
Constant
*>
(
operands
[
1
]));
if
(
fold_
)
{
Constant
*
res
;
if
(
count
==
1
)
{
res
=
folder_
->
compute
(
instr
,
dynamic_cast
<
Constant
*>
(
operands
[
0
]));
}
else
{
// count == 2
res
=
folder_
->
compute
(
instr
,
dynamic_cast
<
Constant
*>
(
operands
[
0
]),
dynamic_cast
<
Constant
*>
(
operands
[
1
]));
}
ret
.
push_back
(
ConstantExpression
::
create
(
res
));
return
ret
;
}
// normal case:
// - try to find expression that already exists
// - take care of constant
for
(
int
i
=
0
;
i
!=
count
;
i
++
)
{
v
=
operands
[
i
];
v_const
=
dynamic_cast
<
Constant
*>
(
v
);
if
(
v_const
)
{
ret
.
push_back
(
ConstantExpression
::
create
(
v_const
));
}
else
{
auto
res
=
search_ve
(
v
,
part
);
assert
(
res
);
ret
.
push_back
(
res
);
}
}
return
ret
;
}
shared_ptr
<
Expression
>
GVN
::
valueExpr
(
Instruction
*
instr
,
const
partitions
&
part
)
{
// TODO
// ?? should use part?
std
::
string
err
{
"Undefined"
};
std
::
cout
<<
instr
->
print
()
<<
std
::
endl
;
std
::
vector
<
shared_ptr
<
Expression
>>
res
;
// first check if there is already one congruence class inside
auto
tmp
=
search_ve
(
instr
,
part
);
if
(
tmp
)
return
tmp
;
if
(
instr
->
isBinary
()
or
instr
->
is_cmp
()
or
instr
->
is_fcmp
())
{
auto
op1
=
instr
->
get_operand
(
0
);
auto
op2
=
instr
->
get_operand
(
1
);
auto
op1_const
=
dynamic_cast
<
Constant
*>
(
op1
);
auto
op2_const
=
dynamic_cast
<
Constant
*>
(
op2
);
if
(
op1_const
and
op2_const
)
{
// both are constant number, so:
// constant fold!
return
ConstantExpression
::
create
(
folder_
->
compute
(
instr
,
op1_const
,
op2_const
));
}
else
{
// both none constant
auto
op1_instr
=
dynamic_cast
<
Instruction
*>
(
op1
);
auto
op2_instr
=
dynamic_cast
<
Instruction
*>
(
op2
);
assert
((
op1_instr
or
op1_const
)
and
(
op2_instr
or
op2_const
)
&&
"must be this case"
);
res
=
core_
(
instr
,
part
,
2
);
if
(
res
.
size
()
==
1
)
// constant fold
return
res
[
0
];
else
return
BinaryExpression
::
create
(
instr
->
get_instr_type
(),
(
op1_const
?
ConstantExpression
::
create
(
op1_const
)
:
valueExpr
(
op1_instr
)),
(
op2_const
?
ConstantExpression
::
create
(
op2_const
)
:
valueExpr
(
op2_instr
)));
}
instr
->
get_instr_type
(),
res
[
0
],
res
[
1
]);
}
else
if
(
instr
->
is_phi
())
{
err
=
"phi"
;
}
else
if
(
instr
->
is_fp2si
()
or
instr
->
is_si2fp
()
or
instr
->
is_zext
())
{
auto
op
=
instr
->
get_operand
(
0
);
auto
op_const
=
dynamic_cast
<
Constant
*>
(
op
);
auto
op_instr
=
dynamic_cast
<
Instruction
*>
(
op
);
assert
(
op_instr
or
op_const
);
// get dest type
auto
instr_fp2si
=
dynamic_cast
<
FpToSiInst
*>
(
instr
);
auto
instr_si2fp
=
dynamic_cast
<
SiToFpInst
*>
(
instr
);
auto
instr_zext
=
dynamic_cast
<
ZextInst
*>
(
instr
);
Type
*
dest_type
=
nullptr
;
if
(
instr_fp2si
)
dest_type
=
instr_fp2si
->
get_dest_type
();
else
if
(
instr_si2fp
)
dest_type
=
instr_si2fp
->
get_dest_type
();
else
if
(
instr_zext
)
dest_type
=
instr_zext
->
get_dest_type
();
else
err
=
"cast"
;
res
=
core_
(
instr
,
part
,
1
);
if
(
res
[
0
]
->
get_expr_type
()
==
Expression
::
e_constant
)
return
res
[
0
];
Type
*
dest_type
;
switch
(
instr
->
get_instr_type
())
{
case
Instruction
::
fptosi
:
dest_type
=
static_cast
<
FpToSiInst
*>
(
instr
)
->
get_dest_type
();
break
;
case
Instruction
::
sitofp
:
dest_type
=
static_cast
<
SiToFpInst
*>
(
instr
)
->
get_dest_type
();
break
;
case
Instruction
::
zext
:
dest_type
=
static_cast
<
ZextInst
*>
(
instr
)
->
get_dest_type
();
break
;
default:
dest_type
=
nullptr
;
err
=
"cast"
;
}
if
(
dest_type
)
{
if
(
op_const
)
return
ConstantExpression
::
create
(
folder_
->
compute
(
instr
,
op_const
));
else
return
CastExpression
::
create
(
instr
->
get_instr_type
(),
valueExpr
(
op_instr
),
dest_type
);
return
CastExpression
::
create
(
instr
->
get_instr_type
(),
res
[
0
],
dest_type
);
}
}
else
if
(
instr
->
is_gep
())
{
auto
operands
=
instr
->
get_operands
();
auto
ptr
=
operands
[
0
];
std
::
vector
<
std
::
shared_ptr
<
Expression
>>
idxs
;
// check for base address
assert
(
not
dynamic_cast
<
Constant
*>
(
ptr
)
and
dynamic_cast
<
Instruction
*>
(
ptr
)
&&
"base address should only be from instruction"
);
// set idxes
for
(
int
i
=
1
;
i
<
operands
.
size
();
i
++
)
{
if
(
dynamic_cast
<
Constant
*>
(
operands
[
i
]))
idxs
.
push_back
(
ConstantExpression
::
create
(
dynamic_cast
<
Constant
*>
(
operands
[
i
])));
else
{
assert
(
dynamic_cast
<
Instruction
*>
(
operands
[
i
]));
idxs
.
push_back
(
valueExpr
(
dynamic_cast
<
Instruction
*>
(
operands
[
i
])));
}
}
return
GEPExpression
::
create
(
valueExpr
(
dynamic_cast
<
Instruction
*>
(
ptr
)),
idxs
);
res
=
core_
(
instr
,
part
,
instr
->
get_operands
().
size
(),
false
);
auto
ptr
=
res
[
0
];
res
.
erase
(
res
.
begin
());
return
GEPExpression
::
create
(
ptr
,
res
);
}
else
if
(
instr
->
is_load
()
or
instr
->
is_alloca
()
or
instr
->
is_call
())
{
return
UniqueExpression
::
create
(
instr
);
}
...
...
@@ -450,31 +483,26 @@ GVN::transferFunction(Instruction *x, Value *e, partitions pin) {
if
(
e_const
)
ve
=
ConstantExpression
::
create
(
e_const
);
else
ve
=
valueExpr
(
e_instr
,
&
pin
);
ve
=
valueExpr
(
e_instr
,
pin
);
}
else
ve
=
valueExpr
(
x
,
&
pin
);
ve
=
valueExpr
(
x
,
pin
);
auto
vpf
=
valuePhiFunc
(
ve
,
curr_bb
);
// TODO: set leader
for
(
auto
c
:
pout
)
{
if
(
ve
==
c
->
value_expr_
or
(
vpf
and
vpf
==
c
->
value_phi_
))
{
if
(
ve
==
c
->
value_expr_
or
(
vpf
and
c
->
value_phi_
and
*
vpf
==
*
c
->
value_phi_
))
{
c
->
value_expr_
=
ve
;
c
->
members_
.
insert
(
x
);
}
else
{
auto
c
=
createCongruenceClass
(
new_number
());
c
->
members_
.
insert
(
x
);
c
->
value_expr_
=
ve
;
c
->
value_phi_
=
vpf
;
pout
.
insert
(
c
);
return
pout
;
}
}
/* // first version: ignore ve and vpf
* // and only update index, leader and members
* auto c = createCongruenceClass(new_number());
* c->leader_ = x;
* c->members_.insert(x);
* pout.insert(c); */
auto
c
=
createCongruenceClass
(
new_number
());
c
->
members_
.
insert
(
x
);
c
->
leader_
=
x
;
c
->
value_expr_
=
ve
;
c
->
value_phi_
=
vpf
;
pout
.
insert
(
c
);
return
pout
;
}
...
...
@@ -491,7 +519,9 @@ GVN::transferFunction(BasicBlock *bb) {
* LOG_INFO << "pin:\n";
* utils::print_partitions(pin_[bb]);
* LOG_INFO << "pout before:\n";
* utils::print_partitions(pout_[bb]); */
* utils::print_partitions(pout_[bb]); */
std
::
cout
<<
"for basic block "
<<
bb
->
get_name
()
<<
", pin:"
<<
std
::
endl
;
utils
::
print_partitions
(
pin_
[
bb
]);
// iterate through all instructions in the block
for
(
auto
&
instr
:
bb
->
get_instructions
())
{
...
...
@@ -503,7 +533,7 @@ GVN::transferFunction(BasicBlock *bb) {
for
(
auto
succ
:
bb
->
get_succ_basic_blocks
())
{
for
(
auto
&
instr
:
succ
->
get_instructions
())
{
if
(
instr
.
is_phi
())
{
if
((
res
=
pretend_copy_stmt
(
&
instr
,
bb
)
==
-
1
)
)
if
((
res
=
pretend_copy_stmt
(
&
instr
,
bb
)
)
==
-
1
)
continue
;
part
=
transferFunction
(
&
instr
,
instr
.
get_operand
(
res
),
part
);
}
...
...
@@ -572,19 +602,19 @@ GVN::initPerFunction() {
void
GVN
::
replace_cc_members
()
{
for
(
auto
&
[
_bb
,
part
]
:
pout_
)
{
auto
bb
=
_bb
;
// workaround: structured bindings can't be captured
in C++17
auto
bb
=
_bb
;
// workaround: structured bindings can't be captured
//
in C++17
for
(
auto
&
cc
:
part
)
{
if
(
cc
->
index_
==
0
)
continue
;
// if you are planning to do constant propagation, leaders
should be
// set to constant at some point
// if you are planning to do constant propagation, leaders
// s
hould be s
et to constant at some point
for
(
auto
&
member
:
cc
->
members_
)
{
bool
member_is_phi
=
dynamic_cast
<
PhiInst
*>
(
member
);
bool
value_phi
=
cc
->
value_phi_
!=
nullptr
;
if
(
member
!=
cc
->
leader_
and
(
value_phi
or
!
member_is_phi
))
{
// only replace the members if users are in the same
block
// as bb
// only replace the members if users are in the same
//
block
as bb
member
->
replace_use_with_when
(
cc
->
leader_
,
[
bb
](
User
*
user
)
{
if
(
auto
instr
=
...
...
@@ -592,7 +622,7 @@ GVN::replace_cc_members() {
auto
parent
=
instr
->
get_parent
();
auto
&
bb_pre
=
parent
->
get_pre_basic_blocks
();
if
(
instr
->
is_phi
())
// as copy stmt, the phi
// belongs to this block
// belongs to this block
return
std
::
find
(
bb_pre
.
begin
(),
bb_pre
.
end
(),
bb
)
!=
bb_pre
.
end
();
...
...
@@ -650,7 +680,8 @@ GVN::run() {
gvn_json
<<
"
\n\"
pout
\"
: "
<<
utils
::
dump_bb2partition
(
pout_
);
gvn_json
<<
"},"
;
}
replace_cc_members
();
// don't delete instructions, just replace them
replace_cc_members
();
// don't delete instructions, just replace
// them
}
dce_
->
run
();
// let dce do that for us
if
(
dump_json_
)
...
...
tests/4-ir-opt/testcases/GVN/functional/clear.sh
0 → 100755
View file @
b1f2b21d
rm
-rf
*
.ll
rm
-rf
gvn.json
rm
-rf
`
ls
|
grep
-v
"
\.
"
`
tests/4-ir-opt/testcases/GVN/performance/clear.sh
0 → 100755
View file @
b1f2b21d
rm
-rf
const-prop
rm
-rf
transpose
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment