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
0454682c
Commit
0454682c
authored
Feb 05, 2023
by
lxq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
write reg-alloca for int values
parent
3d814ba8
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
373 additions
and
188 deletions
+373
-188
Reports/5-bonus/report.md
Reports/5-bonus/report.md
+47
-23
include/codegen/codegen.hpp
include/codegen/codegen.hpp
+102
-50
include/codegen/liverange.hpp
include/codegen/liverange.hpp
+14
-7
include/codegen/regalloc.hpp
include/codegen/regalloc.hpp
+18
-4
src/codegen/codegen.cpp
src/codegen/codegen.cpp
+170
-94
src/codegen/liverange.cpp
src/codegen/liverange.cpp
+8
-8
src/codegen/regalloc.cpp
src/codegen/regalloc.cpp
+14
-2
No files found.
Reports/5-bonus/report.md
View file @
0454682c
...
...
@@ -59,38 +59,38 @@ label7: ; preds = %label0
```
llvm
1
.
op1
=
0
in-set:
[
]
out-set:
[
op1
]
in-set:
[
]
out-set:
[
op1
]
2
.
br
label
%label0
in-set:
[
op1
]
out-set:
[
op1
]
in-set:
[
op1
]
out-set:
[
op1
]
3
.
%op2
=
icmp
slt
i32
%op1
,
10
in-set:
[
op1
]
out-set:
[
op2
op1
]
in-set:
[
op1
]
out-set:
[
op2
op1
]
4
.
%op3
=
zext
i1
%op2
to
i32
in-set:
[
op2
op1
]
out-set:
[
op3
op1
]
in-set:
[
op2
op1
]
out-set:
[
op3
op1
]
5
.
%op4
=
icmp
ne
i32
%op3
,
0
in-set:
[
op3
op1
]
out-set:
[
op4
op1
]
in-set:
[
op3
op1
]
out-set:
[
op4
op1
]
6
.
br
i1
%op4
,
label
%label5
,
label
%label7
in-set:
[
op4
op1
]
out-set:
[
op1
]
in-set:
[
op4
op1
]
out-set:
[
op1
]
7
.
call
void
@output
(
i32
%op1
)
in-set:
[
op1
]
out-set:
[
op1
]
in-set:
[
op1
]
out-set:
[
op1
]
8
.
%op6
=
add
i32
%op1
,
1
in-set:
[
op1
]
out-set:
[
op6
]
in-set:
[
op1
]
out-set:
[
op6
]
9
.
op1
=
op6
in-set:
[
op6
]
out-set:
[
op1
]
in-set:
[
op6
]
out-set:
[
op1
]
10
.
br
label
%label0
in-set:
[
op1
]
out-set:
[
op1
]
in-set:
[
op1
]
out-set:
[
op1
]
11
.
ret
i32
0
in-set:
[
]
out-set:
[
]
in-set:
[
]
out-set:
[
]
```
获得活跃区间:编号为i的指令,涉及两个端点:i-1和i,分别对应IN和OUT。由此得到各个变量的活跃区间是:
...
...
@@ -111,4 +111,28 @@ op6: <8, 8>
-
[
Documentations/5-bonus/寄存器分配.md · master · compiler_staff / 2022fall-Compiler_CMinus · GitLab
](
https://cscourse.ustc.edu.cn/vdir/Gitlab/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/5-bonus/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D.md#poletto
)
i
程序有
`$a`
系列寄存器8个,
`$t`
系列9个,拿出
`$t0`
、
`$t1`
做IR生成汇编过程中的临时寄存器(这个方案仅在cminus下成立),所以可以自由分配的寄存器一共15个。
首先完成对于局部变量的寄存器分配,即全局变量、传参依旧通过栈进行。
程序分配寄存器时会对部分指令做特殊处理,具体如下:
-
`phi`
指令:还原为
`copy-stmt`
,所以寄存器照样分配,如果没分到使用栈内存
-
`alloca`
指令:这里忽略对于
`alloca`
指令的寄存器分配,
`alloca`
仍然使用栈存储,原因如下:
-
对于int|float的
`alloca`
,使用寄存器可以正常进行,只需将相关指令
`load`
和
`store`
分别成赋值即可。
-
但是对于数组的
`alloca`
,使用寄存器就很难模拟了。
即寄存器不能完成
`alloca`
的内存逻辑,同时经过
`mem2reg`
优化过后,不再有局部变量的声明,所以忽略对于
`alloca`
指令的寄存器分配。
-
`cmp`
、
`fcmp`
和
`zext`
指令:不做寄存器分配,也不做栈分配。
这实际是指令选择部分的内容:
因为在cminus中并没有bool变量,这些IR指令用到的i1类型都是临时的:只为分支指令服务,所以直接将这些指令集成到分支跳转的判断中。
-
`call`
指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖
`call`
指令的程序点。
include/codegen/codegen.hpp
View file @
0454682c
...
...
@@ -9,15 +9,17 @@
#include "Module.h"
#include "Value.h"
#include "liverange.hpp"
#include "
logging
.hpp"
#include "
regalloc
.hpp"
#define __RO_PART__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#include <map>
#include <ostream>
#include <vector>
#define ALIGN(x, align) (((
x / align) + (x % align
? 1 : 0)) * align)
#define ALIGN(x, align) (((
(x) / align) + (((x) % align)
? 1 : 0)) * align)
// #define STACK_ALIGN(x) (((x / 16) + (x % 16 ? 1 : 0)) * 16)
#define STACK_ALIGN(x) ALIGN(x, 16)
...
...
@@ -27,7 +29,7 @@ using std::vector;
class
CodeGen
{
public:
CodeGen
(
Module
*
m_
)
:
m
(
m_
),
LRA
(
m_
,
phi_map
)
{}
CodeGen
(
Module
*
m_
)
:
m
(
m_
),
LRA
(
m_
,
phi_map
)
,
RA
(
R_USABLE
)
{}
string
print
()
{
string
result
;
...
...
@@ -42,35 +44,41 @@ class CodeGen {
void
run
();
private:
void
IR2assem
(
Instruction
&
,
BasicBlock
&
);
void
IR2assem
(
LoadInst
*
);
void
IR2assem
(
StoreInst
*
);
void
IR2assem
(
ReturnInst
*
);
void
IR2assem
(
GetElementPtrInst
*
);
void
IR2assem
(
CallInst
*
);
void
IR2assem
(
BranchInst
*
);
void
IR2assem
(
BinaryInst
*
);
void
IR2assem
(
FpToSiInst
*
);
void
IR2assem
(
SiToFpInst
*
);
void
IR2assem
(
PhiInst
*
)
{}
// The Instructions below will do nothing
void
IR2assem
(
AllocaInst
*
)
{}
// integration with BranchInst
void
IR2assem
(
CmpInst
*
)
{}
void
IR2assem
(
FCmpInst
*
)
{}
void
IR2assem
(
ZextInst
*
)
{}
//
// data member
//
std
::
map
<
Value
*
,
unsigned
int
>
off
;
// stack offset to $fp
std
::
map
<
Function
*
,
std
::
map
<
int
,
int
>>
func_arg_off
;
// to $sp
// total space for args, NOTE: not aligned
std
::
map
<
Function
*
,
int
>
func_arg_N
;
std
::
map
<
BasicBlock
*
,
std
::
vector
<
std
::
pair
<
Value
*
,
Value
*>>>
phi_map
;
std
::
map
<
Constant
*
,
std
::
string
>
ROdata
;
unsigned
int
stackN
;
// function local vars and so on
Function
*
cur_func
;
Module
*
m
;
vector
<
string
>
output
;
// register allocation
LRA
::
LiveRangeAnalyzer
LRA
;
RA
::
RegAllocator
RA
;
// 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.
string
last_reg
;
//
// function member
//
void
stackMemAlloc
();
void
stackMemDealloc
();
// load value `opk` to the specified register
// - for constant number, just load into reg
// - for global variables and pointers from alloca and GEP, read through
// address
// only use register a_id and t_
void
value2reg
(
Value
*
,
int
id
=
0
);
// In the case of register allocation, this function will return the
// allocated register for that value, if the value possesses no register,
// choose from from $t0 or $t1 based on id
__attribute__
((
warn_unused_result
))
string
value2reg
(
Value
*
,
int
i
=
0
);
// load the content in ptr to specified register.
// only use register a_id and t_
void
ptrContent2reg
(
Value
*
,
int
id
=
0
);
void
ptrContent2reg
(
Value
*
,
string
);
void
compute_arg_info
(
Function
*
);
string
bool2branch
(
Instruction
*
);
void
getPhiMap
();
...
...
@@ -80,15 +88,35 @@ class CodeGen {
output
.
push_back
(
"# "
+
print_as_op
(
copy
.
first
,
false
)
+
" = "
+
print_as_op
(
copy
.
second
,
false
));
auto
lvalue
=
static_cast
<
Instruction
*>
(
copy
.
first
);
value2reg
(
copy
.
second
);
back2stack
(
lvalue
);
auto
src_reg
=
value2reg
(
copy
.
second
);
if
(
gencopy
(
lvalue
,
src_reg
)
==
false
)
back2stack
(
lvalue
);
}
}
// if reg-allocation, store to the specific register
// or is stack-allocation, set last_reg for back2stack()
bool
gencopy
(
Value
*
lhs
,
string
rhs_reg
)
{
auto
[
lhs_reg
,
find
]
=
getRegName
(
lhs
);
if
(
not
find
)
{
// wait for back2stack() to store back
last_reg
=
rhs_reg
;
return
false
;
}
auto
is_float
=
lhs
->
get_type
()
->
is_float_type
();
if
(
rhs_reg
!=
lhs_reg
)
{
if
(
is_float
)
output
.
push_back
(
"fmov.s "
+
lhs_reg
+
", "
+
rhs_reg
);
else
output
.
push_back
(
"or "
+
lhs_reg
+
", $zero, "
+
rhs_reg
);
}
return
true
;
}
string
label_in_assem
(
BasicBlock
*
bb
)
{
string
label_in_assem
(
BasicBlock
*
bb
)
const
{
return
cur_func
->
get_name
()
+
bb
->
get_name
().
substr
(
5
);
}
int
typeLen
(
Type
*
type
)
{
int
typeLen
(
Type
*
type
)
const
{
if
(
type
->
is_float_type
())
return
4
;
else
if
(
type
->
is_integer_type
())
{
...
...
@@ -107,19 +135,19 @@ class CodeGen {
}
}
// assert the value needed to store back is in
$a0 or $f0
, according to the
// assert the value needed to store back is in
`last_reg`
, according to the
// value type
void
back2stack
(
Instruction
*
instr
)
{
// std::cerr << instr->print() << std::endl;
auto
type
=
instr
->
get_type
();
string
instr_ir
=
type
->
is_float_type
()
?
"fst"
:
"st"
;
string
suff
=
suffix
(
type
);
string
reg
=
type
->
is_float_type
()
?
"$fa0"
:
"$a0"
;
string
addr
=
"$fp, -"
+
std
::
to_string
(
off
[
instr
]
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", "
+
addr
);
//
string reg = type->is_float_type() ? "$fa0" : "$a0";
string
addr
=
"$fp, -"
+
std
::
to_string
(
off
.
at
(
instr
)
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
last_
reg
+
", "
+
addr
);
}
string
suffix
(
Type
*
type
)
{
string
suffix
(
Type
*
type
)
const
{
int
len
=
typeLen
(
type
);
switch
(
len
)
{
case
1
:
...
...
@@ -134,29 +162,53 @@ class CodeGen {
assert
(
false
&&
"no such suffix"
);
}
bool
no_stack_alloca
(
Instruction
*
instr
)
{
bool
no_stack_alloca
(
Instruction
*
instr
)
const
{
if
(
instr
->
is_void
())
return
true
;
if
(
instr
->
is_fcmp
()
or
instr
->
is_cmp
()
or
instr
->
is_zext
())
return
true
;
if
(
RA
.
get
().
find
(
instr
)
!=
RA
.
get
().
end
())
return
true
;
return
false
;
}
string
tmpregname
(
int
i
,
bool
is_float
)
const
{
assert
(
i
==
0
or
i
==
1
);
return
(
is_float
?
"$ft"
:
"$t"
)
+
to_string
(
i
);
}
std
::
map
<
Value
*
,
unsigned
int
>
off
;
// stack offset to $fp
std
::
map
<
Function
*
,
std
::
map
<
int
,
int
>>
func_arg_off
;
// to $sp
std
::
map
<
Function
*
,
int
>
func_arg_N
;
// total space for args
std
::
map
<
BasicBlock
*
,
std
::
vector
<
std
::
pair
<
Value
*
,
Value
*>>>
phi_map
;
std
::
map
<
Constant
*
,
std
::
string
>
ROdata
;
unsigned
int
stackN
;
// function local vars and so on
Function
*
cur_func
;
static
string
regname
(
int
i
,
bool
is_float
=
false
)
{
string
name
;
if
(
is_float
)
{
assert
(
false
&&
"not implemented!"
);
}
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
);
}
return
name
;
}
Module
*
m
;
vector
<
string
>
output
;
pair
<
string
,
bool
>
getRegName
(
Value
*
,
int
=
0
)
const
;
// register allocation
LRA
::
LiveRangeAnalyzer
LRA
;
void
IR2assem
(
Instruction
&
,
BasicBlock
&
);
void
IR2assem
(
LoadInst
*
);
void
IR2assem
(
StoreInst
*
);
void
IR2assem
(
ReturnInst
*
);
void
IR2assem
(
GetElementPtrInst
*
);
void
IR2assem
(
CallInst
*
);
void
IR2assem
(
BranchInst
*
);
void
IR2assem
(
BinaryInst
*
);
void
IR2assem
(
FpToSiInst
*
);
void
IR2assem
(
SiToFpInst
*
);
void
IR2assem
(
PhiInst
*
)
{}
// The Instructions below will do nothing
void
IR2assem
(
AllocaInst
*
)
{}
// integration with BranchInst
void
IR2assem
(
CmpInst
*
)
{}
void
IR2assem
(
FCmpInst
*
)
{}
void
IR2assem
(
ZextInst
*
)
{}
};
#endif
include/codegen/liverange.hpp
View file @
0454682c
...
...
@@ -2,6 +2,7 @@
#define LIVERANGE_HPP
#include "Module.h"
#include "Value.h"
#include <iostream>
#include <map>
...
...
@@ -27,7 +28,6 @@ struct Interval {
using
LiveSet
=
set
<
Value
*>
;
using
PhiMap
=
map
<
BasicBlock
*
,
vector
<
pair
<
Value
*
,
Value
*>>>
;
using
LiveInterval
=
pair
<
Interval
,
Value
*>
;
struct
LiveIntervalCMP
{
bool
operator
()(
LiveInterval
const
&
lhs
,
LiveInterval
const
&
rhs
)
const
{
if
(
lhs
.
first
.
i
!=
rhs
.
first
.
i
)
...
...
@@ -36,29 +36,31 @@ struct LiveIntervalCMP {
return
lhs
.
second
<
rhs
.
second
;
}
};
using
LVITS
=
set
<
LiveInterval
,
LiveIntervalCMP
>
;
class
LiveRangeAnalyzer
{
public:
friend
class
CodeGen
;
public:
LiveRangeAnalyzer
(
Module
*
m_
,
PhiMap
&
phi_map_
)
:
m
(
m_
),
phi_map
(
phi_map_
)
{}
LiveRangeAnalyzer
()
=
delete
;
void
run
();
//
void run();
void
run
(
Function
*
);
void
clear
();
void
print
(
Function
*
func
,
bool
printSet
=
true
);
string
print_liveSet
(
const
LiveSet
&
ls
)
{
void
print
(
Function
*
func
,
bool
printSet
=
true
)
const
;
string
print_liveSet
(
const
LiveSet
&
ls
)
const
{
string
s
=
"[ "
;
for
(
auto
k
:
ls
)
s
+=
k
->
get_name
()
+
" "
;
s
+=
"]"
;
return
s
;
}
string
print_interval
(
Interval
&
i
)
{
string
print_interval
(
Interval
&
i
)
const
{
return
"<"
+
to_string
(
i
.
i
)
+
", "
+
to_string
(
i
.
j
)
+
">"
;
}
const
LVITS
&
get
()
{
return
liveIntervals
;
}
private:
Module
*
m
;
...
...
@@ -68,7 +70,8 @@ class LiveRangeAnalyzer {
map
<
Value
*
,
int
>
instr_id
;
map
<
pair
<
Value
*
,
Value
*>
,
int
>
cpstmt_id
;
const
PhiMap
&
phi_map
;
set
<
LiveInterval
,
LiveIntervalCMP
>
liveIntervals
;
LVITS
liveIntervals
;
map
<
Value
*
,
Interval
>
intervalmap
;
void
make_id
(
Function
*
);
void
make_interval
(
Function
*
);
...
...
@@ -86,6 +89,10 @@ class LiveRangeAnalyzer {
// Require: out-set is already set
// Return: the in-set(will not set IN-map)
LiveSet
transferFunction
(
Instruction
*
);
public:
const
decltype
(
instr_id
)
&
get_instr_id
()
{
return
instr_id
;
}
const
decltype
(
intervalmap
)
&
get_interval_map
()
{
return
intervalmap
;
}
};
}
// namespace LRA
#endif
include/codegen/regalloc.hpp
View file @
0454682c
#include "Value.h"
#include "liverange.hpp"
// using std::transform;
#include <iostream>
#include <string>
using
std
::
cout
;
using
std
::
endl
;
using
std
::
to_string
;
using
namespace
LRA
;
namespace
RA
{
#define MAXR 32
bool
no_reg_alloca
(
Value
*
v
);
struct
ActiveCMP
{
bool
operator
()(
LiveInterval
const
&
lhs
,
LiveInterval
const
&
rhs
)
const
{
if
(
lhs
.
first
.
j
!=
rhs
.
first
.
j
)
...
...
@@ -18,15 +27,20 @@ struct ActiveCMP {
class
RegAllocator
{
public:
RegAllocator
(
const
uint
R_
)
:
R
(
R_
),
used
{
false
}
{}
RegAllocator
(
const
uint
R_
)
:
R
(
R_
),
used
{
false
}
{
assert
(
R
<=
MAXR
);
}
RegAllocator
()
=
delete
;
// input set is sorted by increasing start point
void
LinearScan
(
set
<
LiveInterval
>
&
liveints
);
void
LinearScan
(
const
LVITS
&
liveints
);
void
reset
();
const
map
<
Value
*
,
int
>
&
get
()
const
{
return
regmap
;
}
void
print
(
string
(
*
regname
)(
int
))
{
for
(
auto
[
op
,
reg
]
:
regmap
)
cout
<<
op
->
get_name
()
<<
" ~ "
<<
regname
(
reg
)
<<
endl
;
}
private:
const
uint
R
;
bool
used
[
MAXR
];
bool
used
[
MAXR
+
1
];
// index range: 1 ~ R
map
<
Value
*
,
int
>
regmap
;
// sorted by increasing end point
set
<
LiveInterval
,
ActiveCMP
>
active
;
...
...
src/codegen/codegen.cpp
View file @
0454682c
// 局部变量究竟保存在哪里?
// alloca会返回一个指针,这个指针指向一块可用的内存区域
// 这个该如何体现在assemb上?
// NOTE: 参数类型需要额外考虑!
#include "codegen.hpp"
#include "BasicBlock.h"
...
...
@@ -21,6 +15,7 @@
#include <sstream>
#include <string>
#include <sys/types.h>
#include <tuple>
#include <utility>
#include <vector>
...
...
@@ -37,30 +32,23 @@
using
std
::
to_string
;
class
Reg
{
public:
Reg
(
int
index
)
:
id
(
index
)
{}
int
id
;
string
print
()
{
if
(
id
==
0
)
return
"$zero"
;
if
(
id
==
1
)
return
"$ra"
;
if
(
id
==
2
)
return
"$tp"
;
if
(
id
==
3
)
return
"$sp"
;
if
(
4
<=
id
and
id
<=
11
)
return
"$a"
+
to_string
(
id
-
4
);
if
(
12
<=
id
and
id
<=
20
)
return
"$t"
+
to_string
(
id
-
12
);
if
(
id
==
22
)
return
"$fp"
;
assert
(
false
);
pair
<
string
,
bool
>
CodeGen
::
getRegName
(
Value
*
v
,
int
i
)
const
{
assert
(
i
==
0
or
i
==
1
);
bool
find
;
string
name
;
bool
is_float
=
v
->
get_type
()
->
is_float_type
();
auto
regmap
=
RA
.
get
();
if
(
regmap
.
find
(
v
)
==
regmap
.
end
())
{
name
=
tmpregname
(
i
,
is_float
);
find
=
false
;
}
else
{
auto
regid
=
regmap
.
find
(
v
)
->
second
;
name
=
regname
(
regid
,
is_float
);
find
=
true
;
}
};
return
{
name
,
find
};
}
void
CodeGen
::
getPhiMap
()
{
...
...
@@ -95,12 +83,25 @@ CodeGen::run() {
}
// arguments: stack transfer
for
(
auto
&
func
:
m
->
get_functions
())
if
(
not
func
.
is_declaration
())
compute_arg_info
(
&
func
);
//
if (not func.is_declaration())
compute_arg_info
(
&
func
);
// funtions
for
(
auto
&
func
:
m
->
get_functions
())
{
if
(
not
func
.
is_declaration
())
{
LRA
.
run
(
&
func
);
RA
.
LinearScan
(
LRA
.
get
());
std
::
cout
<<
"register map for function: "
<<
func
.
get_name
()
<<
std
::
endl
;
RA
.
print
([](
int
i
)
{
return
regname
(
i
);
});
auto
regmap
=
RA
.
get
();
for
(
auto
[
_
,
op
]
:
LRA
.
get
())
{
if
(
regmap
.
find
(
op
)
==
regmap
.
end
())
std
::
cout
<<
"no reg belongs to "
<<
op
->
get_name
()
<<
std
::
endl
;
}
cur_func
=
&
func
;
output
.
push_back
(
""
);
output
.
push_back
(
".globl "
+
func
.
get_name
());
...
...
@@ -140,37 +141,49 @@ CodeGen::run() {
}
void
CodeGen
::
ptrContent2reg
(
Value
*
ptr
,
int
id
)
{
CodeGen
::
ptrContent2reg
(
Value
*
ptr
,
string
reg_name
)
{
auto
ele_tp
=
ptr
->
get_type
()
->
get_pointer_element_type
();
assert
(
ele_tp
);
bool
is_float
=
ele_tp
->
is_float_type
();
string
instr_ir
=
(
is_float
?
"fld"
:
"ld"
);
string
reg_name
=
(
is_float
?
"$fa"
:
"$a"
)
+
to_string
(
id
);
string
suff
=
suffix
(
ele_tp
);
auto
[
addr_reg
,
find
]
=
getRegName
(
ptr
,
1
);
if
(
not
find
)
addr_reg
=
"$t1"
;
if
(
dynamic_cast
<
GlobalVariable
*>
(
ptr
))
{
output
.
push_back
(
"la.local "
+
reg_name
+
", "
+
ptr
->
get_name
());
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
output
.
push_back
(
"la.local "
+
addr_reg
+
", "
+
ptr
->
get_name
());
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
addr_reg
+
", 0"
);
}
else
if
(
dynamic_cast
<
AllocaInst
*>
(
ptr
))
{
/* auto alloc_instr = static_cast<AllocaInst *>(ptr);
* string suff = suffix(alloc_instr->get_alloca_type()); */
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
ptr
]
));
to_string
(
off
.
at
(
ptr
)
));
}
else
if
(
dynamic_cast
<
GetElementPtrInst
*>
(
ptr
))
{
// auto GEP_instr = static_cast<GetElementPtrInst *>(ptr);
output
.
push_back
(
"ld.d "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
ptr
]));
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
if
(
not
find
)
{
output
.
push_back
(
"ld.d "
+
addr_reg
+
", $fp, -"
+
to_string
(
off
.
at
(
ptr
)));
}
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
addr_reg
+
", 0"
);
}
else
assert
(
false
&&
"unknown type"
);
}
void
CodeGen
::
value2reg
(
Value
*
v
,
int
i
d
)
{
string
CodeGen
::
value2reg
(
Value
*
v
,
int
i
)
{
bool
is_float
=
v
->
get_type
()
->
is_float_type
();
auto
reg_name
=
(
is_float
?
"$fa"
:
"$a"
)
+
to_string
(
id
);
string
tmp_ireg
=
"$t0"
;
string
tmp_ireg
=
"$t"
+
to_string
(
i
);
auto
[
reg_name
,
find
]
=
getRegName
(
v
,
i
);
if
(
find
)
return
reg_name
;
// now is the stack allocation case
if
(
dynamic_cast
<
Constant
*>
(
v
))
{
if
(
v
==
ConstantInt
::
get
(
0
,
m
))
return
"$zero"
;
auto
constant
=
static_cast
<
Constant
*>
(
v
);
#ifdef __RO_PART__
if
(
ROdata
.
find
(
constant
)
==
ROdata
.
end
())
...
...
@@ -182,6 +195,7 @@ CodeGen::value2reg(Value *v, int id) {
instr_ir
=
"fld.s"
;
else
assert
(
false
&&
"wait for completion"
);
// bug here: maybe
output
.
push_back
(
"la.local "
+
tmp_ireg
+
", "
+
addr
);
output
.
push_back
(
instr_ir
+
" "
+
reg_name
+
", "
+
tmp_ireg
+
", 0"
);
#else
...
...
@@ -217,7 +231,8 @@ CodeGen::value2reg(Value *v, int id) {
}
else
if
(
dynamic_cast
<
AllocaInst
*>
(
v
))
{
// auto alloc_instr = dynamic_cast<AllocaInst *>(v);
// give the stack address
output
.
push_back
(
"addi.d "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
v
]));
output
.
push_back
(
"addi.d "
+
reg_name
+
", $fp, -"
+
to_string
(
off
.
at
(
v
)));
}
else
if
(
dynamic_cast
<
Argument
*>
(
v
))
{
auto
args
=
cur_func
->
get_args
();
int
id
=
1
;
...
...
@@ -226,12 +241,14 @@ CodeGen::value2reg(Value *v, int id) {
break
;
string
instr_ir
=
is_float
?
"fld"
:
"ld"
;
output
.
push_back
(
instr_ir
+
suffix
(
v
->
get_type
())
+
" "
+
reg_name
+
", $fp, "
+
to_string
(
func_arg_off
[
cur_func
][
id
]));
", $fp, "
+
to_string
(
func_arg_off
.
at
(
cur_func
).
at
(
id
)));
}
else
{
string
instr_ir
=
is_float
?
"fld"
:
"ld"
;
output
.
push_back
(
instr_ir
+
suffix
(
v
->
get_type
())
+
" "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
v
]
));
", $fp, -"
+
to_string
(
off
.
at
(
v
)
));
}
return
reg_name
;
}
void
...
...
@@ -250,20 +267,7 @@ CodeGen::compute_arg_info(Function *func) {
}
for
(
arg_id
=
1
;
arg_id
<=
func
->
get_num_of_args
();
++
arg_id
)
arg_off
[
arg_id
]
=
argN
-
arg_off
[
arg_id
];
func_arg_N
[
func
]
=
STACK_ALIGN
(
argN
);
}
void
CodeGen
::
stackMemDealloc
()
{
// 7: return value should be determined already!
output
.
push_back
(
cur_func
->
get_name
()
+
"_end:"
);
output
.
push_back
(
"# epilog"
);
output
.
push_back
(
"ld.d $ra, $sp, "
+
to_string
(
stackN
-
8
));
output
.
push_back
(
"ld.d $fp, $sp, "
+
to_string
(
stackN
-
16
));
/* output.push_back("ld.d $ra, $fp, -8");
* output.push_back("ld.d $fp, $fp, -16"); */
output
.
push_back
(
"addi.d $sp, $sp, "
+
to_string
(
stackN
));
output
.
push_back
(
"jr $ra"
);
func_arg_N
[
func
]
=
argN
;
}
// the addr for opk is: fp - off[opk]
...
...
@@ -294,20 +298,39 @@ CodeGen::stackMemAlloc() {
output
.
push_back
(
"st.d $fp, $sp, "
+
to_string
(
stackN
-
16
));
output
.
push_back
(
"addi.d $fp, $sp, "
+
to_string
(
stackN
));
}
void
CodeGen
::
stackMemDealloc
()
{
// 7: return value should be determined already!
output
.
push_back
(
cur_func
->
get_name
()
+
"_end:"
);
output
.
push_back
(
"# epilog"
);
output
.
push_back
(
"ld.d $ra, $sp, "
+
to_string
(
stackN
-
8
));
output
.
push_back
(
"ld.d $fp, $sp, "
+
to_string
(
stackN
-
16
));
/* output.push_back("ld.d $ra, $fp, -8");
* output.push_back("ld.d $fp, $fp, -16"); */
output
.
push_back
(
"addi.d $sp, $sp, "
+
to_string
(
stackN
));
output
.
push_back
(
"jr $ra"
);
}
void
CodeGen
::
IR2assem
(
FpToSiInst
*
instr
)
{
assert
(
instr
->
get_operand
(
0
)
->
get_type
()
==
m
->
get_float_type
());
assert
(
instr
->
get_dest_type
()
==
m
->
get_int32_type
());
value2reg
(
instr
->
get_operand
(
0
));
output
.
push_back
(
"ftintrz.w.s $fa0, $fa0"
);
output
.
push_back
(
"movfr2gr.s $a0, $fa0"
);
string
f_reg
=
value2reg
(
instr
->
get_operand
(
0
));
auto
[
i_reg
,
_
]
=
getRegName
(
instr
);
output
.
push_back
(
"ftintrz.w.s "
+
f_reg
+
", "
+
f_reg
);
output
.
push_back
(
"movfr2gr.s "
+
i_reg
+
", "
+
f_reg
);
gencopy
(
instr
,
i_reg
);
}
void
CodeGen
::
IR2assem
(
SiToFpInst
*
instr
)
{
assert
(
instr
->
get_operand
(
0
)
->
get_type
()
==
m
->
get_int32_type
());
assert
(
instr
->
get_dest_type
()
==
m
->
get_float_type
());
output
.
push_back
(
"movgr2fr.w $fa0, $a0"
);
output
.
push_back
(
"ffint.s.w $fa0, $fa0"
);
string
i_reg
=
value2reg
(
instr
->
get_operand
(
0
));
auto
[
f_reg
,
_
]
=
getRegName
(
instr
);
output
.
push_back
(
"movgr2fr.w "
+
f_reg
+
", "
+
i_reg
);
output
.
push_back
(
"ffint.s.w "
+
f_reg
+
", "
+
f_reg
);
gencopy
(
instr
,
f_reg
);
}
string
...
...
@@ -355,10 +378,12 @@ CodeGen::bool2branch(Instruction *instr) {
reverse
=
true
;
break
;
}
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
return
instr_ir
+
(
reverse
?
" $a1, $a0,"
:
" $a0, $a1,"
);
auto
reg1
=
value2reg
(
instr
->
get_operand
(
0
),
0
);
auto
reg2
=
value2reg
(
instr
->
get_operand
(
1
),
1
);
return
instr_ir
+
" "
+
(
reverse
?
(
reg2
+
", "
+
reg1
)
:
(
reg1
+
", "
+
reg2
))
+
","
;
}
else
{
assert
(
false
&&
"not implemented"
);
switch
(
fcmp_instr
->
get_cmp_op
())
{
case
FCmpInst
::
EQ
:
instr_ir
=
"fcmp.ceq.s $fcc0"
;
...
...
@@ -381,9 +406,9 @@ CodeGen::bool2branch(Instruction *instr) {
instr_ir
=
"fcmp.cle.s $fcc0"
;
break
;
}
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
output
.
push_back
(
instr_ir
+
", "
+
"$fa0, $fa1"
);
auto
reg1
=
value2reg
(
instr
->
get_operand
(
0
),
0
);
auto
reg2
=
value2reg
(
instr
->
get_operand
(
1
),
1
);
output
.
push_back
(
instr_ir
+
", "
+
reg1
+
", "
+
reg2
);
return
(
reverse
?
"bceqz $fcc0,"
:
"bcnez $fcc0,"
);
}
}
...
...
@@ -407,42 +432,79 @@ CodeGen::IR2assem(BranchInst *instr) {
void
CodeGen
::
IR2assem
(
CallInst
*
instr
)
{
auto
func
=
static_cast
<
Function
*>
(
instr
->
get_operand
(
0
));
auto
func_argN
=
func_arg_N
.
at
(
func
);
// analyze the registers that need to be stored
int
cur_i
=
LRA
.
get_instr_id
().
at
(
instr
);
auto
regmap
=
RA
.
get
();
//
int
storeN
=
0
;
vector
<
std
::
tuple
<
Value
*
,
string
,
int
>>
store_record
;
for
(
auto
[
op
,
interval
]
:
LRA
.
get_interval_map
())
{
if
(
RA
::
no_reg_alloca
(
op
))
continue
;
if
(
interval
.
i
<=
cur_i
and
cur_i
<=
interval
.
j
)
{
int
tplen
=
typeLen
(
op
->
get_type
());
storeN
=
ALIGN
(
storeN
,
tplen
)
+
tplen
;
auto
name
=
regname
(
regmap
.
at
(
op
),
op
->
get_type
()
->
is_float_type
());
store_record
.
push_back
({
op
,
name
,
storeN
});
}
}
int
totalN
=
STACK_ALIGN
(
ALIGN
(
storeN
,
8
)
+
func_argN
);
// cout << "debug: " << STACK_ALIGN(12) << endl;
// stack space allocation
output
.
push_back
(
"addi.d $sp, $sp, -"
+
to_string
(
func_arg_N
[
func
]
));
output
.
push_back
(
"addi.d $sp, $sp, -"
+
to_string
(
totalN
));
string
instr_ir
,
suff
,
reg
;
// place the reserved regs
for
(
auto
[
op
,
reg
,
off
]
:
store_record
)
{
instr_ir
=
(
op
->
get_type
()
->
is_float_type
()
?
"fst"
:
"st"
);
suff
=
suffix
(
op
->
get_type
());
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", $sp, "
+
to_string
(
totalN
-
off
));
}
// place the arguments
for
(
int
i
=
1
;
i
<
instr
->
get_num_operand
();
i
++
)
{
auto
arg
=
instr
->
get_operand
(
i
);
// auto tplen = typeLen(arg->get_type());
instr_ir
=
(
arg
->
get_type
()
->
is_float_type
()
?
"fst"
:
"st"
);
suff
=
suffix
(
arg
->
get_type
());
reg
=
(
arg
->
get_type
()
->
is_float_type
()
?
"$fa0"
:
"$a0"
);
value2reg
(
arg
);
reg
=
value2reg
(
arg
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", $sp, "
+
to_string
(
func_arg_off
[
func
][
i
]
));
to_string
(
func_arg_off
.
at
(
func
).
at
(
i
)
));
}
output
.
push_back
(
"bl "
+
func
->
get_name
());
output
.
push_back
(
"addi.d $sp, $sp, "
+
to_string
(
func_arg_N
[
func
]));
// bug here: maybe
gencopy
(
instr
,
instr
->
get_type
()
->
is_float_type
()
?
"$fa0"
:
"$a0"
);
// restore the reserved regs
for
(
auto
[
op
,
reg
,
off
]
:
store_record
)
{
instr_ir
=
(
op
->
get_type
()
->
is_float_type
()
?
"fld"
:
"ld"
);
suff
=
suffix
(
op
->
get_type
());
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", $sp, "
+
to_string
(
totalN
-
off
));
}
output
.
push_back
(
"addi.d $sp, $sp, "
+
to_string
(
totalN
));
// output.push_back("addi.d $fp, $sp, " + to_string(stackN));
}
void
CodeGen
::
IR2assem
(
BinaryInst
*
instr
)
{
auto
is_float
=
instr
->
get_type
()
->
is_float_type
(
);
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
auto
reg1
=
value2reg
(
instr
->
get_operand
(
0
),
0
);
auto
reg2
=
value2reg
(
instr
->
get_operand
(
1
),
1
);
auto
[
reg
,
_
]
=
getRegName
(
instr
);
string
instr_ir
=
instr
->
get_instr_op_name
();
if
(
instr_ir
==
"sdiv"
)
instr_ir
=
"div"
;
string
suff
=
suffix
(
instr
->
get_type
());
output
.
push_back
(
instr_ir
+
suff
+
(
is_float
?
" $fa0, $fa0, $fa1"
:
" $a0, $a0, $a1"
)
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", "
+
reg1
+
", "
+
reg2
);
gencopy
(
instr
,
reg
);
}
void
CodeGen
::
IR2assem
(
GetElementPtrInst
*
instr
)
{
value2reg
(
instr
->
get_operand
(
0
),
0
);
assert
(
instr
->
get_num_operand
()
<=
3
);
auto
addr_reg
=
value2reg
(
instr
->
get_operand
(
0
),
0
);
assert
(
addr_reg
==
"$t0"
);
Type
*
type
=
instr
->
get_operand
(
0
)
->
get_type
();
for
(
int
i
=
1
;
i
<
instr
->
get_num_operand
();
i
++
)
{
int
size
;
...
...
@@ -454,38 +516,52 @@ CodeGen::IR2assem(GetElementPtrInst *instr) {
type
=
type
->
get_pointer_element_type
();
}
else
assert
(
false
&&
"GEP translation error"
);
value2reg
(
instr
->
get_operand
(
i
),
1
);
value2reg
(
ConstantInt
::
get
(
size
,
m
),
2
);
output
.
push_back
(
"mul.w $a1, $a1, $a2"
);
output
.
push_back
(
"add.d $a0, $a0, $a1"
);
if
(
size
!=
4
)
{
// getelementptr [5 x i32], [5 x i32]* @w, i32 0, i32 4
assert
(
instr
->
get_operand
(
i
)
==
ConstantInt
::
get
(
0
,
m
)
&&
"cminus support only 1 dimension array, so first offset is "
"must 0"
);
continue
;
}
auto
off_reg
=
value2reg
(
instr
->
get_operand
(
i
),
1
);
// value2reg(ConstantInt::get(size, m), 2);
output
.
push_back
(
"slli.d "
+
off_reg
+
", "
+
off_reg
+
", 2"
);
output
.
push_back
(
"add.d "
+
addr_reg
+
", "
+
addr_reg
+
", "
+
off_reg
);
}
gencopy
(
instr
,
addr_reg
);
}
void
CodeGen
::
IR2assem
(
LoadInst
*
instr
)
{
// move the address to a0
ptrContent2reg
(
instr
->
get_lval
());
assert
(
instr
->
get_type
()
==
instr
->
get_load_type
())
;
auto
[
reg
,
find
]
=
getRegName
(
instr
);
ptrContent2reg
(
instr
->
get_lval
()
,
reg
);
if
(
not
find
)
// this if is just for logically clear
last_reg
=
reg
;
}
void
CodeGen
::
IR2assem
(
StoreInst
*
instr
)
{
value2reg
(
instr
->
get_rval
(),
0
);
value2reg
(
instr
->
get_lval
(),
1
);
auto
reg1
=
value2reg
(
instr
->
get_rval
(),
0
);
auto
reg2
=
value2reg
(
instr
->
get_lval
(),
1
);
bool
is_float
=
instr
->
get_rval
()
->
get_type
()
->
is_float_type
();
string
instr_ir
=
(
is_float
?
"fst"
:
"st"
);
string
suff
=
suffix
(
instr
->
get_rval
()
->
get_type
());
string
reg
=
(
is_float
?
"$fa0"
:
"$a0"
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", $a1, 0"
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg1
+
", "
+
reg2
+
", 0"
);
}
void
CodeGen
::
IR2assem
(
ReturnInst
*
instr
)
{
if
(
not
instr
->
is_void_ret
())
{
auto
value
=
instr
->
get_operand
(
0
);
value2reg
(
value
);
auto
is_float
=
value
->
get_type
()
->
is_float_type
();
auto
reg
=
value2reg
(
value
);
if
(
is_float
and
reg
!=
"$fa0"
)
output
.
push_back
(
"fmov.s $fa0, "
+
reg
);
else
if
(
not
is_float
and
reg
!=
"$a0"
)
output
.
push_back
(
"or $a0, $zero "
+
reg
);
}
output
.
push_back
(
"b "
+
cur_func
->
get_name
()
+
"_end"
);
}
...
...
src/codegen/liverange.cpp
View file @
0454682c
...
...
@@ -11,6 +11,7 @@ LiveRangeAnalyzer::clear() {
OUT
.
clear
();
instr_id
.
clear
();
cpstmt_id
.
clear
();
intervalmap
.
clear
();
liveIntervals
.
clear
();
}
...
...
@@ -133,24 +134,23 @@ LiveRangeAnalyzer::run(Function *func) {
void
LiveRangeAnalyzer
::
make_interval
(
Function
*
)
{
map
<
Value
*
,
Interval
>
liverange
;
for
(
int
time
=
1
;
time
<=
ir_cnt
;
++
time
)
{
for
(
auto
op
:
IN
.
at
(
time
))
{
auto
&
interval
=
liverange
[
op
];
auto
&
interval
=
intervalmap
[
op
];
if
(
interval
.
i
==
0
)
// uninitialized
interval
.
i
=
time
-
1
;
else
interval
.
j
=
time
-
1
;
}
for
(
auto
op
:
OUT
.
at
(
time
))
{
auto
&
interval
=
liverange
[
op
];
auto
&
interval
=
intervalmap
[
op
];
if
(
interval
.
i
==
0
)
// uninitialized
interval
.
i
=
time
;
else
interval
.
j
=
time
;
}
}
for
(
auto
[
op
,
interval
]
:
liverange
)
for
(
auto
[
op
,
interval
]
:
intervalmap
)
liveIntervals
.
insert
({
interval
,
op
});
}
...
...
@@ -188,7 +188,7 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) {
}
void
LiveRangeAnalyzer
::
print
(
Function
*
func
,
bool
printSet
)
{
// for debug
LiveRangeAnalyzer
::
print
(
Function
*
func
,
bool
printSet
)
const
{
// for debug
cout
<<
"Function "
<<
func
->
get_name
()
<<
endl
;
for
(
auto
&
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
&
instr
:
bb
.
get_instructions
())
{
...
...
@@ -200,7 +200,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug
for
(
auto
pr
:
phi_map
.
find
(
&
bb
)
->
second
)
{
auto
[
lv
,
rv
]
=
pr
;
auto
idx
=
cpstmt_id
.
at
(
pr
);
cout
<<
cpstmt_id
[
pr
]
<<
". "
<<
lv
->
get_name
()
<<
" = "
cout
<<
cpstmt_id
.
at
(
pr
)
<<
". "
<<
lv
->
get_name
()
<<
" = "
<<
(
rv
->
get_name
()
==
""
?
rv
->
print
()
:
rv
->
get_name
())
<<
endl
;
...
...
@@ -213,8 +213,8 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug
}
}
// normal ir
cout
<<
instr_id
[
&
instr
]
<<
". "
<<
instr
.
print
()
<<
" # "
<<
&
instr
<<
endl
;
cout
<<
instr_id
.
at
(
&
instr
)
<<
". "
<<
instr
.
print
()
<<
" # "
<<
&
instr
<<
endl
;
if
(
not
printSet
)
continue
;
auto
idx
=
instr_id
.
at
(
&
instr
);
...
...
src/codegen/regalloc.cpp
View file @
0454682c
#include "regalloc.hpp"
#include "Instruction.h"
#include "liverange.hpp"
#include <algorithm>
using
std
::
for_each
;
using
namespace
RA
;
bool
RA
::
no_reg_alloca
(
Value
*
v
)
{
auto
instr
=
static_cast
<
Instruction
*>
(
v
);
return
instr
->
is_alloca
()
or
instr
->
is_cmp
()
or
instr
->
is_fcmp
()
or
instr
->
is_zext
();
}
void
RegAllocator
::
reset
()
{
regmap
.
clear
();
active
.
clear
();
for_each
(
used
,
used
+
R
,
[](
bool
&
u
)
{
u
=
false
;
});
for_each
(
used
,
used
+
R
+
1
,
[](
bool
&
u
)
{
u
=
false
;
});
}
void
RegAllocator
::
LinearScan
(
set
<
LiveInterval
>
&
liveints
)
{
RegAllocator
::
LinearScan
(
const
LVITS
&
liveints
)
{
reset
();
int
reg
;
for
(
auto
liveint
:
liveints
)
{
if
(
no_reg_alloca
(
liveint
.
second
))
continue
;
ExpireOldIntervals
(
liveint
);
if
(
active
.
size
()
==
R
)
SpillAtInterval
(
liveint
);
...
...
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