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
805d36ad
Commit
805d36ad
authored
Feb 08, 2023
by
lxq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ready to finish all the functional test!
parent
e23c2e2e
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
187 additions
and
118 deletions
+187
-118
Reports/5-bonus/report.md
Reports/5-bonus/report.md
+6
-0
include/codegen/codegen.hpp
include/codegen/codegen.hpp
+25
-9
include/codegen/liverange.hpp
include/codegen/liverange.hpp
+14
-6
include/codegen/regalloc.hpp
include/codegen/regalloc.hpp
+8
-5
src/codegen/codegen.cpp
src/codegen/codegen.cpp
+71
-65
src/codegen/liverange.cpp
src/codegen/liverange.cpp
+18
-11
src/codegen/regalloc.cpp
src/codegen/regalloc.cpp
+45
-22
No files found.
Reports/5-bonus/report.md
View file @
805d36ad
...
...
@@ -161,4 +161,10 @@ op6: <8, 8>
-
`tests/4-ir-opt/testcases/GVN/performance`
## 局限性
-
GEP的取巧设计
-
未考虑指令寻址的立即数
-
include/codegen/codegen.hpp
View file @
805d36ad
...
...
@@ -15,10 +15,12 @@
#include <string>
#define __PRINT_ORI__
#define __RO_PART__
//
#define __RO_PART__
#define __PRINT_COMMENT__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#define R_USABLE (17 - 2)
// #fa = 8, #ft=16, reserve $ft0, $ft1 for temporary
#define FR_USABLE (24 - 2)
#define ARG_R 8
#include <map>
...
...
@@ -40,7 +42,12 @@ using std::vector;
class
CodeGen
{
public:
CodeGen
(
Module
*
m_
)
:
m
(
m_
),
LRA
(
m_
,
phi_map
),
RA
(
R_USABLE
,
ARG_R
)
{}
CodeGen
(
Module
*
m_
)
:
cmp_zext_cnt
(
0
)
,
m
(
m_
)
,
LRA
(
m_
,
phi_map
)
,
RA_int
(
R_USABLE
,
false
)
,
RA_float
(
FR_USABLE
,
true
)
{}
string
print
()
{
string
result
;
...
...
@@ -77,7 +84,8 @@ class CodeGen {
vector
<
string
>
output
;
// register allocation
LRA
::
LiveRangeAnalyzer
LRA
;
RA
::
RegAllocator
RA
;
LRA
::
LVITS
LVITS_int
,
LVITS_float
;
RA
::
RegAllocator
RA_int
,
RA_float
;
// some instruction has lvalue, but is stack-allocated,
// we need this variable to track the reg name which has rvalue.
// this variable is maintain by gencopy() and LoadInst.
...
...
@@ -147,7 +155,7 @@ class CodeGen {
gencopy
(
lhs_reg
,
rhs_reg
,
is_float
);
return
true
;
}
void
gencopy
(
string
lhs_reg
,
string
rhs_reg
,
bool
is_float
=
false
)
{
void
gencopy
(
string
lhs_reg
,
string
rhs_reg
,
bool
is_float
)
{
if
(
rhs_reg
!=
lhs_reg
)
{
if
(
is_float
)
output
.
push_back
(
"fmov.s "
+
lhs_reg
+
", "
+
rhs_reg
);
...
...
@@ -215,7 +223,9 @@ class CodeGen {
return
true
;
if
(
instr
->
is_fcmp
()
or
instr
->
is_cmp
()
or
instr
->
is_zext
())
return
true
;
if
(
RA
.
get
().
find
(
instr
)
!=
RA
.
get
().
end
())
auto
regmap
=
(
instr
->
get_type
()
->
is_float_type
()
?
RA_float
.
get
()
:
RA_int
.
get
());
if
(
regmap
.
find
(
instr
)
!=
regmap
.
end
())
return
true
;
return
false
;
...
...
@@ -225,17 +235,23 @@ class CodeGen {
return
(
is_float
?
"$ft"
:
"$t"
)
+
to_string
(
i
);
}
static
string
regname
(
int
i
,
bool
is_float
=
false
)
{
static
string
regname
(
uint
i
,
bool
is_float
)
{
string
name
;
if
(
is_float
)
{
assert
(
false
&&
"not implemented!"
);
// assert(false && "not implemented!");
if
(
1
<=
i
and
i
<=
8
)
name
=
"$fa"
+
to_string
(
i
-
1
);
else
if
(
9
<=
i
and
i
<=
FR_USABLE
)
name
=
"$ft"
+
to_string
(
i
-
9
+
2
);
else
name
=
"WRONG_REG_"
+
to_string
(
i
);
}
else
{
if
(
1
<=
i
and
i
<=
8
)
name
=
"$a"
+
to_string
(
i
-
1
);
else
if
(
9
<=
i
and
i
<=
R_USABLE
)
name
=
"$t"
+
to_string
(
i
-
9
+
2
);
else
name
=
"WRONG_REG"
+
to_string
(
i
);
name
=
"WRONG_REG
_
"
+
to_string
(
i
);
}
return
name
;
}
...
...
include/codegen/liverange.hpp
View file @
805d36ad
...
...
@@ -15,12 +15,14 @@ using std::string;
using
std
::
to_string
;
using
std
::
vector
;
#define UNINITIAL -1
#define __LRA_PRINT__
namespace
LRA
{
struct
Interval
{
Interval
(
int
a
=
-
1
,
int
b
=
-
1
)
:
i
(
a
),
j
(
b
)
{}
Interval
(
int
a
=
UNINITIAL
,
int
b
=
UNINITIAL
)
:
i
(
a
),
j
(
b
)
{}
int
i
;
// 0 means uninitialized
int
j
;
};
...
...
@@ -49,15 +51,17 @@ class LiveRangeAnalyzer {
// void run();
void
run
(
Function
*
);
void
clear
();
void
print
(
Function
*
func
,
bool
printSet
=
false
,
bool
printInt
=
false
)
const
;
string
print_liveSet
(
const
LiveSet
&
ls
)
const
{
void
print
(
Function
*
func
,
bool
printSet
=
false
,
bool
printInt
=
false
)
const
;
static
string
print_liveSet
(
const
LiveSet
&
ls
)
{
string
s
=
"[ "
;
for
(
auto
k
:
ls
)
s
+=
k
->
get_name
()
+
" "
;
s
+=
"]"
;
return
s
;
}
st
ring
print_interval
(
Interval
&
i
)
const
{
st
atic
string
print_interval
(
const
Interval
&
i
)
{
return
"<"
+
to_string
(
i
.
i
)
+
", "
+
to_string
(
i
.
j
)
+
">"
;
}
const
LVITS
&
get
()
{
return
liveIntervals
;
}
...
...
@@ -91,8 +95,12 @@ class LiveRangeAnalyzer {
LiveSet
transferFunction
(
Instruction
*
);
public:
const
decltype
(
instr_id
)
&
get_instr_id
()
{
return
instr_id
;
}
const
decltype
(
intervalmap
)
&
get_interval_map
()
{
return
intervalmap
;
}
const
decltype
(
instr_id
)
&
get_instr_id
()
const
{
return
instr_id
;
}
const
decltype
(
intervalmap
)
&
get_interval_map
()
const
{
return
intervalmap
;
}
const
decltype
(
IN
)
&
get_in_set
()
const
{
return
IN
;
}
const
decltype
(
OUT
)
&
get_out_set
()
const
{
return
OUT
;
}
};
}
// namespace LRA
#endif
include/codegen/regalloc.hpp
View file @
805d36ad
...
...
@@ -14,24 +14,27 @@ using namespace LRA;
namespace
RA
{
#define MAXR 32
#define ARG_MAX_R 8
struct
ActiveCMP
{
bool
operator
()(
LiveInterval
const
&
lhs
,
LiveInterval
const
&
rhs
)
const
{
if
(
lhs
.
first
.
j
!=
rhs
.
first
.
j
)
return
lhs
.
first
.
j
<
rhs
.
first
.
j
;
else
else
if
(
lhs
.
first
.
i
!=
rhs
.
first
.
i
)
return
lhs
.
first
.
i
<
rhs
.
first
.
i
;
else
return
lhs
.
second
<
rhs
.
second
;
}
};
class
RegAllocator
{
public:
RegAllocator
(
const
uint
R_
,
const
uint
ARG_R_
)
:
R
(
R_
),
ARG_MAX_R
(
ARG_R_
),
used
{
false
}
{
RegAllocator
(
const
uint
R_
,
bool
fl
)
:
FLOAT
(
fl
),
R
(
R_
),
used
{
false
}
{
cout
<<
"RegAllocator initialize: R="
<<
R
<<
endl
;
assert
(
R
<=
MAXR
);
}
RegAllocator
()
=
delete
;
bool
no_reg_alloca
(
Value
*
v
)
const
;
static
bool
no_reg_alloca
(
Value
*
v
)
;
// input set is sorted by increasing start point
void
LinearScan
(
const
LVITS
&
,
Function
*
);
const
map
<
Value
*
,
int
>
&
get
()
const
{
return
regmap
;
}
...
...
@@ -42,8 +45,8 @@ class RegAllocator {
private:
Function
*
cur_func
;
const
bool
FLOAT
;
const
uint
R
;
const
uint
ARG_MAX_R
;
bool
used
[
MAXR
+
1
];
// index range: 1 ~ R
map
<
Value
*
,
int
>
regmap
;
// sorted by increasing end point
...
...
src/codegen/codegen.cpp
View file @
805d36ad
This diff is collapsed.
Click to expand it.
src/codegen/liverange.cpp
View file @
805d36ad
...
...
@@ -125,31 +125,34 @@ LiveRangeAnalyzer::run(Function *func) {
}
}
// argument should be in the IN-set of Entry
assert
(
IN
.
find
(
0
)
==
IN
.
end
()
and
OUT
.
find
(
0
)
==
OUT
.
end
()
&&
"no instr_id will be mapped to 0"
);
IN
[
0
]
=
OUT
[
0
]
=
{};
for
(
auto
arg
:
func
->
get_args
())
IN
[
1
].
insert
(
arg
);
IN
[
0
].
insert
(
arg
);
make_interval
(
func
);
#ifdef __LRA_PRINT__
print
(
func
,
tru
e
,
true
);
print
(
func
,
fals
e
,
true
);
#endif
}
void
LiveRangeAnalyzer
::
make_interval
(
Function
*
)
{
for
(
int
time
=
1
;
time
<=
ir_cnt
;
++
time
)
{
for
(
int
time
=
0
;
time
<=
ir_cnt
;
++
time
)
{
for
(
auto
op
:
IN
.
at
(
time
))
{
auto
&
interval
=
intervalmap
[
op
];
if
(
interval
.
i
==
-
1
)
// uninitialized
interval
.
i
=
time
-
1
;
if
(
interval
.
i
==
UNINITIAL
)
// uninitialized
interval
.
i
=
interval
.
j
=
time
;
else
interval
.
j
=
time
-
1
;
interval
.
j
=
time
;
}
for
(
auto
op
:
OUT
.
at
(
time
))
{
auto
&
interval
=
intervalmap
[
op
];
if
(
interval
.
i
==
-
1
)
// uninitialized
interval
.
i
=
time
;
if
(
interval
.
i
==
UNINITIAL
)
// uninitialized
interval
.
i
=
interval
.
j
=
time
+
1
;
else
interval
.
j
=
time
;
interval
.
j
=
time
+
1
;
}
}
for
(
auto
&
[
op
,
interval
]
:
intervalmap
)
...
...
@@ -197,6 +200,11 @@ LiveRangeAnalyzer::print(Function *func,
bool
printSet
,
bool
printInt
)
const
{
// for debug
cout
<<
"Function "
<<
func
->
get_name
()
<<
endl
;
cout
<<
"0. Entry"
<<
endl
;
if
(
printSet
)
{
cout
<<
"
\t
in-set: "
+
print_liveSet
(
IN
.
at
(
0
))
<<
"
\n
"
;
cout
<<
"
\t
out-set: "
+
print_liveSet
(
OUT
.
at
(
0
))
<<
"
\n
"
;
}
for
(
auto
&
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
&
instr
:
bb
.
get_instructions
())
{
if
(
instr
.
is_phi
())
// ignore phi
...
...
@@ -220,8 +228,7 @@ LiveRangeAnalyzer::print(Function *func,
}
}
// normal ir
cout
<<
instr_id
.
at
(
&
instr
)
<<
". "
<<
instr
.
print
()
<<
" # "
<<
&
instr
<<
endl
;
cout
<<
instr_id
.
at
(
&
instr
)
<<
". "
<<
instr
.
print
()
<<
endl
;
if
(
not
printSet
)
continue
;
auto
idx
=
instr_id
.
at
(
&
instr
);
...
...
src/codegen/regalloc.cpp
View file @
805d36ad
...
...
@@ -10,6 +10,9 @@ using std::for_each;
using
namespace
RA
;
#define ASSERT_CMPINST_USED_ONCE(cmpinst) \
(assert(cmpinst->get_use_list().size() == 1))
int
get_arg_id
(
Argument
*
arg
)
{
auto
args
=
arg
->
get_parent
()
->
get_args
();
...
...
@@ -23,7 +26,7 @@ get_arg_id(Argument *arg) {
}
bool
RegAllocator
::
no_reg_alloca
(
Value
*
v
)
const
{
RegAllocator
::
no_reg_alloca
(
Value
*
v
)
{
auto
instr
=
dynamic_cast
<
Instruction
*>
(
v
);
auto
arg
=
dynamic_cast
<
Argument
*>
(
v
);
if
(
instr
)
{
...
...
@@ -31,21 +34,26 @@ RegAllocator::no_reg_alloca(Value *v) const {
if
(
instr
->
is_alloca
()
or
instr
->
is_cmp
()
or
instr
->
is_fcmp
())
return
true
;
else
if
(
instr
->
is_zext
())
{
// only alloca for true use
for
(
auto
use
:
instr
->
get_use_list
())
if
(
not
dynamic_cast
<
Instruction
*>
(
use
.
val_
)
->
is_br
())
{
auto
instr
=
static_cast
<
Instruction
*>
(
use
.
val_
);
if
(
instr
->
is_cmp
())
{
// special case for cmp again
auto
cmp
=
static_cast
<
CmpInst
*>
(
instr
);
assert
(
cmp
->
get_cmp_op
()
==
CmpInst
::
NE
);
auto
uses
=
instr
->
get_use_list
();
assert
(
uses
.
size
()
==
1
and
dynamic_cast
<
Instruction
*>
(
uses
.
begin
()
->
val_
)
->
is_br
());
bool
alloc
;
ASSERT_CMPINST_USED_ONCE
(
instr
);
auto
use_ins
=
dynamic_cast
<
Instruction
*>
(
instr
->
get_use_list
().
begin
()
->
val_
);
// assert(use_ins != nullptr && "should only be instruction?");
if
(
use_ins
->
is_cmp
()
and
static_cast
<
CmpInst
*>
(
use_ins
)
->
get_cmp_op
()
==
CmpInst
::
NE
)
{
// this case:
// %op0 = icmp slt i32 1, 2
// %op1 = zext i1 %op0 to i32
// %op2 = icmp ne i32 %op1, 0 # <- if judges to here
// br i1 %op2, label %label3, label %label5
ASSERT_CMPINST_USED_ONCE
(
use_ins
);
auto
use2_ins
=
dynamic_cast
<
Instruction
*>
(
use_ins
->
get_use_list
().
begin
()
->
val_
);
alloc
=
not
(
use2_ins
->
is_br
());
}
else
alloc
=
true
;
}
else
return
false
;
}
return
true
;
return
not
(
alloc
);
}
else
// then always allocate
return
false
;
}
...
...
@@ -64,19 +72,22 @@ RegAllocator::reset(Function *func) {
}
int
RegAllocator
::
ReserveForArg
(
const
LVITS
&
L
iveints
)
{
RegAllocator
::
ReserveForArg
(
const
LVITS
&
l
iveints
)
{
auto
args
=
cur_func
->
get_args
();
auto
it_int
=
L
iveints
.
begin
();
auto
it_int
=
l
iveints
.
begin
();
auto
it_arg
=
args
.
begin
();
int
reg
;
for
(
reg
=
1
;
reg
<=
args
.
size
()
and
reg
<=
ARG_MAX_R
;
++
reg
)
{
auto
arg
=
*
it_arg
;
auto
liveint
=
*
it_int
;
assert
(
arg
==
liveint
.
second
&&
"arg should be in order in liveints"
);
if
(
not
(
FLOAT
^
arg
->
get_type
()
->
is_float_type
()))
{
auto
liveint
=
*
it_int
;
assert
(
arg
==
liveint
.
second
&&
"arg should be in order in liveints"
);
used
[
reg
]
=
true
;
regmap
[
arg
]
=
reg
;
active
.
insert
(
liveint
);
used
[
reg
]
=
true
;
regmap
[
arg
]
=
reg
;
active
.
insert
(
liveint
);
}
++
it_arg
,
++
it_int
;
}
return
reg
;
...
...
@@ -88,6 +99,8 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
ReserveForArg
(
liveints
);
int
reg
;
for
(
auto
liveint
:
liveints
)
{
if
(
FLOAT
^
liveint
.
second
->
get_type
()
->
is_float_type
())
continue
;
if
(
dynamic_cast
<
Argument
*>
(
liveint
.
second
))
{
continue
;
}
...
...
@@ -99,6 +112,13 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
else
{
for
(
reg
=
1
;
reg
<=
R
and
used
[
reg
];
++
reg
)
;
if
(
reg
==
16
)
{
for
(
auto
[
interval
,
v
]
:
active
)
{
cout
<<
"already allocated: "
<<
v
->
get_name
()
<<
" ~ "
<<
regmap
.
at
(
v
)
<<
endl
;
}
assert
(
false
);
}
used
[
reg
]
=
true
;
regmap
[
liveint
.
second
]
=
reg
;
active
.
insert
(
liveint
);
...
...
@@ -108,10 +128,12 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
void
RegAllocator
::
ExpireOldIntervals
(
LiveInterval
liveint
)
{
auto
it
=
active
.
begin
();
for
(;
it
!=
active
.
end
()
and
it
->
first
.
j
<
liveint
.
first
.
i
;
++
it
)
used
[
regmap
.
at
(
it
->
second
)]
=
false
;
active
.
erase
(
active
.
begin
(),
it
);
}
void
...
...
@@ -122,6 +144,7 @@ RegAllocator::SpillAtInterval(LiveInterval liveint) {
if
(
spill
.
first
.
j
>
liveint
.
first
.
j
)
{
// cancel reg allocation for spill
regmap
[
liveint
.
second
]
=
regmap
.
at
(
spill
.
second
);
active
.
insert
(
liveint
);
active
.
erase
(
spill
);
regmap
.
erase
(
spill
.
second
);
...
...
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