Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
2
2025ustc-jianmu-compiler
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
43
Merge Requests
43
CI / CD
CI / CD
Pipelines
Jobs
Schedules
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
compiler_staff
2025ustc-jianmu-compiler
Commits
f40efe88
Commit
f40efe88
authored
Dec 03, 2025
by
Yang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
publish lab4
parent
93702b62
Changes
32
Hide whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
1903 additions
and
860 deletions
+1903
-860
CMakeLists.txt
CMakeLists.txt
+1
-1
include/cminusfc/cminusf_builder.hpp
include/cminusfc/cminusf_builder.hpp
+0
-5
include/codegen/CodeGen.hpp
include/codegen/CodeGen.hpp
+0
-14
include/codegen/Register.hpp
include/codegen/Register.hpp
+1
-1
include/lightir/BasicBlock.hpp
include/lightir/BasicBlock.hpp
+1
-2
include/lightir/Instruction.hpp
include/lightir/Instruction.hpp
+5
-3
include/passes/DeadCode.hpp
include/passes/DeadCode.hpp
+1
-1
include/passes/Dominators.hpp
include/passes/Dominators.hpp
+17
-17
include/passes/FuncInfo.hpp
include/passes/FuncInfo.hpp
+6
-2
include/passes/LICM.hpp
include/passes/LICM.hpp
+0
-4
include/passes/LoopDetection.hpp
include/passes/LoopDetection.hpp
+1
-0
lldb_formatters.py
lldb_formatters.py
+2
-1
src/cminusfc/cminusf_builder.cpp
src/cminusfc/cminusf_builder.cpp
+0
-17
src/cminusfc/main.cpp
src/cminusfc/main.cpp
+54
-35
src/codegen/CodeGen.cpp
src/codegen/CodeGen.cpp
+574
-300
src/io/io.c
src/io/io.c
+53
-6
src/io/io.h
src/io/io.h
+2
-2
src/lightir/BasicBlock.cpp
src/lightir/BasicBlock.cpp
+9
-9
src/lightir/Function.cpp
src/lightir/Function.cpp
+1
-10
src/lightir/IRprinter.cpp
src/lightir/IRprinter.cpp
+1
-1
src/lightir/Instruction.cpp
src/lightir/Instruction.cpp
+18
-2
src/lightir/Module.cpp
src/lightir/Module.cpp
+17
-17
src/lightir/User.cpp
src/lightir/User.cpp
+1
-1
src/passes/DeadCode.cpp
src/passes/DeadCode.cpp
+9
-8
src/passes/Dominators.cpp
src/passes/Dominators.cpp
+30
-33
src/passes/FuncInfo.cpp
src/passes/FuncInfo.cpp
+224
-209
src/passes/LICM.cpp
src/passes/LICM.cpp
+119
-130
src/passes/LoopDetection.cpp
src/passes/LoopDetection.cpp
+18
-1
src/passes/Mem2Reg.cpp
src/passes/Mem2Reg.cpp
+31
-26
tests/4-opt/CMakeLists.txt
tests/4-opt/CMakeLists.txt
+9
-0
tests/4-opt/eval_lab4.cpp
tests/4-opt/eval_lab4.cpp
+695
-0
tests/CMakeLists.txt
tests/CMakeLists.txt
+3
-2
No files found.
CMakeLists.txt
View file @
f40efe88
...
@@ -63,4 +63,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
...
@@ -63,4 +63,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories
(
${
PROJECT_SOURCE_DIR
}
)
include_directories
(
${
PROJECT_SOURCE_DIR
}
)
include_directories
(
${
PROJECT_BINARY_DIR
}
)
include_directories
(
${
PROJECT_BINARY_DIR
}
)
add_subdirectory
(
src
)
add_subdirectory
(
src
)
#
add_subdirectory(tests)
add_subdirectory
(
tests
)
include/cminusfc/cminusf_builder.hpp
View file @
f40efe88
...
@@ -67,15 +67,10 @@ class CminusfBuilder : public ASTVisitor {
...
@@ -67,15 +67,10 @@ class CminusfBuilder : public ASTVisitor {
auto
*
output_float_fun
=
auto
*
output_float_fun
=
Function
::
create
(
output_float_type
,
"outputFloat"
,
module
);
Function
::
create
(
output_float_type
,
"outputFloat"
,
module
);
auto
*
neg_idx_except_type
=
FunctionType
::
get
(
TyVoid
,
{});
auto
*
neg_idx_except_fun
=
Function
::
create
(
neg_idx_except_type
,
"neg_idx_except"
,
module
);
scope
.
enter
();
scope
.
enter
();
scope
.
push
(
"input"
,
input_fun
);
scope
.
push
(
"input"
,
input_fun
);
scope
.
push
(
"output"
,
output_fun
);
scope
.
push
(
"output"
,
output_fun
);
scope
.
push
(
"outputFloat"
,
output_float_fun
);
scope
.
push
(
"outputFloat"
,
output_float_fun
);
scope
.
push
(
"neg_idx_except"
,
neg_idx_except_fun
);
}
}
Module
*
getModule
()
const
{
return
module
;
}
Module
*
getModule
()
const
{
return
module
;
}
...
...
include/codegen/CodeGen.hpp
View file @
f40efe88
...
@@ -64,18 +64,6 @@ class CodeGen {
...
@@ -64,18 +64,6 @@ class CodeGen {
void
gen_fptosi
();
void
gen_fptosi
();
void
gen_epilogue
();
void
gen_epilogue
();
static
std
::
string
label_name
(
BasicBlock
*
bb
)
{
return
"."
+
bb
->
get_parent
()
->
get_name
()
+
"_"
+
bb
->
get_name
();
}
static
std
::
string
func_exit_label_name
(
Function
*
func
)
{
return
func
->
get_name
()
+
"_exit"
;
}
static
std
::
string
fcmp_label_name
(
BasicBlock
*
bb
,
unsigned
cnt
)
{
return
label_name
(
bb
)
+
"_fcmp_"
+
std
::
to_string
(
cnt
);
}
struct
{
struct
{
/* 随着ir遍历设置 */
/* 随着ir遍历设置 */
Function
*
func
{
nullptr
};
// 当前函数
Function
*
func
{
nullptr
};
// 当前函数
...
@@ -84,14 +72,12 @@ class CodeGen {
...
@@ -84,14 +72,12 @@ class CodeGen {
/* 在allocate()中设置 */
/* 在allocate()中设置 */
unsigned
frame_size
{
0
};
// 当前函数的栈帧大小
unsigned
frame_size
{
0
};
// 当前函数的栈帧大小
std
::
unordered_map
<
Value
*
,
int
>
offset_map
{};
// 指针相对 fp 的偏移
std
::
unordered_map
<
Value
*
,
int
>
offset_map
{};
// 指针相对 fp 的偏移
unsigned
fcmp_cnt
{
0
};
// fcmp 的计数器, 用于创建 fcmp 需要的 label
void
clear
()
{
void
clear
()
{
func
=
nullptr
;
func
=
nullptr
;
bb
=
nullptr
;
bb
=
nullptr
;
inst
=
nullptr
;
inst
=
nullptr
;
frame_size
=
0
;
frame_size
=
0
;
fcmp_cnt
=
0
;
offset_map
.
clear
();
offset_map
.
clear
();
}
}
...
...
include/codegen/Register.hpp
View file @
f40efe88
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
* $r23 - $r31 $s0 - $s8 static
* $r23 - $r31 $s0 - $s8 static
*
*
* Floating-point Register Convention
* Floating-point Register Convention
* Name
Alias
Meaning
* Name
Alias
Meaning
* $f0-$f1 $fa0-$fa1 argument/return value
* $f0-$f1 $fa0-$fa1 argument/return value
* $f2-$f7 $fa2-$fa7 argument
* $f2-$f7 $fa2-$fa7 argument
* $f8-$f23 $ft0-$ft15 temporary
* $f8-$f23 $ft0-$ft15 temporary
...
...
include/lightir/BasicBlock.hpp
View file @
f40efe88
...
@@ -20,8 +20,7 @@ class BasicBlock : public Value {
...
@@ -20,8 +20,7 @@ class BasicBlock : public Value {
~
BasicBlock
()
override
;
~
BasicBlock
()
override
;
static
BasicBlock
*
create
(
Module
*
m
,
const
std
::
string
&
name
,
static
BasicBlock
*
create
(
Module
*
m
,
const
std
::
string
&
name
,
Function
*
parent
)
{
Function
*
parent
)
{
auto
prefix
=
name
.
empty
()
?
""
:
"label_"
;
return
new
BasicBlock
(
m
,
name
,
parent
);
return
new
BasicBlock
(
m
,
prefix
+
name
,
parent
);
}
}
/****************api about cfg****************/
/****************api about cfg****************/
...
...
include/lightir/Instruction.hpp
View file @
f40efe88
...
@@ -214,6 +214,8 @@ public:
...
@@ -214,6 +214,8 @@ public:
Value
*
get_condition
()
const
{
return
get_operand
(
0
);
}
Value
*
get_condition
()
const
{
return
get_operand
(
0
);
}
void
replace_all_bb_match
(
BasicBlock
*
need_replace
,
BasicBlock
*
replace_to
);
std
::
string
print
()
override
;
std
::
string
print
()
override
;
};
};
...
@@ -251,8 +253,8 @@ class StoreInst : public Instruction {
...
@@ -251,8 +253,8 @@ class StoreInst : public Instruction {
public:
public:
static
StoreInst
*
create_store
(
Value
*
val
,
Value
*
ptr
,
BasicBlock
*
bb
);
static
StoreInst
*
create_store
(
Value
*
val
,
Value
*
ptr
,
BasicBlock
*
bb
);
Value
*
get_
r
val
()
const
{
return
this
->
get_operand
(
0
);
}
Value
*
get_val
()
const
{
return
this
->
get_operand
(
0
);
}
Value
*
get_
lval
()
const
{
return
this
->
get_operand
(
1
);
}
Value
*
get_
ptr
()
const
{
return
this
->
get_operand
(
1
);
}
std
::
string
print
()
override
;
std
::
string
print
()
override
;
};
};
...
@@ -264,7 +266,7 @@ class LoadInst : public Instruction {
...
@@ -264,7 +266,7 @@ class LoadInst : public Instruction {
public:
public:
static
LoadInst
*
create_load
(
Value
*
ptr
,
BasicBlock
*
bb
,
const
std
::
string
&
name
=
""
);
static
LoadInst
*
create_load
(
Value
*
ptr
,
BasicBlock
*
bb
,
const
std
::
string
&
name
=
""
);
Value
*
get_
lval
()
const
{
return
this
->
get_operand
(
0
);
}
Value
*
get_
ptr
()
const
{
return
this
->
get_operand
(
0
);
}
Type
*
get_load_type
()
const
{
return
get_type
();
}
Type
*
get_load_type
()
const
{
return
get_type
();
}
std
::
string
print
()
override
;
std
::
string
print
()
override
;
...
...
include/passes/DeadCode.hpp
View file @
f40efe88
...
@@ -15,7 +15,7 @@ class FuncInfo;
...
@@ -15,7 +15,7 @@ class FuncInfo;
class
DeadCode
:
public
TransformPass
{
class
DeadCode
:
public
TransformPass
{
public:
public:
/**
/**
*
*
* @param m 所属 Module
* @param m 所属 Module
* @param remove_unreachable_bb 是否需要删除不可达的 BasicBlocks
* @param remove_unreachable_bb 是否需要删除不可达的 BasicBlocks
...
...
include/passes/Dominators.hpp
View file @
f40efe88
...
@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass {
...
@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass {
void
run
()
override
;
void
run
()
override
;
// 获取基本块的直接支配节点
// 获取基本块的直接支配节点
BasicBlock
*
get_idom
(
const
BasicBlock
*
bb
)
const
{
return
idom_
.
at
(
bb
);
}
BasicBlock
*
get_idom
(
BasicBlock
*
bb
)
const
{
return
idom_
.
at
(
bb
);
}
const
std
::
set
<
BasicBlock
*>
&
get_dominance_frontier
(
const
BasicBlock
*
bb
)
{
const
std
::
set
<
BasicBlock
*>
&
get_dominance_frontier
(
BasicBlock
*
bb
)
{
return
dom_frontier_
.
at
(
bb
);
return
dom_frontier_
.
at
(
bb
);
}
}
const
std
::
set
<
BasicBlock
*>
&
get_dom_tree_succ_blocks
(
const
BasicBlock
*
bb
)
{
const
std
::
set
<
BasicBlock
*>
&
get_dom_tree_succ_blocks
(
BasicBlock
*
bb
)
{
return
dom_tree_succ_blocks_
.
at
(
bb
);
return
dom_tree_succ_blocks_
.
at
(
bb
);
}
}
...
@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass {
...
@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass {
void
dump_dominator_tree
();
void
dump_dominator_tree
();
// functions for dominance tree
// functions for dominance tree
bool
is_dominate
(
const
BasicBlock
*
bb1
,
const
BasicBlock
*
bb2
)
const
{
bool
is_dominate
(
BasicBlock
*
bb1
,
BasicBlock
*
bb2
)
const
{
return
dom_tree_L_
.
at
(
bb1
)
<=
dom_tree_L_
.
at
(
bb2
)
&&
return
dom_tree_L_
.
at
(
bb1
)
<=
dom_tree_L_
.
at
(
bb2
)
&&
dom_tree_R_
.
at
(
bb1
)
>=
dom_tree_L_
.
at
(
bb2
);
dom_tree_R_
.
at
(
bb1
)
>=
dom_tree_L_
.
at
(
bb2
);
}
}
...
@@ -54,33 +54,33 @@ class Dominators : public FunctionAnalysisPass {
...
@@ -54,33 +54,33 @@ class Dominators : public FunctionAnalysisPass {
void
create_dom_tree_succ
();
void
create_dom_tree_succ
();
void
create_dom_dfs_order
();
void
create_dom_dfs_order
();
BasicBlock
*
intersect
(
BasicBlock
*
b1
,
const
BasicBlock
*
b2
)
const
;
BasicBlock
*
intersect
(
BasicBlock
*
b1
,
BasicBlock
*
b2
)
const
;
void
create_reverse_post_order
();
void
create_reverse_post_order
();
void
set_idom
(
const
BasicBlock
*
bb
,
BasicBlock
*
idom
)
{
idom_
[
bb
]
=
idom
;
}
void
set_idom
(
BasicBlock
*
bb
,
BasicBlock
*
idom
)
{
idom_
[
bb
]
=
idom
;
}
void
set_dominance_frontier
(
const
BasicBlock
*
bb
,
std
::
set
<
BasicBlock
*>&
df
)
{
void
set_dominance_frontier
(
BasicBlock
*
bb
,
std
::
set
<
BasicBlock
*>&
df
)
{
dom_frontier_
[
bb
].
clear
();
dom_frontier_
[
bb
].
clear
();
dom_frontier_
[
bb
].
insert
(
df
.
begin
(),
df
.
end
());
dom_frontier_
[
bb
].
insert
(
df
.
begin
(),
df
.
end
());
}
}
void
add_dom_tree_succ_block
(
const
BasicBlock
*
bb
,
BasicBlock
*
dom_tree_succ_bb
)
{
void
add_dom_tree_succ_block
(
BasicBlock
*
bb
,
BasicBlock
*
dom_tree_succ_bb
)
{
dom_tree_succ_blocks_
[
bb
].
insert
(
dom_tree_succ_bb
);
dom_tree_succ_blocks_
[
bb
].
insert
(
dom_tree_succ_bb
);
}
}
unsigned
int
get_
post_order
(
const
BasicBlock
*
bb
)
const
{
unsigned
int
get_
reversed_post_order
(
BasicBlock
*
bb
)
const
{
return
post_order_
.
at
(
bb
);
return
reversed_
post_order_
.
at
(
bb
);
}
}
// for debug
// for debug
void
print_idom
()
const
;
void
print_idom
()
const
;
void
print_dominance_frontier
();
void
print_dominance_frontier
();
std
::
vector
<
BasicBlock
*>
post_order_vec_
{};
// 逆后序
std
::
vector
<
BasicBlock
*>
reversed_
post_order_vec_
{};
// 逆后序
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
post_order_
{};
// 逆后序
std
::
map
<
BasicBlock
*
,
unsigned
int
>
reversed_post_order_
{};
// 逆后序索引
std
::
map
<
const
BasicBlock
*
,
BasicBlock
*>
idom_
{};
// 直接支配
std
::
map
<
BasicBlock
*
,
BasicBlock
*>
idom_
{};
// 直接支配
std
::
map
<
const
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_frontier_
{};
// 支配边界集合
std
::
map
<
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_frontier_
{};
// 支配边界集合
std
::
map
<
const
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_tree_succ_blocks_
{};
// 支配树中的后继节点
std
::
map
<
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_tree_succ_blocks_
{};
// 支配树中的后继节点
// 支配树上的dfs序L,R
// 支配树上的dfs序L,R
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
dom_tree_L_
;
std
::
map
<
BasicBlock
*
,
unsigned
int
>
dom_tree_L_
;
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
dom_tree_R_
;
std
::
map
<
BasicBlock
*
,
unsigned
int
>
dom_tree_R_
;
std
::
vector
<
BasicBlock
*>
dom_dfs_order_
;
std
::
vector
<
BasicBlock
*>
dom_dfs_order_
;
std
::
vector
<
BasicBlock
*>
dom_post_order_
;
std
::
vector
<
BasicBlock
*>
dom_post_order_
;
...
...
include/passes/FuncInfo.hpp
View file @
f40efe88
...
@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass {
...
@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass {
void
run
()
override
;
void
run
()
override
;
// 函数是否是纯函数
// 函数是否是纯函数
bool
is_pure
(
Function
*
func
)
{
return
!
func
->
is_declaration
()
&&
!
use_libs
.
count
(
func
)
&&
loads
[
func
].
empty
()
&&
stores
[
func
].
empty
();
}
bool
is_pure
(
Function
*
func
)
{
return
!
func
->
is_declaration
()
&&
!
use_libs
[
func
]
&&
loads
[
func
].
empty
()
&&
stores
[
func
].
empty
();
}
// 函数是否使用了 io
bool
use_io
(
Function
*
func
)
{
return
func
->
is_declaration
()
||
use_libs
[
func
];
}
// 返回 StoreInst 存入的变量(全局/局部变量或函数参数)
// 返回 StoreInst 存入的变量(全局/局部变量或函数参数)
static
Value
*
store_ptr
(
const
StoreInst
*
st
);
static
Value
*
store_ptr
(
const
StoreInst
*
st
);
// 返回 LoadInst 加载的变量(全局/局部变量或函数参数)
// 返回 LoadInst 加载的变量(全局/局部变量或函数参数)
static
Value
*
load_ptr
(
const
LoadInst
*
ld
);
static
Value
*
load_ptr
(
const
LoadInst
*
ld
);
// 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数)
// 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数)
std
::
unordered_set
<
Value
*>
get_stores
(
const
CallInst
*
call
);
std
::
unordered_set
<
Value
*>
get_stores
(
const
CallInst
*
call
);
// 返回 CallInst 代表的函数调用间接加载的变量(全局/局部变量或函数参数)
std
::
unordered_set
<
Value
*>
get_loads
(
const
CallInst
*
call
);
private:
private:
// 函数存储的值
// 函数存储的值
std
::
unordered_map
<
Function
*
,
UseMessage
>
stores
;
std
::
unordered_map
<
Function
*
,
UseMessage
>
stores
;
...
...
include/passes/LICM.hpp
View file @
f40efe88
...
@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass {
...
@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass {
std
::
vector
<
Instruction
*>
collect_insts
(
Loop
*
loop
);
std
::
vector
<
Instruction
*>
collect_insts
(
Loop
*
loop
);
void
traverse_loop
(
Loop
*
loop
);
void
traverse_loop
(
Loop
*
loop
);
void
run_on_loop
(
Loop
*
loop
);
void
run_on_loop
(
Loop
*
loop
);
void
collect_loop_info
(
Loop
*
loop
,
std
::
set
<
Value
*>
&
loop_instructions
,
std
::
set
<
Value
*>
&
updated_global
,
bool
&
contains_impure_call
);
};
};
\ No newline at end of file
include/passes/LoopDetection.hpp
View file @
f40efe88
...
@@ -40,6 +40,7 @@ class Loop {
...
@@ -40,6 +40,7 @@ class Loop {
const
std
::
vector
<
Loop
*>&
get_sub_loops
()
{
return
sub_loops_
;
}
const
std
::
vector
<
Loop
*>&
get_sub_loops
()
{
return
sub_loops_
;
}
const
std
::
unordered_set
<
BasicBlock
*>&
get_latches
()
{
return
latches_
;
}
const
std
::
unordered_set
<
BasicBlock
*>&
get_latches
()
{
return
latches_
;
}
void
add_latch
(
BasicBlock
*
bb
)
{
latches_
.
insert
(
bb
);
}
void
add_latch
(
BasicBlock
*
bb
)
{
latches_
.
insert
(
bb
);
}
std
::
string
safe_print
()
const
;
};
};
class
LoopDetection
:
public
FunctionAnalysisPass
{
class
LoopDetection
:
public
FunctionAnalysisPass
{
...
...
lldb_formatters.py
View file @
f40efe88
...
@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
...
@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
,
"BasicBlock"
,
"BasicBlock"
,
"GlobalVariable"
,
"GlobalVariable"
,
"Instruction"
,
"IBinaryInst"
,
"FBinaryInst"
,
"ICmpInst"
,
"FCmpInst"
,
"CallInst"
,
"BranchInst"
,
"ReturnInst"
,
"GetElementPtrInst"
,
"StoreInst"
,
"LoadInst"
,
"AllocaInst"
,
"ZextInst"
,
"FpToSiInst"
,
"SiToFpInst"
,
"PhiInst"
,
"Instruction"
,
"IBinaryInst"
,
"FBinaryInst"
,
"ICmpInst"
,
"FCmpInst"
,
"CallInst"
,
"BranchInst"
,
"ReturnInst"
,
"GetElementPtrInst"
,
"StoreInst"
,
"LoadInst"
,
"AllocaInst"
,
"ZextInst"
,
"FpToSiInst"
,
"SiToFpInst"
,
"PhiInst"
,
"ASMInstruction"
,
"Reg"
,
"FReg"
,
"CFReg"
]
,
"ASMInstruction"
,
"Reg"
,
"FReg"
,
"CFReg"
,
"Loop"
]
for
i
in
types
:
for
i
in
types
:
debugger
.
HandleCommand
(
debugger
.
HandleCommand
(
f"type summary add -F lldb_formatters.SafePrintSummary
{
i
}
-w my"
f"type summary add -F lldb_formatters.SafePrintSummary
{
i
}
-w my"
...
...
src/cminusfc/cminusf_builder.cpp
View file @
f40efe88
...
@@ -329,27 +329,10 @@ Value* CminusfBuilder::visit(ASTVar &node) {
...
@@ -329,27 +329,10 @@ Value* CminusfBuilder::visit(ASTVar &node) {
}
}
}
else
{
}
else
{
auto
*
val
=
node
.
expression
->
accept
(
*
this
);
auto
*
val
=
node
.
expression
->
accept
(
*
this
);
auto
*
exceptBB
=
BasicBlock
::
create
(
module
,
""
,
context
.
func
);
auto
*
contBB
=
BasicBlock
::
create
(
module
,
""
,
context
.
func
);
if
(
val
->
get_type
()
->
is_float_type
())
{
if
(
val
->
get_type
()
->
is_float_type
())
{
val
=
builder
->
create_fptosi
(
val
,
INT32_T
);
val
=
builder
->
create_fptosi
(
val
,
INT32_T
);
}
}
Value
*
is_neg
=
builder
->
create_icmp_lt
(
val
,
CONST_INT
(
0
));
builder
->
create_cond_br
(
is_neg
,
exceptBB
,
contBB
);
builder
->
set_insert_point
(
exceptBB
);
auto
*
neg_idx_except_fun
=
scope
.
find
(
"neg_idx_except"
);
builder
->
create_call
(
dynamic_cast
<
Function
*>
(
neg_idx_except_fun
),
{});
if
(
context
.
func
->
get_return_type
()
->
is_void_type
())
{
builder
->
create_void_ret
();
}
else
if
(
context
.
func
->
get_return_type
()
->
is_float_type
())
{
builder
->
create_ret
(
CONST_FP
(
0.
));
}
else
{
builder
->
create_ret
(
CONST_INT
(
0
));
}
builder
->
set_insert_point
(
contBB
);
Value
*
tmp_ptr
;
Value
*
tmp_ptr
;
if
(
is_int
||
is_float
)
{
if
(
is_int
||
is_float
)
{
tmp_ptr
=
builder
->
create_gep
(
var
,
{
val
});
tmp_ptr
=
builder
->
create_gep
(
var
,
{
val
});
...
...
src/cminusfc/main.cpp
View file @
f40efe88
...
@@ -23,30 +23,30 @@ struct Config {
...
@@ -23,30 +23,30 @@ struct Config {
std
::
filesystem
::
path
input_file
;
std
::
filesystem
::
path
input_file
;
std
::
filesystem
::
path
output_file
;
std
::
filesystem
::
path
output_file
;
bool
emitast
{
false
};
bool
emitast
{
false
};
bool
emitasm
{
false
};
bool
emitasm
{
false
};
bool
emitllvm
{
false
};
bool
emitllvm
{
false
};
// optization conifg
// optization conifg
bool
mem2reg
{
false
};
bool
mem2reg
{
false
};
bool
licm
{
false
};
bool
licm
{
false
};
Config
(
int
argc
,
char
**
argv
)
:
argc
(
argc
),
argv
(
argv
)
{
Config
(
int
argc
,
char
**
argv
)
:
argc
(
argc
),
argv
(
argv
)
{
parse_cmd_line
();
parse_cmd_line
();
check
();
check
();
}
}
private:
private:
int
argc
{
-
1
};
int
argc
{
-
1
};
char
**
argv
{
nullptr
};
char
**
argv
{
nullptr
};
void
parse_cmd_line
();
void
parse_cmd_line
();
void
check
();
void
check
();
// print helper infomation and exit
// print helper infomation and exit
void
print_help
()
const
;
void
print_help
()
const
;
void
print_err
(
const
string
&
msg
)
const
;
void
print_err
(
const
string
&
msg
)
const
;
};
};
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
Config
config
(
argc
,
argv
);
Config
config
(
argc
,
argv
);
auto
syntax_tree
=
parse
(
config
.
input_file
.
c_str
());
auto
syntax_tree
=
parse
(
config
.
input_file
.
c_str
());
...
@@ -55,7 +55,8 @@ int main(int argc, char **argv) {
...
@@ -55,7 +55,8 @@ int main(int argc, char **argv) {
if
(
config
.
emitast
)
{
// if emit ast (lab1), print ast and return
if
(
config
.
emitast
)
{
// if emit ast (lab1), print ast and return
ASTPrinter
printer
;
ASTPrinter
printer
;
ast
.
run_visitor
(
printer
);
ast
.
run_visitor
(
printer
);
}
else
{
}
else
{
Module
*
m
;
Module
*
m
;
CminusfBuilder
builder
;
CminusfBuilder
builder
;
ast
.
run_visitor
(
builder
);
ast
.
run_visitor
(
builder
);
...
@@ -63,11 +64,12 @@ int main(int argc, char **argv) {
...
@@ -63,11 +64,12 @@ int main(int argc, char **argv) {
PassManager
PM
(
m
);
PassManager
PM
(
m
);
// optimization
// optimization
if
(
config
.
mem2reg
)
{
if
(
config
.
mem2reg
)
{
PM
.
add_pass
<
DeadCode
>
(
true
);
PM
.
add_pass
<
Mem2Reg
>
();
PM
.
add_pass
<
Mem2Reg
>
();
PM
.
add_pass
<
DeadCode
>
(
false
);
PM
.
add_pass
<
DeadCode
>
(
false
);
}
}
if
(
config
.
licm
)
{
if
(
config
.
licm
)
{
PM
.
add_pass
<
LoopInvariantCodeMotion
>
();
PM
.
add_pass
<
LoopInvariantCodeMotion
>
();
PM
.
add_pass
<
DeadCode
>
(
false
);
PM
.
add_pass
<
DeadCode
>
(
false
);
}
}
...
@@ -79,13 +81,20 @@ int main(int argc, char **argv) {
...
@@ -79,13 +81,20 @@ int main(int argc, char **argv) {
output_stream
<<
"; ModuleID = 'cminus'
\n
"
;
output_stream
<<
"; ModuleID = 'cminus'
\n
"
;
output_stream
<<
"source_filename = "
<<
abs_path
<<
"
\n\n
"
;
output_stream
<<
"source_filename = "
<<
abs_path
<<
"
\n\n
"
;
output_stream
<<
m
->
print
();
output_stream
<<
m
->
print
();
}
else
if
(
config
.
emitasm
)
{
}
else
if
(
config
.
emitasm
)
{
auto
abs_path
=
std
::
filesystem
::
canonical
(
config
.
input_file
);
config
.
output_file
.
replace_extension
(
"ll"
);
std
::
ofstream
output_stream2
(
config
.
output_file
);
output_stream2
<<
"; ModuleID = 'cminus'
\n
"
;
output_stream2
<<
"source_filename = "
<<
abs_path
<<
"
\n\n
"
;
output_stream2
<<
m
->
print
();
CodeGen
codegen
(
m
);
CodeGen
codegen
(
m
);
codegen
.
run
();
codegen
.
run
();
output_stream
<<
codegen
.
print
();
output_stream
<<
codegen
.
print
();
}
}
delete
m
;
delete
m
;
}
}
return
0
;
return
0
;
...
@@ -96,27 +105,36 @@ void Config::parse_cmd_line() {
...
@@ -96,27 +105,36 @@ void Config::parse_cmd_line() {
for
(
int
i
=
1
;
i
<
argc
;
++
i
)
{
for
(
int
i
=
1
;
i
<
argc
;
++
i
)
{
if
(
argv
[
i
]
==
"-h"
s
||
argv
[
i
]
==
"--help"
s
)
{
if
(
argv
[
i
]
==
"-h"
s
||
argv
[
i
]
==
"--help"
s
)
{
print_help
();
print_help
();
}
else
if
(
argv
[
i
]
==
"-o"
s
)
{
}
else
if
(
argv
[
i
]
==
"-o"
s
)
{
if
(
output_file
.
empty
()
&&
i
+
1
<
argc
)
{
if
(
output_file
.
empty
()
&&
i
+
1
<
argc
)
{
output_file
=
argv
[
i
+
1
];
output_file
=
argv
[
i
+
1
];
i
+=
1
;
i
+=
1
;
}
else
{
}
else
{
print_err
(
"bad output file"
);
print_err
(
"bad output file"
);
}
}
}
else
if
(
argv
[
i
]
==
"-emit-ast"
s
)
{
}
else
if
(
argv
[
i
]
==
"-emit-ast"
s
)
{
emitast
=
true
;
emitast
=
true
;
}
else
if
(
argv
[
i
]
==
"-S"
s
)
{
}
else
if
(
argv
[
i
]
==
"-S"
s
)
{
emitasm
=
true
;
emitasm
=
true
;
}
else
if
(
argv
[
i
]
==
"-emit-llvm"
s
)
{
}
else
if
(
argv
[
i
]
==
"-emit-llvm"
s
)
{
emitllvm
=
true
;
emitllvm
=
true
;
}
else
if
(
argv
[
i
]
==
"-mem2reg"
s
)
{
}
else
if
(
argv
[
i
]
==
"-mem2reg"
s
)
{
mem2reg
=
true
;
mem2reg
=
true
;
}
else
if
(
argv
[
i
]
==
"-licm"
s
)
{
}
else
if
(
argv
[
i
]
==
"-licm"
s
)
{
licm
=
true
;
licm
=
true
;
}
else
{
}
else
{
if
(
input_file
.
empty
())
{
if
(
input_file
.
empty
())
{
input_file
=
argv
[
i
];
input_file
=
argv
[
i
];
}
else
{
}
else
{
string
err
=
string
err
=
"unrecognized command-line option
\'
"
s
+
argv
[
i
]
+
"
\'
"
s
;
"unrecognized command-line option
\'
"
s
+
argv
[
i
]
+
"
\'
"
s
;
print_err
(
err
);
print_err
(
err
);
...
@@ -143,24 +161,25 @@ void Config::check() {
...
@@ -143,24 +161,25 @@ void Config::check() {
}
}
if
(
output_file
.
empty
())
{
if
(
output_file
.
empty
())
{
output_file
=
input_file
.
stem
();
output_file
=
input_file
.
stem
();
if
(
emitllvm
)
{
}
output_file
.
replace_extension
(
".ll"
);
if
(
emitllvm
)
{
}
else
if
(
emitasm
)
{
output_file
.
replace_extension
(
".ll"
);
output_file
.
replace_extension
(
".s"
);
}
}
else
if
(
emitasm
)
{
output_file
.
replace_extension
(
".s"
);
}
}
}
}
void
Config
::
print_help
()
const
{
void
Config
::
print_help
()
const
{
std
::
cout
<<
"Usage: "
<<
exe_name
std
::
cout
<<
"Usage: "
<<
exe_name
<<
" [-h|--help] [-o <target-file>] [-emit-llvm] [-S] [-dump-json]"
<<
" [-h|--help] [-o <target-file>] [-emit-llvm] [-S] [-dump-json]"
"[-mem2reg] [-licm]"
"[-mem2reg] [-licm]"
"<input-file>"
"<input-file>"
<<
std
::
endl
;
<<
std
::
endl
;
exit
(
0
);
exit
(
0
);
}
}
void
Config
::
print_err
(
const
string
&
msg
)
const
{
void
Config
::
print_err
(
const
string
&
msg
)
const
{
std
::
cout
<<
exe_name
<<
": "
<<
msg
<<
std
::
endl
;
std
::
cout
<<
exe_name
<<
": "
<<
msg
<<
std
::
endl
;
exit
(
-
1
);
exit
(
-
1
);
}
}
src/codegen/CodeGen.cpp
View file @
f40efe88
#include "CodeGen.hpp"
#include "CodeGen.hpp"
#include <cstring>
#include "ASMInstruction.hpp"
#include "ASMInstruction.hpp"
#include "BasicBlock.hpp"
#include "CodeGenUtil.hpp"
#include "CodeGenUtil.hpp"
#include "Function.hpp"
#include "Instruction.hpp"
#include "Register.hpp"
#include "Register.hpp"
#include "Type.hpp"
#include <string>
std
::
string
ASMInstruction
::
safe_print
()
const
void
CodeGen
::
allocate
()
{
{
switch
(
type
)
{
case
Instruction
:
case
Attribute
:
return
content
;
case
Label
:
return
content
+
":"
;
case
Comment
:
return
"# "
+
content
;
}
return
"<error>"
;
}
void
CodeGen
::
allocate
()
{
// 备份 $ra $fp
unsigned
offset
=
PROLOGUE_OFFSET_BASE
;
unsigned
offset
=
PROLOGUE_OFFSET_BASE
;
for
(
auto
&
arg
:
context
.
func
->
get_args
())
// 为每个参数分配栈空间
{
for
(
auto
&
arg
:
context
.
func
->
get_args
())
{
auto
size
=
arg
->
get_type
()
->
get_size
();
auto
size
=
arg
->
get_type
()
->
get_size
();
offset
=
offset
+
size
;
offset
=
ALIGN
(
offset
+
size
,
size
)
;
context
.
offset_map
[
arg
]
=
-
static_cast
<
int
>
(
offset
);
context
.
offset_map
[
arg
]
=
-
static_cast
<
int
>
(
offset
);
}
}
for
(
auto
&
bb
:
context
.
func
->
get_basic_blocks
())
// 为指令结果分配栈空间
{
for
(
auto
bb
:
context
.
func
->
get_basic_blocks
())
{
for
(
auto
&
instr
:
bb
->
get_instructions
())
for
(
auto
instr
:
bb
->
get_instructions
())
{
{
// 每个非 void 的定值都分配栈空间
if
(
not
instr
->
is_void
())
if
(
not
instr
->
is_void
())
{
{
auto
size
=
instr
->
get_type
()
->
get_size
();
auto
size
=
instr
->
get_type
()
->
get_size
();
offset
=
offset
+
size
;
offset
=
ALIGN
(
offset
+
size
,
size
>
8
?
8
:
size
)
;
context
.
offset_map
[
instr
]
=
-
static_cast
<
int
>
(
offset
);
context
.
offset_map
[
instr
]
=
-
static_cast
<
int
>
(
offset
);
}
}
// alloca 的副作用:分配额外空间
if
(
instr
->
is_alloca
())
if
(
instr
->
is_alloca
())
{
{
auto
*
alloca_inst
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
auto
*
alloca_inst
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
auto
alloc_size
=
alloca_inst
->
get_alloca_type
()
->
get_size
();
auto
alloc_size
=
alloca_inst
->
get_alloca_type
()
->
get_size
();
offset
+=
alloc_size
;
offset
=
ALIGN
(
offset
+
alloc_size
,
alloc_size
>
8
?
8
:
alloc_size
)
;
}
}
}
}
}
}
// 分配栈空间,需要是 16 的整数倍
context
.
frame_size
=
ALIGN
(
offset
,
PROLOGUE_ALIGN
);
context
.
frame_size
=
ALIGN
(
offset
,
PROLOGUE_ALIGN
);
}
}
void
CodeGen
::
copy_stmt
()
{
void
CodeGen
::
copy_stmt
()
for
(
auto
succ
:
context
.
bb
->
get_succ_basic_blocks
())
{
{
for
(
auto
inst
:
succ
->
get_instructions
())
{
for
(
auto
&
succ
:
context
.
bb
->
get_succ_basic_blocks
())
if
(
inst
->
is_phi
())
{
{
// 遍历后继块中 phi 的定值 bb
for
(
auto
&
inst
:
succ
->
get_instructions
())
for
(
unsigned
i
=
1
;
i
<
inst
->
get_operands
().
size
();
i
+=
2
)
{
{
// phi 的定值 bb 是当前翻译块
if
(
inst
->
is_phi
())
if
(
inst
->
get_operand
(
i
)
==
context
.
bb
)
{
{
auto
*
lvalue
=
inst
->
get_operand
(
i
-
1
);
for
(
unsigned
i
=
1
;
i
<
inst
->
get_operands
().
size
();
i
+=
2
)
if
(
lvalue
->
get_type
()
->
is_float_type
())
{
{
if
(
inst
->
get_operand
(
i
)
==
context
.
bb
)
{
auto
*
lvalue
=
inst
->
get_operand
(
i
-
1
);
if
(
lvalue
->
get_type
()
->
is_float_type
())
{
load_to_freg
(
lvalue
,
FReg
::
fa
(
0
));
load_to_freg
(
lvalue
,
FReg
::
fa
(
0
));
store_from_freg
(
inst
,
FReg
::
fa
(
0
));
store_from_freg
(
inst
,
FReg
::
fa
(
0
));
}
else
{
}
else
{
load_to_greg
(
lvalue
,
Reg
::
a
(
0
));
load_to_greg
(
lvalue
,
Reg
::
a
(
0
));
store_from_greg
(
inst
,
Reg
::
a
(
0
));
store_from_greg
(
inst
,
Reg
::
a
(
0
));
}
}
break
;
break
;
}
}
// 如果没有找到当前翻译块,说明是 undef,无事可做
}
}
}
else
{
}
else
{
break
;
break
;
}
}
}
}
}
}
}
}
void
CodeGen
::
load_to_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
void
CodeGen
::
load_to_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
assert
(
val
->
get_type
()
->
is_integer_type
()
||
assert
(
val
->
get_type
()
->
is_integer_type
()
||
val
->
get_type
()
->
is_pointer_type
());
val
->
get_type
()
->
is_pointer_type
());
if
(
auto
*
constant
=
dynamic_cast
<
ConstantInt
*>
(
val
))
{
if
(
auto
*
constant
=
dynamic_cast
<
ConstantInt
*>
(
val
))
int32_t
val
=
constant
->
get_value
();
{
i
f
(
IS_IMM_12
(
val
))
{
i
nt32_t
val1
=
constant
->
get_value
();
append_inst
(
ADDI
WORD
,
{
reg
.
print
(),
"$zero"
,
std
::
to_string
(
val
)});
if
(
IS_IMM_12
(
val1
))
}
else
{
{
load_large_int32
(
val
,
reg
);
append_inst
(
ADDI
WORD
,
{
reg
.
print
(),
"$zero"
,
std
::
to_string
(
val1
)}
);
}
}
}
else
if
(
auto
*
global
=
dynamic_cast
<
GlobalVariable
*>
(
val
))
{
else
{
load_large_int32
(
val1
,
reg
);
}
}
else
if
(
auto
*
global
=
dynamic_cast
<
GlobalVariable
*>
(
val
))
{
append_inst
(
LOAD_ADDR
,
{
reg
.
print
(),
global
->
get_name
()});
append_inst
(
LOAD_ADDR
,
{
reg
.
print
(),
global
->
get_name
()});
}
else
{
}
else
{
load_from_stack_to_greg
(
val
,
reg
);
load_from_stack_to_greg
(
val
,
reg
);
}
}
}
}
void
CodeGen
::
load_large_int32
(
int32_t
val
,
const
Reg
&
reg
)
{
void
CodeGen
::
load_large_int32
(
int32_t
val
,
const
Reg
&
reg
)
int32_t
high_20
=
val
>>
12
;
// si20
{
int32_t
high_20
=
val
>>
12
;
uint32_t
low_12
=
val
&
LOW_12_MASK
;
uint32_t
low_12
=
val
&
LOW_12_MASK
;
append_inst
(
LU12I_W
,
{
reg
.
print
(),
std
::
to_string
(
high_20
)});
append_inst
(
LU12I_W
,
{
reg
.
print
(),
std
::
to_string
(
high_20
)});
append_inst
(
ORI
,
{
reg
.
print
(),
reg
.
print
(),
std
::
to_string
(
low_12
)});
append_inst
(
ORI
,
{
reg
.
print
(),
reg
.
print
(),
std
::
to_string
(
low_12
)});
}
}
void
CodeGen
::
load_large_int64
(
int64_t
val
,
const
Reg
&
reg
)
{
void
CodeGen
::
load_large_int64
(
int64_t
val
,
const
Reg
&
reg
)
{
auto
low_32
=
static_cast
<
int32_t
>
(
val
&
LOW_32_MASK
);
auto
low_32
=
static_cast
<
int32_t
>
(
val
&
LOW_32_MASK
);
load_large_int32
(
low_32
,
reg
);
load_large_int32
(
low_32
,
reg
);
auto
high_32
=
static_cast
<
int32_t
>
(
val
>>
32
);
auto
high_32
=
static_cast
<
int32_t
>
(
val
>>
32
);
int32_t
high_32_low_20
=
(
high_32
<<
12
)
>>
12
;
// si20
int32_t
high_32_low_20
=
(
high_32
<<
12
)
>>
12
;
int32_t
high_32_high_12
=
high_32
>>
20
;
// si12
int32_t
high_32_high_12
=
high_32
>>
20
;
append_inst
(
LU32I_D
,
{
reg
.
print
(),
std
::
to_string
(
high_32_low_20
)});
append_inst
(
LU32I_D
,
{
reg
.
print
(),
std
::
to_string
(
high_32_low_20
)});
append_inst
(
LU52I_D
,
append_inst
(
LU52I_D
,
{
reg
.
print
(),
reg
.
print
(),
std
::
to_string
(
high_32_high_12
)});
{
reg
.
print
(),
reg
.
print
(),
std
::
to_string
(
high_32_high_12
)});
}
}
void
CodeGen
::
load_from_stack_to_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
void
CodeGen
::
load_from_stack_to_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset_str
=
std
::
to_string
(
offset
);
auto
offset_str
=
std
::
to_string
(
offset
);
auto
*
type
=
val
->
get_type
();
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
IS_IMM_12
(
offset
))
if
(
type
->
is_int1_type
())
{
{
if
(
type
->
is_int1_type
())
{
append_inst
(
LOAD
BYTE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
LOAD
BYTE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
LOAD
WORD
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
LOAD
WORD
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
else
{
// Pointer
}
else
{
append_inst
(
LOAD
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
LOAD
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
}
}
else
{
}
else
{
load_large_int64
(
offset
,
reg
);
load_large_int64
(
offset
,
reg
);
append_inst
(
ADD
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
reg
.
print
()});
append_inst
(
ADD
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
reg
.
print
()});
if
(
type
->
is_int1_type
())
{
if
(
type
->
is_int1_type
())
{
append_inst
(
LOAD
BYTE
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
append_inst
(
LOAD
BYTE
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
LOAD
WORD
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
append_inst
(
LOAD
WORD
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
}
else
{
// Pointer
}
else
{
append_inst
(
LOAD
DOUBLE
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
append_inst
(
LOAD
DOUBLE
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
}
}
}
}
}
}
void
CodeGen
::
store_from_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
void
CodeGen
::
store_from_greg
(
Value
*
val
,
const
Reg
&
reg
)
{
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset_str
=
std
::
to_string
(
offset
);
auto
offset_str
=
std
::
to_string
(
offset
);
auto
*
type
=
val
->
get_type
();
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
IS_IMM_12
(
offset
))
if
(
type
->
is_int1_type
())
{
{
if
(
type
->
is_int1_type
())
{
append_inst
(
STORE
BYTE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
STORE
BYTE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
STORE
WORD
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
STORE
WORD
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
else
{
// Pointer
}
else
{
append_inst
(
STORE
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
STORE
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
}
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
load_large_int64
(
offset
,
addr
);
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
if
(
type
->
is_int1_type
())
{
if
(
type
->
is_int1_type
())
{
append_inst
(
STORE
BYTE
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
append_inst
(
STORE
BYTE
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
STORE
WORD
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
append_inst
(
STORE
WORD
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
}
else
{
// Pointer
}
else
{
append_inst
(
STORE
DOUBLE
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
append_inst
(
STORE
DOUBLE
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
}
}
}
}
}
}
void
CodeGen
::
load_to_freg
(
Value
*
val
,
const
FReg
&
freg
)
{
void
CodeGen
::
load_to_freg
(
Value
*
val
,
const
FReg
&
freg
)
{
assert
(
val
->
get_type
()
->
is_float_type
());
assert
(
val
->
get_type
()
->
is_float_type
());
if
(
auto
*
constant
=
dynamic_cast
<
ConstantFP
*>
(
val
))
{
if
(
auto
*
constant
=
dynamic_cast
<
ConstantFP
*>
(
val
))
float
val
=
constant
->
get_value
();
{
load_float_imm
(
val
,
freg
);
float
val1
=
constant
->
get_value
();
}
else
{
load_float_imm
(
val1
,
freg
);
}
else
{
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset_str
=
std
::
to_string
(
offset
);
auto
offset_str
=
std
::
to_string
(
offset
);
if
(
IS_IMM_12
(
offset
))
{
if
(
IS_IMM_12
(
offset
))
{
append_inst
(
FLOAD
SINGLE
,
{
freg
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
FLOAD
SINGLE
,
{
freg
.
print
(),
"$fp"
,
offset_str
});
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
load_large_int64
(
offset
,
addr
);
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
...
@@ -185,18 +229,24 @@ void CodeGen::load_to_freg(Value *val, const FReg &freg) {
...
@@ -185,18 +229,24 @@ void CodeGen::load_to_freg(Value *val, const FReg &freg) {
}
}
}
}
void
CodeGen
::
load_float_imm
(
float
val
,
const
FReg
&
r
)
{
void
CodeGen
::
load_float_imm
(
float
val
,
const
FReg
&
r
)
int32_t
bytes
=
*
reinterpret_cast
<
int32_t
*>
(
&
val
);
{
int32_t
bytes
=
0
;
memcpy
(
&
bytes
,
&
val
,
sizeof
(
float
));
load_large_int32
(
bytes
,
Reg
::
t
(
8
));
load_large_int32
(
bytes
,
Reg
::
t
(
8
));
append_inst
(
GR2FR
WORD
,
{
r
.
print
(),
Reg
::
t
(
8
).
print
()});
append_inst
(
GR2FR
WORD
,
{
r
.
print
(),
Reg
::
t
(
8
).
print
()});
}
}
void
CodeGen
::
store_from_freg
(
Value
*
val
,
const
FReg
&
r
)
{
void
CodeGen
::
store_from_freg
(
Value
*
val
,
const
FReg
&
r
)
{
auto
offset
=
context
.
offset_map
.
at
(
val
);
auto
offset
=
context
.
offset_map
.
at
(
val
);
if
(
IS_IMM_12
(
offset
))
{
if
(
IS_IMM_12
(
offset
))
{
auto
offset_str
=
std
::
to_string
(
offset
);
auto
offset_str
=
std
::
to_string
(
offset
);
append_inst
(
FSTORE
SINGLE
,
{
r
.
print
(),
"$fp"
,
offset_str
});
append_inst
(
FSTORE
SINGLE
,
{
r
.
print
(),
"$fp"
,
offset_str
});
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
load_large_int64
(
offset
,
addr
);
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
...
@@ -204,14 +254,18 @@ void CodeGen::store_from_freg(Value *val, const FReg &r) {
...
@@ -204,14 +254,18 @@ void CodeGen::store_from_freg(Value *val, const FReg &r) {
}
}
}
}
void
CodeGen
::
gen_prologue
()
{
void
CodeGen
::
gen_prologue
()
if
(
IS_IMM_12
(
-
static_cast
<
int
>
(
context
.
frame_size
)))
{
{
if
(
IS_IMM_12
(
-
static_cast
<
int
>
(
context
.
frame_size
)))
{
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $fp, $sp, -16"
);
append_inst
(
"st.d $fp, $sp, -16"
);
append_inst
(
"addi.d $fp, $sp, 0"
);
append_inst
(
"addi.d $fp, $sp, 0"
);
append_inst
(
"addi.d $sp, $sp, "
+
append_inst
(
"addi.d $sp, $sp, "
+
std
::
to_string
(
-
static_cast
<
int
>
(
context
.
frame_size
)));
std
::
to_string
(
-
static_cast
<
int
>
(
context
.
frame_size
)));
}
else
{
}
else
{
load_large_int64
(
context
.
frame_size
,
Reg
::
t
(
0
));
load_large_int64
(
context
.
frame_size
,
Reg
::
t
(
0
));
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $fp, $sp, -16"
);
append_inst
(
"st.d $fp, $sp, -16"
);
...
@@ -221,177 +275,405 @@ void CodeGen::gen_prologue() {
...
@@ -221,177 +275,405 @@ void CodeGen::gen_prologue() {
int
garg_cnt
=
0
;
int
garg_cnt
=
0
;
int
farg_cnt
=
0
;
int
farg_cnt
=
0
;
for
(
auto
arg
:
context
.
func
->
get_args
())
{
for
(
auto
arg
:
context
.
func
->
get_args
())
if
(
arg
->
get_type
()
->
is_float_type
())
{
{
if
(
arg
->
get_type
()
->
is_float_type
())
{
store_from_freg
(
arg
,
FReg
::
fa
(
farg_cnt
++
));
store_from_freg
(
arg
,
FReg
::
fa
(
farg_cnt
++
));
}
else
{
// int or pointer
}
else
{
store_from_greg
(
arg
,
Reg
::
a
(
garg_cnt
++
));
store_from_greg
(
arg
,
Reg
::
a
(
garg_cnt
++
));
}
}
}
}
}
}
void
CodeGen
::
gen_epilogue
()
{
void
CodeGen
::
gen_epilogue
()
// TODO 根据你的理解设定函数的 epilogue
{
throw
not_implemented_error
{
__FUNCTION__
};
append_inst
(
context
.
func
->
get_name
()
+
"_exit"
,
ASMInstruction
::
Label
);
if
(
IS_IMM_12
(
-
static_cast
<
int
>
(
context
.
frame_size
)))
{
append_inst
(
"addi.d $sp, $sp, "
+
std
::
to_string
(
static_cast
<
int
>
(
context
.
frame_size
)));
append_inst
(
"ld.d $ra, $sp, -8"
);
append_inst
(
"ld.d $fp, $sp, -16"
);
append_inst
(
"jr $ra"
);
}
else
{
load_large_int64
(
context
.
frame_size
,
Reg
::
t
(
0
));
append_inst
(
"add.d $sp, $sp, $t0"
);
append_inst
(
"ld.d $ra, $sp, -8"
);
append_inst
(
"ld.d $fp, $sp, -16"
);
append_inst
(
"jr $ra"
);
}
}
}
void
CodeGen
::
gen_ret
()
{
void
CodeGen
::
gen_ret
()
// TODO 函数返回,思考如何处理返回值、寄存器备份,如何返回调用者地址
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
retInst
=
dynamic_cast
<
ReturnInst
*>
(
context
.
inst
);
auto
*
retType
=
context
.
func
->
get_return_type
();
if
(
retType
->
is_void_type
())
{
append_inst
(
"addi.w $a0, $zero, 0"
);
}
else
if
(
retType
->
is_float_type
())
{
load_to_freg
(
retInst
->
get_operand
(
0
),
FReg
::
fa
(
0
));
}
else
{
load_to_greg
(
retInst
->
get_operand
(
0
),
Reg
::
a
(
0
));
}
std
::
string
label
=
context
.
func
->
get_name
()
+
"_exit"
;
append_inst
(
"b "
+
label
);
}
}
void
CodeGen
::
gen_br
()
{
void
CodeGen
::
gen_br
()
auto
*
branchInst
=
static_cast
<
BranchInst
*>
(
context
.
inst
);
{
if
(
branchInst
->
is_cond_br
())
{
auto
*
branchInst
=
dynamic_cast
<
BranchInst
*>
(
context
.
inst
);
// TODO 补全条件跳转的情况
if
(
branchInst
->
is_cond_br
())
throw
not_implemented_error
{
__FUNCTION__
};
{
}
else
{
load_to_greg
(
branchInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
auto
*
branchbb
=
static_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
0
));
auto
*
trueBB
=
dynamic_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
1
));
append_inst
(
"b "
+
label_name
(
branchbb
));
auto
*
falseBB
=
dynamic_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
2
));
append_inst
(
"bnez"
,
{
Reg
::
t
(
0
).
print
(),
trueBB
->
get_name
()});
append_inst
(
"b"
,
{
falseBB
->
get_name
()});
}
else
{
auto
*
branchbb
=
dynamic_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
0
));
append_inst
(
"b "
+
branchbb
->
get_name
());
}
}
}
}
void
CodeGen
::
gen_binary
()
{
void
CodeGen
::
gen_binary
()
{
load_to_greg
(
context
.
inst
->
get_operand
(
0
),
Reg
::
t
(
0
));
load_to_greg
(
context
.
inst
->
get_operand
(
0
),
Reg
::
t
(
0
));
load_to_greg
(
context
.
inst
->
get_operand
(
1
),
Reg
::
t
(
1
));
load_to_greg
(
context
.
inst
->
get_operand
(
1
),
Reg
::
t
(
1
));
switch
(
context
.
inst
->
get_instr_type
())
{
switch
(
context
.
inst
->
get_instr_type
())
case
Instruction
::
add
:
{
append_inst
(
"add.w $t2, $t0, $t1"
);
case
Instruction
::
add
:
break
;
output
.
emplace_back
(
"add.w $t2, $t0, $t1"
);
case
Instruction
::
sub
:
break
;
append_inst
(
"sub.w $t2, $t0, $t1"
);
case
Instruction
::
sub
:
break
;
output
.
emplace_back
(
"sub.w $t2, $t0, $t1"
);
case
Instruction
::
mul
:
break
;
append_inst
(
"mul.w $t2, $t0, $t1"
);
case
Instruction
::
mul
:
break
;
output
.
emplace_back
(
"mul.w $t2, $t0, $t1"
);
case
Instruction
::
sdiv
:
break
;
append_inst
(
"div.w $t2, $t0, $t1"
);
case
Instruction
::
sdiv
:
break
;
output
.
emplace_back
(
"div.w $t2, $t0, $t1"
);
default:
break
;
assert
(
false
);
default:
assert
(
false
);
}
}
store_from_greg
(
context
.
inst
,
Reg
::
t
(
2
));
store_from_greg
(
context
.
inst
,
Reg
::
t
(
2
));
if
(
context
.
inst
->
get_instr_type
()
==
Instruction
::
mul
)
{
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
if
(
context
.
inst
->
get_instr_type
()
==
Instruction
::
sdiv
)
{
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
4
,
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
}
}
void
CodeGen
::
gen_float_binary
()
{
void
CodeGen
::
gen_float_binary
()
// TODO 浮点类型的二元指令
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
floatInst
=
dynamic_cast
<
FBinaryInst
*>
(
context
.
inst
);
auto
op
=
floatInst
->
get_instr_type
();
auto
firstNum
=
floatInst
->
get_operand
(
0
);
load_to_freg
(
firstNum
,
FReg
::
ft
(
1
));
auto
secondNum
=
floatInst
->
get_operand
(
1
);
load_to_freg
(
secondNum
,
FReg
::
ft
(
2
));
switch
(
op
)
{
case
Instruction
::
fadd
:
append_inst
(
"fadd.s"
,
{
FReg
::
ft
(
0
).
print
(),
FReg
::
ft
(
1
).
print
(),
FReg
::
ft
(
2
).
print
()});
break
;
case
Instruction
::
fsub
:
append_inst
(
"fsub.s"
,
{
FReg
::
ft
(
0
).
print
(),
FReg
::
ft
(
1
).
print
(),
FReg
::
ft
(
2
).
print
()});
break
;
case
Instruction
::
fmul
:
append_inst
(
"fmul.s"
,
{
FReg
::
ft
(
0
).
print
(),
FReg
::
ft
(
1
).
print
(),
FReg
::
ft
(
2
).
print
()});
break
;
case
Instruction
::
fdiv
:
append_inst
(
"fdiv.s"
,
{
FReg
::
ft
(
0
).
print
(),
FReg
::
ft
(
1
).
print
(),
FReg
::
ft
(
2
).
print
()});
break
;
default:
std
::
cout
<<
"wrong gen_float_binary
\n
"
;
break
;
}
store_from_freg
(
context
.
inst
,
FReg
::
ft
(
0
));
if
(
context
.
inst
->
get_instr_type
()
==
Instruction
::
fmul
)
{
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
if
(
context
.
inst
->
get_instr_type
()
==
Instruction
::
fdiv
)
{
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
4
,
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
}
}
void
CodeGen
::
gen_alloca
()
{
void
CodeGen
::
gen_alloca
()
/* 我们已经为 alloca 的内容分配空间,在此我们还需保存 alloca
{
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针
auto
*
allocaInst
=
dynamic_cast
<
AllocaInst
*>
(
context
.
inst
);
*/
auto
offset
=
context
.
offset_map
[
allocaInst
];
// TODO 将 alloca 出空间的起始地址保存在栈帧上
auto
trueOffset
=
offset
-
static_cast
<
int
>
(
allocaInst
->
get_alloca_type
()
->
get_size
());
throw
not_implemented_error
{
__FUNCTION__
};
if
(
IS_IMM_12
(
trueOffset
))
append_inst
(
"addi.d"
,
{
Reg
::
t
(
0
).
print
(),
"$fp"
,
std
::
to_string
(
trueOffset
)});
else
{
load_to_greg
(
ConstantInt
::
get
(
trueOffset
,
m
),
Reg
::
t
(
1
));
append_inst
(
"add.d"
,
{
Reg
::
t
(
0
).
print
(),
"$fp"
,
Reg
::
t
(
1
).
print
()});
}
store_from_greg
(
allocaInst
,
Reg
::
t
(
0
));
load_to_greg
(
ConstantInt
::
get
(
0
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
static_cast
<
int
>
(
allocaInst
->
get_alloca_type
()
->
get_size
()),
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
}
void
CodeGen
::
gen_load
()
{
void
CodeGen
::
gen_load
()
auto
*
ptr
=
context
.
inst
->
get_operand
(
0
);
{
auto
*
type
=
context
.
inst
->
get_type
();
auto
*
ptr
=
context
.
inst
->
get_operand
(
0
);
auto
*
type
=
context
.
inst
->
get_type
();
load_to_greg
(
ptr
,
Reg
::
t
(
0
));
load_to_greg
(
ptr
,
Reg
::
t
(
0
));
if
(
type
->
is_float_type
())
{
if
(
type
->
is_float_type
())
{
append_inst
(
"fld.s $ft0, $t0, 0"
);
append_inst
(
"fld.s $ft0, $t0, 0"
);
store_from_freg
(
context
.
inst
,
FReg
::
ft
(
0
));
store_from_freg
(
context
.
inst
,
FReg
::
ft
(
0
));
}
else
{
// TODO load 整数类型的数据
throw
not_implemented_error
{
__FUNCTION__
};
}
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
"ld.w $t0, $t0, 0"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
else
if
(
type
->
is_int1_type
())
{
append_inst
(
"ld.b $t0, $t0, 0"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
else
{
append_inst
(
"ld.d $t0, $t0, 0"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
if
(
ptr
->
is
<
AllocaInst
>
()
&&
!
((
ptr
->
as
<
AllocaInst
>
())
->
get_alloca_type
()
->
is_array_type
()))
return
;
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
load_to_greg
(
ConstantInt
::
get
(
3
,
m
),
Reg
::
a
(
1
));
append_inst
(
"bl add_lab4_flag"
);
}
}
void
CodeGen
::
gen_store
()
{
void
CodeGen
::
gen_store
()
// TODO 翻译 store 指令
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
storeInst
=
dynamic_cast
<
StoreInst
*>
(
context
.
inst
);
auto
addr
=
storeInst
->
get_operand
(
1
);
auto
value
=
storeInst
->
get_operand
(
0
);
load_to_greg
(
addr
,
Reg
::
t
(
0
));
if
(
value
->
get_type
()
->
is_float_type
())
{
load_to_freg
(
value
,
FReg
::
ft
(
0
));
append_inst
(
"fst.s $ft0, $t0, 0"
);
}
else
if
(
value
->
get_type
()
->
is_int32_type
())
{
load_to_greg
(
value
,
Reg
::
t
(
1
));
append_inst
(
"st.w $t1, $t0, 0"
);
}
else
if
(
value
->
get_type
()
->
is_int1_type
())
{
load_to_greg
(
value
,
Reg
::
t
(
1
));
append_inst
(
"st.b $t1, $t0, 0"
);
}
else
{
load_to_greg
(
value
,
Reg
::
t
(
1
));
append_inst
(
"st.d $t1, $t0, 0"
);
}
}
}
void
CodeGen
::
gen_icmp
()
{
void
CodeGen
::
gen_icmp
()
// TODO 处理各种整数比较的情况
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
icmpInst
=
dynamic_cast
<
ICmpInst
*>
(
context
.
inst
);
auto
op
=
icmpInst
->
get_instr_type
();
load_to_greg
(
icmpInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
load_to_greg
(
icmpInst
->
get_operand
(
1
),
Reg
::
t
(
1
));
switch
(
op
)
{
case
Instruction
::
ge
:
append_inst
(
"slt $t0, $t0, $t1"
);
append_inst
(
"addi.d $t1, $zero, 1"
);
append_inst
(
"xor $t0, $t0, $t1"
);
break
;
case
Instruction
::
gt
:
append_inst
(
"slt $t0, $t1, $t0"
);
break
;
case
Instruction
::
le
:
append_inst
(
"slt $t0, $t1, $t0"
);
append_inst
(
"addi.d $t1, $zero, 1"
);
append_inst
(
"xor $t0, $t0, $t1"
);
break
;
case
Instruction
::
lt
:
append_inst
(
"slt $t0, $t0, $t1"
);
break
;
case
Instruction
::
eq
:
append_inst
(
"xor $t0, $t0, $t1"
);
append_inst
(
"sltu $t0, $zero, $t0"
);
append_inst
(
"addi.d $t1, $zero, 1"
);
append_inst
(
"xor $t0, $t0, $t1"
);
break
;
case
Instruction
::
ne
:
append_inst
(
"xor $t0, $t0, $t1"
);
append_inst
(
"sltu $t0, $zero, $t0"
);
break
;
default:
std
::
cout
<<
"wrong icmp
\n
"
;
break
;
}
store_from_greg
(
icmpInst
,
Reg
::
t
(
0
));
}
}
void
CodeGen
::
gen_fcmp
()
{
void
CodeGen
::
gen_fcmp
()
// TODO 处理各种浮点数比较的情况
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
fcmpInst
=
dynamic_cast
<
FCmpInst
*>
(
context
.
inst
);
auto
op
=
fcmpInst
->
get_instr_type
();
load_to_freg
(
fcmpInst
->
get_operand
(
0
),
FReg
::
ft
(
0
));
load_to_freg
(
fcmpInst
->
get_operand
(
1
),
FReg
::
ft
(
1
));
switch
(
op
)
{
case
Instruction
::
fge
:
append_inst
(
"fcmp.sle.s $fcc0, $ft1, $ft0"
);
break
;
case
Instruction
::
fgt
:
append_inst
(
"fcmp.slt.s $fcc0, $ft1, $ft0"
);
break
;
case
Instruction
::
fle
:
append_inst
(
"fcmp.sle.s $fcc0, $ft0, $ft1"
);
break
;
case
Instruction
::
flt
:
append_inst
(
"fcmp.slt.s $fcc0, $ft0, $ft1"
);
break
;
case
Instruction
::
feq
:
append_inst
(
"fcmp.seq.s $fcc0, $ft0, $ft1"
);
break
;
case
Instruction
::
fne
:
append_inst
(
"fcmp.sne.s $fcc0, $ft0, $ft1"
);
break
;
default:
break
;
}
append_inst
(
"bceqz"
,
{
"$fcc0"
,
"0XC"
});
append_inst
(
"addi.w $t0, $zero, 1"
);
append_inst
(
"b 0x8"
);
append_inst
(
"addi.w $t0, $zero, 0"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
}
void
CodeGen
::
gen_zext
()
{
void
CodeGen
::
gen_zext
()
// TODO 将窄位宽的整数数据进行零扩展
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
zextInst
=
dynamic_cast
<
ZextInst
*>
(
context
.
inst
);
load_to_greg
(
zextInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
append_inst
(
"bstrpick.w $t0, $t0, 7, 0"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
}
void
CodeGen
::
gen_call
()
{
void
CodeGen
::
gen_call
()
// TODO 函数调用,注意我们只需要通过寄存器传递参数,即不需考虑栈上传参的情况
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
callInst
=
dynamic_cast
<
CallInst
*>
(
context
.
inst
);
auto
*
functionType
=
static_cast
<
FunctionType
*>
(
callInst
->
get_function_type
());
auto
argsNum
=
functionType
->
get_num_of_args
();
unsigned
int
j
=
0
;
unsigned
int
k
=
0
;
for
(
unsigned
int
i
=
0
;
i
<
argsNum
;
i
++
)
{
if
(
functionType
->
get_param_type
(
i
)
->
is_float_type
())
{
load_to_freg
(
callInst
->
get_operand
(
i
+
1
),
FReg
::
fa
(
k
));
k
++
;
}
else
{
load_to_greg
(
callInst
->
get_operand
(
i
+
1
),
Reg
::
a
(
j
));
j
++
;
}
}
auto
*
func
=
dynamic_cast
<
Function
*>
(
callInst
->
get_operand
(
0
));
append_inst
(
"bl"
,
{
func
->
get_name
()});
auto
retType
=
functionType
->
get_return_type
();
if
(
retType
->
is_integer_type
())
{
store_from_greg
(
context
.
inst
,
Reg
::
a
(
0
));
}
else
if
(
retType
->
is_float_type
())
{
store_from_freg
(
context
.
inst
,
FReg
::
fa
(
0
));
}
}
}
/*
void
CodeGen
::
gen_gep
()
* %op = getelementptr [10 x i32], [10 x i32]* %op, i32 0, i32 %op
{
* %op = getelementptr i32, i32* %op, i32 %op
auto
*
getElementPtrInst
=
dynamic_cast
<
GetElementPtrInst
*>
(
context
.
inst
);
*
unsigned
int
num
=
getElementPtrInst
->
get_num_operand
();
* Memory layout
load_to_greg
(
getElementPtrInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
* - ^
load_to_greg
(
getElementPtrInst
->
get_operand
(
num
-
1
),
Reg
::
t
(
1
));
* +-----------+ | Smaller address
auto
elementType
=
getElementPtrInst
->
get_element_type
();
* | arg ptr |---+ |
append_inst
(
"addi.d $t2, $zero, 4"
);
* +-----------+ | |
if
(
elementType
->
is_float_type
()
||
elementType
->
is_int32_type
())
* | | | |
{
* +-----------+ / |
append_inst
(
"mul.d $t1, $t1, $t2"
);
* | |<-- |
}
* | | \ |
else
* | | | |
{
* | Array | | |
append_inst
(
"addi.d $t2, $zero, 8"
);
* | | | |
append_inst
(
"mul.d $t1, $t1, $t2"
);
* | | | |
}
* | | | |
append_inst
(
"add.d $t2, $t1, $t0"
);
* +-----------+ | |
store_from_greg
(
context
.
inst
,
Reg
::
t
(
2
));
* | Pointer |---+ |
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
0
));
* +-----------+ |
load_to_greg
(
ConstantInt
::
get
(
1
,
m
),
Reg
::
a
(
1
));
* | | |
append_inst
(
"bl add_lab4_flag"
);
* +-----------+ |
* | | |
* +-----------+ |
* | | |
* +-----------+ | Larger address
* +
*/
void
CodeGen
::
gen_gep
()
{
// TODO 计算内存地址
throw
not_implemented_error
{
__FUNCTION__
};
}
}
void
CodeGen
::
gen_sitofp
()
{
void
CodeGen
::
gen_sitofp
()
// TODO 整数转向浮点数
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
sitofpInst
=
dynamic_cast
<
SiToFpInst
*>
(
context
.
inst
);
load_to_greg
(
sitofpInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
append_inst
(
"movgr2fr.w $ft0, $t0"
);
append_inst
(
"ffint.s.w $ft1, $ft0"
);
store_from_freg
(
context
.
inst
,
FReg
::
ft
(
1
));
}
}
void
CodeGen
::
gen_fptosi
()
{
void
CodeGen
::
gen_fptosi
()
// TODO 浮点数转向整数,注意向下取整(round to zero)
{
throw
not_implemented_error
{
__FUNCTION__
};
auto
*
fptosiInst
=
dynamic_cast
<
FpToSiInst
*>
(
context
.
inst
);
load_to_freg
(
fptosiInst
->
get_operand
(
0
),
FReg
::
ft
(
0
));
append_inst
(
"ftintrz.w.s $ft1, $ft0"
);
append_inst
(
"movfr2gr.s $t0, $ft1"
);
store_from_greg
(
context
.
inst
,
Reg
::
t
(
0
));
}
}
void
CodeGen
::
run
()
{
void
CodeGen
::
run
()
// 确保每个函数中基本块的名字都被设置好
{
m
->
set_print_name
();
m
->
set_print_name
();
if
(
!
m
->
get_global_variable
().
empty
())
/* 使用 GNU 伪指令为全局变量分配空间
{
* 你可以使用 `la.local` 指令将标签 (全局变量) 的地址载入寄存器中, 比如
* 要将 `a` 的地址载入 $t0, 只需要 `la.local $t0, a`
*/
if
(
!
m
->
get_global_variable
().
empty
())
{
append_inst
(
"Global variables"
,
ASMInstruction
::
Comment
);
append_inst
(
"Global variables"
,
ASMInstruction
::
Comment
);
/* 虽然下面两条伪指令可以简化为一条 `.bss` 伪指令, 但是我们还是选择使用
* `.section` 将全局变量放到可执行文件的 BSS 段, 原因如下:
* - 尽可能对齐交叉编译器 loongarch64-unknown-linux-gnu-gcc 的行为
* - 支持更旧版本的 GNU 汇编器, 因为 `.bss` 伪指令是应该相对较新的指令,
* GNU 汇编器在 2023 年 2 月的 2.37 版本才将其引入
*/
append_inst
(
".text"
,
ASMInstruction
::
Attribute
);
append_inst
(
".text"
,
ASMInstruction
::
Attribute
);
append_inst
(
".section"
,
{
".bss"
,
"
\"
aw
\"
"
,
"@nobits"
},
append_inst
(
".section"
,
{
".bss"
,
"
\"
aw
\"
"
,
"@nobits"
},
ASMInstruction
::
Attribute
);
ASMInstruction
::
Attribute
);
for
(
auto
global
:
m
->
get_global_variable
())
{
for
(
auto
global
:
m
->
get_global_variable
())
auto
size
=
{
global
->
get_type
()
->
get_pointer_element_type
()
->
get_size
();
auto
size
=
global
->
get_type
()
->
get_pointer_element_type
()
->
get_size
();
append_inst
(
".globl"
,
{
global
->
get_name
()},
append_inst
(
".globl"
,
{
global
->
get_name
()},
ASMInstruction
::
Attribute
);
ASMInstruction
::
Attribute
);
append_inst
(
".type"
,
{
global
->
get_name
(),
"@object"
},
append_inst
(
".type"
,
{
global
->
get_name
(),
"@object"
},
...
@@ -404,114 +686,106 @@ void CodeGen::run() {
...
@@ -404,114 +686,106 @@ void CodeGen::run() {
}
}
}
}
// 函数代码段
output
.
emplace_back
(
".text"
,
ASMInstruction
::
Attribute
);
output
.
emplace_back
(
".text"
,
ASMInstruction
::
Attribute
);
for
(
auto
func
:
m
->
get_functions
())
{
for
(
auto
func
:
m
->
get_functions
())
if
(
not
func
->
is_declaration
())
{
{
// 更新 context
if
(
not
func
->
is_declaration
())
{
context
.
clear
();
context
.
clear
();
context
.
func
=
func
;
context
.
func
=
func
;
// 函数信息
append_inst
(
".globl"
,
{
func
->
get_name
()},
ASMInstruction
::
Attribute
);
append_inst
(
".globl"
,
{
func
->
get_name
()},
ASMInstruction
::
Attribute
);
append_inst
(
".type"
,
{
func
->
get_name
(),
"@function"
},
append_inst
(
".type"
,
{
func
->
get_name
(),
"@function"
},
ASMInstruction
::
Attribute
);
ASMInstruction
::
Attribute
);
append_inst
(
func
->
get_name
(),
ASMInstruction
::
Label
);
append_inst
(
func
->
get_name
(),
ASMInstruction
::
Label
);
// 分配函数栈帧
allocate
();
allocate
();
// 生成 prologue
gen_prologue
();
gen_prologue
();
for
(
auto
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
&
bb
:
func
->
get_basic_blocks
())
{
context
.
bb
=
bb
;
context
.
bb
=
bb
;
append_inst
(
label_name
(
context
.
bb
),
ASMInstruction
::
Label
);
append_inst
(
context
.
bb
->
get_name
(
),
ASMInstruction
::
Label
);
for
(
auto
instr
:
bb
->
get_instructions
())
{
for
(
auto
&
instr
:
bb
->
get_instructions
())
// For debug
{
append_inst
(
instr
->
print
(),
ASMInstruction
::
Comment
);
append_inst
(
instr
->
print
(),
ASMInstruction
::
Comment
);
context
.
inst
=
instr
;
// 更新 context
context
.
inst
=
instr
;
switch
(
instr
->
get_instr_type
())
{
switch
(
instr
->
get_instr_type
())
case
Instruction
::
ret
:
{
gen_ret
();
case
Instruction
::
ret
:
break
;
gen_ret
();
case
Instruction
::
br
:
break
;
copy_stmt
();
case
Instruction
::
br
:
gen_br
();
copy_stmt
();
break
;
gen_br
();
case
Instruction
::
add
:
break
;
case
Instruction
::
sub
:
case
Instruction
::
add
:
case
Instruction
::
mul
:
case
Instruction
::
sub
:
case
Instruction
::
sdiv
:
case
Instruction
::
mul
:
gen_binary
();
case
Instruction
::
sdiv
:
break
;
gen_binary
();
case
Instruction
::
fadd
:
break
;
case
Instruction
::
fsub
:
case
Instruction
::
fadd
:
case
Instruction
::
fmul
:
case
Instruction
::
fsub
:
case
Instruction
::
fdiv
:
case
Instruction
::
fmul
:
gen_float_binary
();
case
Instruction
::
fdiv
:
break
;
gen_float_binary
();
case
Instruction
::
alloca
:
break
;
/* 对于 alloca 指令,我们已经为 alloca
case
Instruction
::
alloca
:
* 的内容分配空间,在此我们还需保存 alloca
gen_alloca
();
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针
break
;
*/
case
Instruction
::
load
:
gen_alloca
();
gen_load
();
break
;
break
;
case
Instruction
::
load
:
case
Instruction
::
store
:
gen_load
();
gen_store
();
break
;
break
;
case
Instruction
::
store
:
case
Instruction
::
ge
:
gen_store
();
case
Instruction
::
gt
:
break
;
case
Instruction
::
le
:
case
Instruction
::
ge
:
case
Instruction
::
lt
:
case
Instruction
::
gt
:
case
Instruction
::
eq
:
case
Instruction
::
le
:
case
Instruction
::
ne
:
case
Instruction
::
lt
:
gen_icmp
();
case
Instruction
::
eq
:
break
;
case
Instruction
::
ne
:
case
Instruction
::
fge
:
gen_icmp
();
case
Instruction
::
fgt
:
break
;
case
Instruction
::
fle
:
case
Instruction
::
fge
:
case
Instruction
::
flt
:
case
Instruction
::
fgt
:
case
Instruction
::
feq
:
case
Instruction
::
fle
:
case
Instruction
::
fne
:
case
Instruction
::
flt
:
gen_fcmp
();
case
Instruction
::
feq
:
break
;
case
Instruction
::
fne
:
case
Instruction
::
phi
:
gen_fcmp
();
break
;
break
;
case
Instruction
::
call
:
case
Instruction
::
phi
:
gen_call
();
/* for phi, just convert to a series of
break
;
* copy-stmts */
case
Instruction
::
getelementptr
:
/* we can collect all phi and deal them at
gen_gep
();
* the end */
break
;
break
;
case
Instruction
::
zext
:
case
Instruction
::
call
:
gen_zext
();
gen_call
();
break
;
break
;
case
Instruction
::
fptosi
:
case
Instruction
::
getelementptr
:
gen_fptosi
();
gen_gep
();
break
;
break
;
case
Instruction
::
sitofp
:
case
Instruction
::
zext
:
gen_sitofp
();
gen_zext
();
break
;
break
;
case
Instruction
::
fptosi
:
gen_fptosi
();
break
;
case
Instruction
::
sitofp
:
gen_sitofp
();
break
;
}
}
}
}
}
}
// 生成 epilogue
gen_epilogue
();
gen_epilogue
();
}
}
}
}
}
}
std
::
string
CodeGen
::
print
()
const
{
std
::
string
CodeGen
::
print
()
const
{
std
::
string
result
;
std
::
string
result
;
for
(
const
auto
&
inst
:
output
)
{
for
(
const
auto
&
inst
:
output
)
{
result
+=
inst
.
format
();
result
+=
inst
.
format
();
}
}
return
result
;
return
result
;
...
...
src/io/io.c
View file @
f40efe88
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
int
input
()
{
#include <sys/time.h>
struct
timeval
time_start
,
time_end
;
int
end_set
;
int
flags
[
2
];
int
input
(
void
)
{
int
a
;
int
a
;
scanf
(
"%d"
,
&
a
);
scanf
(
"%d"
,
&
a
);
gettimeofday
(
&
time_start
,
NULL
);
end_set
=
0
;
return
a
;
return
a
;
}
}
void
output
(
int
a
)
{
printf
(
"%d
\n
"
,
a
);
}
void
output
(
int
a
)
{
if
(
end_set
==
0
)
{
gettimeofday
(
&
time_end
,
NULL
);
end_set
=
1
;
}
printf
(
"%d
\n
"
,
a
);
}
void
outputFloat
(
float
a
)
{
if
(
end_set
==
0
)
{
gettimeofday
(
&
time_end
,
NULL
);
end_set
=
1
;
}
printf
(
"%f
\n
"
,
a
);
}
void
add_lab4_flag
(
int
idx
,
int
val
)
{
flags
[
idx
]
+=
val
;
}
void
outputFloat
(
float
a
)
{
printf
(
"%f
\n
"
,
a
);
}
__attribute
((
constructor
))
void
before_main
(
void
)
{
flags
[
0
]
=
0
;
flags
[
1
]
=
0
;
end_set
=
0
;
gettimeofday
(
&
time_start
,
NULL
);
}
void
neg_idx_except
()
{
__attribute
((
destructor
))
void
after_main
(
void
)
printf
(
"negative index exception
\n
"
);
{
exit
(
0
);
long
time_us
=
0
;
fprintf
(
stderr
,
"Allocate Size (bytes):
\n
%d
\n
"
,
flags
[
0
]);
fprintf
(
stderr
,
"Execute Cost:
\n
%d
\n
"
,
flags
[
1
]);
if
(
end_set
==
0
)
{
gettimeofday
(
&
time_end
,
NULL
);
}
time_us
+=
1000000L
*
(
time_end
.
tv_sec
-
time_start
.
tv_sec
)
+
time_end
.
tv_usec
-
time_start
.
tv_usec
;
fprintf
(
stderr
,
"Take Times (us):
\n
%ld
\n
"
,
time_us
);
}
}
src/io/io.h
View file @
f40efe88
int
input
();
int
input
(
void
);
void
output
(
int
a
);
void
output
(
int
a
);
void
outputFloat
(
float
a
);
void
outputFloat
(
float
a
);
void
neg_idx_except
(
);
void
add_lab4_flag
(
int
idx
,
int
val
);
\ No newline at end of file
src/lightir/BasicBlock.cpp
View file @
f40efe88
...
@@ -11,14 +11,14 @@
...
@@ -11,14 +11,14 @@
BasicBlock
::
BasicBlock
(
const
Module
*
m
,
const
std
::
string
&
name
=
""
,
BasicBlock
::
BasicBlock
(
const
Module
*
m
,
const
std
::
string
&
name
=
""
,
Function
*
parent
=
nullptr
)
Function
*
parent
=
nullptr
)
:
Value
(
m
->
get_label_type
(),
:
Value
(
m
->
get_label_type
(),
parent
==
nullptr
?
GLOBAL_BASICBLOCK_NAMES_
.
get_name
(
name
)
:
parent
->
names4blocks_
.
get_name
(
name
))
parent
==
nullptr
?
GLOBAL_BASICBLOCK_NAMES_
.
get_name
(
name
)
:
parent
->
names4blocks_
.
get_name
(
name
))
,
parent_
(
parent
)
{
,
parent_
(
parent
)
{
assert
(
parent
&&
"currently parent should not be nullptr"
);
assert
(
parent
&&
"currently parent should not be nullptr"
);
parent_
->
add_basic_block
(
this
);
parent_
->
add_basic_block
(
this
);
}
}
Module
*
BasicBlock
::
get_module
()
const
{
return
get_parent
()
->
get_parent
();
}
Module
*
BasicBlock
::
get_module
()
const
{
return
get_parent
()
->
get_parent
();
}
void
BasicBlock
::
erase_from_parent
()
{
this
->
get_parent
()
->
remove
(
this
);
}
void
BasicBlock
::
erase_from_parent
()
{
this
->
get_parent
()
->
remove
(
this
);
}
bool
BasicBlock
::
is_terminated
()
const
{
bool
BasicBlock
::
is_terminated
()
const
{
...
@@ -34,18 +34,18 @@ bool BasicBlock::is_terminated() const {
...
@@ -34,18 +34,18 @@ bool BasicBlock::is_terminated() const {
}
}
}
}
Instruction
*
BasicBlock
::
get_terminator
()
const
Instruction
*
BasicBlock
::
get_terminator
()
const
{
{
assert
(
is_terminated
()
&&
assert
(
is_terminated
()
&&
"Trying to get terminator from an bb which is not terminated"
);
"Trying to get terminator from an bb which is not terminated"
);
return
instr_list_
.
back
();
return
instr_list_
.
back
();
}
}
void
BasicBlock
::
add_instruction
(
Instruction
*
instr
)
{
void
BasicBlock
::
add_instruction
(
Instruction
*
instr
)
{
if
(
instr
->
is_alloca
()
||
instr
->
is_phi
())
if
(
instr
->
is_alloca
()
||
instr
->
is_phi
())
{
{
auto
it
=
instr_list_
.
begin
();
auto
it
=
instr_list_
.
begin
();
for
(;
it
!=
instr_list_
.
end
()
&&
((
*
it
)
->
is_alloca
()
||
(
*
it
)
->
is_phi
());
++
it
)
{}
for
(;
it
!=
instr_list_
.
end
()
&&
((
*
it
)
->
is_alloca
()
||
(
*
it
)
->
is_phi
());
++
it
)
{}
instr_list_
.
emplace
(
it
,
instr
);
instr_list_
.
emplace
(
it
,
instr
);
return
;
return
;
}
}
...
@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const
...
@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const
return
parent_
->
get_entry_block
();
return
parent_
->
get_entry_block
();
}
}
Names
GLOBAL_BASICBLOCK_NAMES_
{
"label"
,
"_"
};
Names
GLOBAL_BASICBLOCK_NAMES_
{
"label"
,
"_"
};
\ No newline at end of file
\ No newline at end of file
src/lightir/Function.cpp
View file @
f40efe88
...
@@ -7,17 +7,8 @@
...
@@ -7,17 +7,8 @@
#include <unordered_set>
#include <unordered_set>
#include <queue>
#include <queue>
namespace
{
std
::
string
chopName
(
std
::
string
name
)
{
if
(
name
.
size
()
>
3
)
return
{
name
.
begin
(),
name
.
begin
()
+
3
};
return
name
;
}
}
Function
::
Function
(
FunctionType
*
ty
,
const
std
::
string
&
name
,
Module
*
parent
)
Function
::
Function
(
FunctionType
*
ty
,
const
std
::
string
&
name
,
Module
*
parent
)
:
Value
(
ty
,
name
),
names4blocks_
(
"
label"
,
chopName
(
name
)
+
"_"
),
names4insts_
(
"op"
,
""
),
parent_
(
parent
),
seq_cnt_
(
0
)
{
:
Value
(
ty
,
name
),
names4blocks_
(
"
"
,
name
+
"_"
),
names4insts_
(
"op"
,
""
),
parent_
(
parent
),
seq_cnt_
(
0
)
{
// num_args_ = ty->getNumParams();
// num_args_ = ty->getNumParams();
parent
->
add_function
(
this
);
parent
->
add_function
(
this
);
// build args
// build args
...
...
src/lightir/IRprinter.cpp
View file @
f40efe88
...
@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const
...
@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const
}
}
else
else
{
{
if
(
auto
fty
=
dynamic_cast
<
FunctionType
*>
(
ty
))
if
(
auto
fty
=
dynamic_cast
<
FunctionType
*>
(
op0
->
get_type
()
))
{
{
auto
ty3
=
fty
->
get_return_type
();
auto
ty3
=
fty
->
get_return_type
();
if
(
ty3
==
nullptr
)
if
(
ty3
==
nullptr
)
...
...
src/lightir/Instruction.cpp
View file @
f40efe88
...
@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) {
...
@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) {
return
new
BranchInst
(
nullptr
,
if_true
,
nullptr
,
bb
);
return
new
BranchInst
(
nullptr
,
if_true
,
nullptr
,
bb
);
}
}
void
BranchInst
::
replace_all_bb_match
(
BasicBlock
*
need_replace
,
BasicBlock
*
replace_to
)
{
if
(
need_replace
==
nullptr
||
replace_to
==
nullptr
||
need_replace
==
replace_to
)
return
;
int
size
=
static_cast
<
int
>
(
get_operands
().
size
());
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
auto
op
=
get_operand
(
i
);
if
(
op
==
need_replace
)
set_operand
(
i
,
replace_to
);
}
auto
parent
=
get_parent
();
if
(
parent
==
nullptr
)
return
;
parent
->
remove_succ_basic_block
(
need_replace
);
need_replace
->
remove_pre_basic_block
(
parent
);
parent
->
add_succ_basic_block
(
replace_to
);
replace_to
->
add_pre_basic_block
(
parent
);
}
ReturnInst
::
ReturnInst
(
Value
*
val
,
BasicBlock
*
bb
)
ReturnInst
::
ReturnInst
(
Value
*
val
,
BasicBlock
*
bb
)
:
Instruction
(
bb
->
get_module
()
->
get_void_type
(),
ret
,
""
,
bb
)
{
:
Instruction
(
bb
->
get_module
()
->
get_void_type
(),
ret
,
""
,
bb
)
{
if
(
val
==
nullptr
)
{
if
(
val
==
nullptr
)
{
...
@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str
...
@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str
PhiInst
::
PhiInst
(
Type
*
ty
,
const
std
::
vector
<
Value
*>&
vals
,
PhiInst
::
PhiInst
(
Type
*
ty
,
const
std
::
vector
<
Value
*>&
vals
,
const
std
::
vector
<
BasicBlock
*>&
val_bbs
,
BasicBlock
*
bb
,
const
std
::
string
&
name
)
const
std
::
vector
<
BasicBlock
*>&
val_bbs
,
BasicBlock
*
bb
,
const
std
::
string
&
name
)
:
Instruction
(
ty
,
phi
,
name
)
{
:
Instruction
(
ty
,
phi
,
name
,
bb
)
{
assert
(
vals
.
size
()
==
val_bbs
.
size
()
&&
"Unmatched vals and bbs"
);
assert
(
vals
.
size
()
==
val_bbs
.
size
()
&&
"Unmatched vals and bbs"
);
for
(
unsigned
i
=
0
;
i
<
vals
.
size
();
i
++
)
{
for
(
unsigned
i
=
0
;
i
<
vals
.
size
();
i
++
)
{
assert
(
ty
==
vals
[
i
]
->
get_type
()
&&
"Bad type for phi"
);
assert
(
ty
==
vals
[
i
]
->
get_type
()
&&
"Bad type for phi"
);
add_operand
(
vals
[
i
]);
add_operand
(
vals
[
i
]);
add_operand
(
val_bbs
[
i
]);
add_operand
(
val_bbs
[
i
]);
}
}
this
->
set_parent
(
bb
);
}
}
PhiInst
*
PhiInst
::
create_phi
(
Type
*
ty
,
BasicBlock
*
bb
,
PhiInst
*
PhiInst
::
create_phi
(
Type
*
ty
,
BasicBlock
*
bb
,
...
...
src/lightir/Module.cpp
View file @
f40efe88
...
@@ -27,48 +27,48 @@ Module::~Module()
...
@@ -27,48 +27,48 @@ Module::~Module()
for
(
auto
i
:
global_list_
)
delete
i
;
for
(
auto
i
:
global_list_
)
delete
i
;
}
}
Type
*
Module
::
get_void_type
()
const
{
return
void_ty_
;
}
Type
*
Module
::
get_void_type
()
const
{
return
void_ty_
;
}
Type
*
Module
::
get_label_type
()
const
{
return
label_ty_
;
}
Type
*
Module
::
get_label_type
()
const
{
return
label_ty_
;
}
IntegerType
*
Module
::
get_int1_type
()
const
{
return
int1_ty_
;
}
IntegerType
*
Module
::
get_int1_type
()
const
{
return
int1_ty_
;
}
IntegerType
*
Module
::
get_int32_type
()
const
{
return
int32_ty_
;
}
IntegerType
*
Module
::
get_int32_type
()
const
{
return
int32_ty_
;
}
FloatType
*
Module
::
get_float_type
()
const
{
return
float32_ty_
;
}
FloatType
*
Module
::
get_float_type
()
const
{
return
float32_ty_
;
}
PointerType
*
Module
::
get_int32_ptr_type
()
{
PointerType
*
Module
::
get_int32_ptr_type
()
{
return
get_pointer_type
(
int32_ty_
);
return
get_pointer_type
(
int32_ty_
);
}
}
PointerType
*
Module
::
get_float_ptr_type
()
{
PointerType
*
Module
::
get_float_ptr_type
()
{
return
get_pointer_type
(
float32_ty_
);
return
get_pointer_type
(
float32_ty_
);
}
}
PointerType
*
Module
::
get_pointer_type
(
Type
*
contained
)
{
PointerType
*
Module
::
get_pointer_type
(
Type
*
contained
)
{
if
(
pointer_map_
.
find
(
contained
)
==
pointer_map_
.
end
())
{
if
(
pointer_map_
.
find
(
contained
)
==
pointer_map_
.
end
())
{
pointer_map_
[
contained
]
=
new
PointerType
(
contained
);
pointer_map_
[
contained
]
=
new
PointerType
(
contained
);
}
}
return
pointer_map_
[
contained
];
return
pointer_map_
[
contained
];
}
}
ArrayType
*
Module
::
get_array_type
(
Type
*
contained
,
unsigned
num_elements
)
{
ArrayType
*
Module
::
get_array_type
(
Type
*
contained
,
unsigned
num_elements
)
{
if
(
array_map_
.
find
({
contained
,
num_elements
})
==
array_map_
.
end
())
{
if
(
array_map_
.
find
({
contained
,
num_elements
})
==
array_map_
.
end
())
{
array_map_
[{
contained
,
num_elements
}]
=
array_map_
[{
contained
,
num_elements
}]
=
new
ArrayType
(
contained
,
num_elements
);
new
ArrayType
(
contained
,
num_elements
);
}
}
return
array_map_
[{
contained
,
num_elements
}];
return
array_map_
[{
contained
,
num_elements
}];
}
}
FunctionType
*
Module
::
get_function_type
(
Type
*
retty
,
FunctionType
*
Module
::
get_function_type
(
Type
*
retty
,
std
::
vector
<
Type
*>
&
args
)
{
std
::
vector
<
Type
*>&
args
)
{
if
(
not
function_map_
.
count
({
retty
,
args
}))
{
if
(
not
function_map_
.
count
({
retty
,
args
}))
{
function_map_
[{
retty
,
args
}]
=
function_map_
[{
retty
,
args
}]
=
new
FunctionType
(
retty
,
args
);
new
FunctionType
(
retty
,
args
);
}
}
return
function_map_
[{
retty
,
args
}];
return
function_map_
[{
retty
,
args
}];
}
}
void
Module
::
add_function
(
Function
*
f
)
{
function_list_
.
push_back
(
f
);
}
void
Module
::
add_function
(
Function
*
f
)
{
function_list_
.
push_back
(
f
);
}
std
::
list
<
Function
*>
&
Module
::
get_functions
()
{
return
function_list_
;
}
std
::
list
<
Function
*>
&
Module
::
get_functions
()
{
return
function_list_
;
}
void
Module
::
add_global_variable
(
GlobalVariable
*
g
)
{
void
Module
::
add_global_variable
(
GlobalVariable
*
g
)
{
global_list_
.
push_back
(
g
);
global_list_
.
push_back
(
g
);
}
}
std
::
list
<
GlobalVariable
*>
&
Module
::
get_global_variable
()
{
std
::
list
<
GlobalVariable
*>
&
Module
::
get_global_variable
()
{
return
global_list_
;
return
global_list_
;
}
}
...
...
src/lightir/User.cpp
View file @
f40efe88
...
@@ -42,6 +42,6 @@ void User::remove_operand(unsigned idx) {
...
@@ -42,6 +42,6 @@ void User::remove_operand(unsigned idx) {
}
}
// remove the designated operand
// remove the designated operand
if
(
operands_
[
idx
])
if
(
operands_
[
idx
])
operands_
[
idx
]
->
remove_use
(
this
,
idx
);
operands_
[
idx
]
->
remove_use
(
this
,
idx
);
operands_
.
erase
(
operands_
.
begin
()
+
idx
);
operands_
.
erase
(
operands_
.
begin
()
+
idx
);
}
}
src/passes/DeadCode.cpp
View file @
f40efe88
...
@@ -10,11 +10,12 @@
...
@@ -10,11 +10,12 @@
// 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令
// 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令
void
DeadCode
::
run
()
{
void
DeadCode
::
run
()
{
bool
changed
;
bool
changed
;
func_info
=
new
FuncInfo
(
m_
);
func_info
=
new
FuncInfo
(
m_
);
func_info
->
run
();
func_info
->
run
();
do
{
do
{
changed
=
false
;
changed
=
false
;
for
(
auto
func
:
m_
->
get_functions
())
{
for
(
auto
func
:
m_
->
get_functions
())
{
if
(
func
->
is_declaration
())
continue
;
if
(
remove_bb_
)
changed
|=
clear_basic_blocks
(
func
);
if
(
remove_bb_
)
changed
|=
clear_basic_blocks
(
func
);
mark
(
func
);
mark
(
func
);
changed
|=
sweep
(
func
);
changed
|=
sweep
(
func
);
...
@@ -133,7 +134,7 @@ bool DeadCode::sweep(Function *func) {
...
@@ -133,7 +134,7 @@ bool DeadCode::sweep(Function *func) {
for
(
auto
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
inst
:
bb
->
get_instructions
())
{
for
(
auto
inst
:
bb
->
get_instructions
())
{
if
(
marked
[
inst
])
continue
;
if
(
marked
[
inst
])
continue
;
wait_del
.
emplace
(
inst
);
wait_del
.
emplace
(
inst
);
}
}
bb
->
get_instructions
().
remove_if
([
&
wait_del
](
Instruction
*
i
)
->
bool
{
return
wait_del
.
count
(
i
);
});
bb
->
get_instructions
().
remove_if
([
&
wait_del
](
Instruction
*
i
)
->
bool
{
return
wait_del
.
count
(
i
);
});
if
(
!
wait_del
.
empty
())
rm
=
true
;
if
(
!
wait_del
.
empty
())
rm
=
true
;
...
@@ -172,12 +173,12 @@ void DeadCode::sweep_globally() const {
...
@@ -172,12 +173,12 @@ void DeadCode::sweep_globally() const {
// changed |= unused_funcs.size() or unused_globals.size();
// changed |= unused_funcs.size() or unused_globals.size();
for
(
auto
func
:
unused_funcs
)
for
(
auto
func
:
unused_funcs
)
{
{
m_
->
get_functions
().
remove
(
func
);
m_
->
get_functions
().
remove
(
func
);
delete
func
;
delete
func
;
}
}
for
(
auto
glob
:
unused_globals
)
for
(
auto
glob
:
unused_globals
)
{
{
m_
->
get_global_variable
().
remove
(
glob
);
m_
->
get_global_variable
().
remove
(
glob
);
delete
glob
;
delete
glob
;
}
}
}
}
src/passes/Dominators.cpp
View file @
f40efe88
...
@@ -62,13 +62,13 @@ void Dominators::run() {
...
@@ -62,13 +62,13 @@ void Dominators::run() {
* 该函数使用后序号来查找两个节点的最近公共支配者。
* 该函数使用后序号来查找两个节点的最近公共支配者。
* 通过在支配树上向上遍历直到找到交点。
* 通过在支配树上向上遍历直到找到交点。
*/
*/
BasicBlock
*
Dominators
::
intersect
(
BasicBlock
*
b1
,
const
BasicBlock
*
b2
)
const
BasicBlock
*
Dominators
::
intersect
(
BasicBlock
*
b1
,
BasicBlock
*
b2
)
const
{
{
while
(
b1
!=
b2
)
{
while
(
b1
!=
b2
)
{
while
(
get_
post_order
(
b1
)
<
get
_post_order
(
b2
))
{
while
(
get_
reversed_post_order
(
b1
)
>
get_reversed
_post_order
(
b2
))
{
b1
=
get_idom
(
b1
);
b1
=
get_idom
(
b1
);
}
}
while
(
get_
post_order
(
b2
)
<
get
_post_order
(
b1
))
{
while
(
get_
reversed_post_order
(
b2
)
>
get_reversed
_post_order
(
b1
))
{
b2
=
get_idom
(
b2
);
b2
=
get_idom
(
b2
);
}
}
}
}
...
@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
...
@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
void
Dominators
::
create_reverse_post_order
()
{
void
Dominators
::
create_reverse_post_order
()
{
std
::
set
<
BasicBlock
*>
visited
;
std
::
set
<
BasicBlock
*>
visited
;
dfs
(
f_
->
get_entry_block
(),
visited
);
dfs
(
f_
->
get_entry_block
(),
visited
);
int
size
=
static_cast
<
int
>
(
reversed_post_order_vec_
.
size
())
-
1
;
for
(
auto
&
it
:
reversed_post_order_
)
{
it
.
second
=
size
-
it
.
second
;
reversed_post_order_vec_
[
it
.
second
]
=
it
.
first
;
}
}
}
/**
/**
...
@@ -100,8 +106,8 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
...
@@ -100,8 +106,8 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
dfs
(
succ
,
visited
);
dfs
(
succ
,
visited
);
}
}
}
}
post_order_vec_
.
push_back
(
bb
);
reversed_
post_order_vec_
.
push_back
(
bb
);
post_order_
.
insert
({
bb
,
post_order_
.
size
()});
reversed_post_order_
.
insert
({
bb
,
reversed_
post_order_
.
size
()});
}
}
/**
/**
...
@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
...
@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
*/
*/
void
Dominators
::
create_idom
()
{
void
Dominators
::
create_idom
()
{
// 可能有用的数据结构
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
reversed_
post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
post_order_ map<BasicBlock*, unsigned int>, 每个基本块在
post_order_vec_ 中的索引
//
reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_
post_order_vec_ 中的索引
// 可能有用的函数
// 可能有用的函数
// intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先
// intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先
// 需要填写
// 需要填写
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者)
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者)
// 代表基本块的直接支配者是否已经确定, 不会在迭代中改变 (默认初始化为 false)
int
bb_count
=
static_cast
<
int
>
(
reversed_post_order_vec_
.
size
());
bool
*
already_determined
=
new
bool
[
post_order_vec_
.
size
()]{};
int
bb_count
=
static_cast
<
int
>
(
post_order_vec_
.
size
());
idom_
[
reversed_post_order_vec_
[
0
]]
=
reversed_post_order_vec_
[
0
];
for
(
int
i
=
0
;
i
<
bb_count
;
i
++
)
{
auto
bb
=
post_order_vec_
[
i
];
// TODO 填写可以直接确定直接支配者, 无需参与迭代的基本块的 idom_ 和 already_determined
throw
"Unimplemented create_idom"
;
}
bool
changed
;
bool
changed
;
do
do
{
{
changed
=
false
;
changed
=
false
;
for
(
int
i
=
0
;
i
<
bb_count
;
i
++
)
for
(
int
i
=
1
;
i
<
bb_count
;
i
++
)
{
{
if
(
already_determined
[
i
])
continue
;
auto
bb
=
reversed_post_order_vec_
[
i
];
auto
bb
=
post_order_vec_
[
i
];
// TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化)
// TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化)
throw
"Unimplemented create_idom"
;
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
)
;
}
}
}
while
(
changed
);
}
while
(
changed
);
delete
[]
already_determined
;
}
}
/**
/**
...
@@ -154,19 +150,19 @@ void Dominators::create_idom() {
...
@@ -154,19 +150,19 @@ void Dominators::create_idom() {
*/
*/
void
Dominators
::
create_dominance_frontier
()
{
void
Dominators
::
create_dominance_frontier
()
{
// 可能有用的数据结构
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
reversed_
post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
post_order_ map<BasicBlock*, unsigned int>, 每个基本块在
post_order_vec_ 中的索引
//
reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_
post_order_vec_ 中的索引
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// (或者 idom_[a] = a 代表 a 没有直接支配者)
// (或者 idom_[a] = a 代表 a 没有直接支配者)
// 需要填写
// 需要填写
// dom_frontier_ map<BasicBlock*, set<BasicBlock*>> 支配边界
// dom_frontier_ map<BasicBlock*, set<BasicBlock*>> 支配边界
int
bb_count
=
static_cast
<
int
>
(
post_order_vec_
.
size
());
int
bb_count
=
static_cast
<
int
>
(
reversed_
post_order_vec_
.
size
());
for
(
int
i
=
0
;
i
<
bb_count
;
i
++
)
for
(
int
i
=
0
;
i
<
bb_count
;
i
++
)
{
{
auto
bb
=
post_order_vec_
[
i
];
auto
bb
=
reversed_
post_order_vec_
[
i
];
// TODO 计算 bb 的支配边界集合, 填入 dom_frontier_
// TODO 计算 bb 的支配边界集合, 填入 dom_frontier_
throw
"Unimplemented create_dominance_frontier"
;
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
)
;
}
}
}
}
...
@@ -178,12 +174,13 @@ void Dominators::create_dominance_frontier() {
...
@@ -178,12 +174,13 @@ void Dominators::create_dominance_frontier() {
*/
*/
void
Dominators
::
create_dom_tree_succ
()
{
void
Dominators
::
create_dom_tree_succ
()
{
// 可能有用的数据结构
// 可能有用的数据结构
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// 需要填写
// 需要填写
// dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点
// dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点
// TODO 分析得到 f_ 中各个基本块的支配树后继
// TODO 分析得到 f_ 中各个基本块的支配树后继
throw
"Unimplemented create_dom_tree_succ"
;
// 注意如果 idom_[n] = n, 这意味着 n 没有直接支配者,因此 n 的后继中没有 n
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
}
/**
/**
...
...
src/passes/FuncInfo.cpp
View file @
f40efe88
...
@@ -8,251 +8,266 @@
...
@@ -8,251 +8,266 @@
void
FuncInfo
::
UseMessage
::
add
(
Value
*
val
)
void
FuncInfo
::
UseMessage
::
add
(
Value
*
val
)
{
{
auto
g
=
dynamic_cast
<
GlobalVariable
*>
(
val
);
auto
g
=
dynamic_cast
<
GlobalVariable
*>
(
val
);
if
(
g
!=
nullptr
)
if
(
g
!=
nullptr
)
{
{
globals_
.
emplace
(
g
);
globals_
.
emplace
(
g
);
return
;
return
;
}
}
auto
arg
=
dynamic_cast
<
Argument
*>
(
val
);
auto
arg
=
dynamic_cast
<
Argument
*>
(
val
);
arguments_
.
emplace
(
arg
);
arguments_
.
emplace
(
arg
);
}
}
bool
FuncInfo
::
UseMessage
::
have
(
Value
*
val
)
const
bool
FuncInfo
::
UseMessage
::
have
(
Value
*
val
)
const
{
{
auto
g
=
dynamic_cast
<
GlobalVariable
*>
(
val
);
auto
g
=
dynamic_cast
<
GlobalVariable
*>
(
val
);
if
(
g
!=
nullptr
)
return
globals_
.
count
(
g
);
if
(
g
!=
nullptr
)
return
globals_
.
count
(
g
);
return
arguments_
.
count
(
dynamic_cast
<
Argument
*>
(
val
));
return
arguments_
.
count
(
dynamic_cast
<
Argument
*>
(
val
));
}
}
bool
FuncInfo
::
UseMessage
::
empty
()
const
bool
FuncInfo
::
UseMessage
::
empty
()
const
{
{
return
globals_
.
empty
()
&&
arguments_
.
empty
();
return
globals_
.
empty
()
&&
arguments_
.
empty
();
}
}
void
FuncInfo
::
run
()
void
FuncInfo
::
run
()
{
{
std
::
unordered_map
<
Value
*
,
Value
*>
val_to_var
;
std
::
unordered_map
<
Value
*
,
Value
*>
val_to_var
;
// 计算对全局变量的 load/store
// 计算对全局变量的 load/store
for
(
auto
glob
:
m_
->
get_global_variable
())
for
(
auto
glob
:
m_
->
get_global_variable
())
cal_val_2_var
(
glob
,
val_to_var
);
cal_val_2_var
(
glob
,
val_to_var
);
std
::
queue
<
Function
*>
worklist
;
std
::
queue
<
Function
*>
worklist
;
std
::
unordered_set
<
Function
*>
in_worklist
;
std
::
unordered_set
<
Function
*>
in_worklist
;
// 计算对函数参数的 load/store
// 计算对函数参数的 load/store
// 本质上来说,对局部变量的 load/store 不会在函数外产生副作用,它也不会被用作 func_info 的信息
// 本质上来说,对局部变量的 load/store 不会在函数外产生副作用,它也不会被用作 func_info 的信息
for
(
auto
func
:
m_
->
get_functions
())
for
(
auto
func
:
m_
->
get_functions
())
{
{
if
(
func
->
is_declaration
())
continue
;
if
(
func
->
is_declaration
())
continue
;
use_libs
[
func
]
=
false
;
use_libs
[
func
]
=
false
;
worklist
.
emplace
(
func
);
worklist
.
emplace
(
func
);
in_worklist
.
emplace
(
func
);
in_worklist
.
emplace
(
func
);
for
(
auto
arg
:
func
->
get_args
())
for
(
auto
arg
:
func
->
get_args
())
{
{
if
(
arg
->
get_type
()
->
is_pointer_type
())
if
(
arg
->
get_type
()
->
is_pointer_type
())
{
{
cal_val_2_var
(
arg
,
val_to_var
);
cal_val_2_var
(
arg
,
val_to_var
);
}
}
}
}
}
}
// 处理函数相互调用导致的隐式 load/store
// 处理函数相互调用导致的隐式 load/store
while
(
!
worklist
.
empty
())
while
(
!
worklist
.
empty
())
{
{
// 被调用的函数
// 被调用的函数
auto
calleeF
=
worklist
.
front
();
auto
calleeF
=
worklist
.
front
();
worklist
.
pop
();
worklist
.
pop
();
in_worklist
.
erase
(
calleeF
);
in_worklist
.
erase
(
calleeF
);
for
(
auto
&
use
:
calleeF
->
get_use_list
())
for
(
auto
&
use
:
calleeF
->
get_use_list
())
{
{
// 函数调用指令
// 函数调用指令
auto
inst
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
auto
inst
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
// 调用 f 的函数
// 调用 f 的函数
auto
callerF
=
inst
->
get_parent
()
->
get_parent
();
auto
callerF
=
inst
->
get_parent
()
->
get_parent
();
auto
&
callerLoads
=
loads
[
callerF
];
auto
&
callerLoads
=
loads
[
callerF
];
auto
&
calleeLoads
=
loads
[
calleeF
];
auto
&
calleeLoads
=
loads
[
calleeF
];
auto
&
callerStores
=
stores
[
callerF
];
auto
&
callerStores
=
stores
[
callerF
];
auto
&
calleeStores
=
stores
[
calleeF
];
auto
&
calleeStores
=
stores
[
calleeF
];
// caller 的 load store 数量
// caller 的 load store 数量
auto
caller_old_load_store_count
=
callerLoads
.
globals_
.
size
()
+
callerLoads
.
arguments_
.
size
()
+
auto
caller_old_load_store_count
=
callerLoads
.
globals_
.
size
()
+
callerLoads
.
arguments_
.
size
()
+
callerStores
.
globals_
.
size
()
+
callerStores
.
arguments_
.
size
();
callerStores
.
globals_
.
size
()
+
callerStores
.
arguments_
.
size
();
// caller 同时 load 了 callee load 的全局变量
// caller 同时 load 了 callee load 的全局变量
for
(
auto
i
:
calleeLoads
.
globals_
)
callerLoads
.
globals_
.
emplace
(
i
);
for
(
auto
i
:
calleeLoads
.
globals_
)
callerLoads
.
globals_
.
emplace
(
i
);
// caller 同时 store 了 callee store 的全局变量
// caller 同时 store 了 callee store 的全局变量
for
(
auto
i
:
calleeStores
.
globals_
)
callerStores
.
globals_
.
emplace
(
i
);
for
(
auto
i
:
calleeStores
.
globals_
)
callerStores
.
globals_
.
emplace
(
i
);
auto
&
ops
=
inst
->
get_operands
();
auto
&
ops
=
inst
->
get_operands
();
// 形式参数
// 形式参数
for
(
auto
calleArg
:
calleeF
->
get_args
())
for
(
auto
calleArg
:
calleeF
->
get_args
())
{
{
if
(
calleArg
->
get_type
()
->
is_pointer_type
())
if
(
calleArg
->
get_type
()
->
is_pointer_type
())
{
{
// 传入的实参
// 传入的实参
auto
trueArg
=
ops
[
calleArg
->
get_arg_no
()
+
1
];
auto
trueArg
=
ops
[
calleArg
->
get_arg_no
()
+
1
];
// 实参来自哪个临时变量
// 实参来自哪个临时变量
auto
trueArgVar
=
val_to_var
.
find
(
trueArg
);
auto
trueArgVar
=
val_to_var
.
find
(
trueArg
);
// 来自局部变量,跳过,因为对局部变量的 load/store 不会在函数外产生副作用
// 来自局部变量,跳过,因为对局部变量的 load/store 不会在函数外产生副作用
if
(
trueArgVar
==
val_to_var
.
end
())
continue
;
if
(
trueArgVar
==
val_to_var
.
end
())
continue
;
auto
trace
=
trueArgVar
->
second
;
auto
trace
=
trueArgVar
->
second
;
// 添加 load
// 添加 load
if
(
calleeLoads
.
have
(
calleArg
))
callerLoads
.
add
(
trace
);
if
(
calleeLoads
.
have
(
calleArg
))
callerLoads
.
add
(
trace
);
// 添加 store
// 添加 store
if
(
calleeStores
.
have
(
calleArg
))
callerStores
.
add
(
trace
);
if
(
calleeStores
.
have
(
calleArg
))
callerStores
.
add
(
trace
);
}
}
}
}
// caller f 的 load/store 产生了变化,可能会影响其它调用 f 的函数的 load/store
// caller f 的 load/store 产生了变化,可能会影响其它调用 f 的函数的 load/store
if
(
callerLoads
.
globals_
.
size
()
+
callerLoads
.
arguments_
.
size
()
+
callerStores
.
globals_
.
size
()
+
if
(
callerLoads
.
globals_
.
size
()
+
callerLoads
.
arguments_
.
size
()
+
callerStores
.
globals_
.
size
()
+
callerStores
.
arguments_
.
size
()
!=
caller_old_load_store_count
)
callerStores
.
arguments_
.
size
()
!=
caller_old_load_store_count
)
{
{
if
(
!
in_worklist
.
count
(
callerF
))
if
(
!
in_worklist
.
count
(
callerF
))
{
{
in_worklist
.
emplace
(
callerF
);
in_worklist
.
emplace
(
callerF
);
worklist
.
emplace
(
callerF
);
worklist
.
emplace
(
callerF
);
}
}
}
}
}
}
}
}
// 没有 load/store,但是调用了库函数的函数是非纯函数(因为库函数是 IO)
// 没有 load/store,但是调用了库函数的函数是非纯函数(因为库函数是 IO)
for
(
auto
&
func
:
m_
->
get_functions
())
for
(
auto
&
func
:
m_
->
get_functions
())
{
{
if
(
func
->
is_declaration
())
if
(
func
->
is_declaration
())
{
{
for
(
auto
&
use
:
func
->
get_use_list
())
for
(
auto
&
use
:
func
->
get_use_list
())
{
{
auto
call
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
auto
call
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
use_libs
[
call
->
get_parent
()
->
get_parent
()]
=
true
;
use_libs
[
call
->
get_parent
()
->
get_parent
()]
=
true
;
}
}
}
}
worklist
.
emplace
(
func
);
worklist
.
emplace
(
func
);
in_worklist
.
emplace
(
func
);
in_worklist
.
emplace
(
func
);
}
}
while
(
!
worklist
.
empty
())
while
(
!
worklist
.
empty
())
{
{
auto
f
=
worklist
.
front
();
auto
f
=
worklist
.
front
();
worklist
.
pop
();
worklist
.
pop
();
in_worklist
.
erase
(
f
);
in_worklist
.
erase
(
f
);
if
(
use_libs
[
f
])
if
(
use_libs
[
f
])
for
(
auto
&
use
:
f
->
get_use_list
())
for
(
auto
&
use
:
f
->
get_use_list
())
{
{
auto
inst
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
auto
inst
=
dynamic_cast
<
CallInst
*>
(
use
.
val_
);
auto
cf
=
inst
->
get_parent
()
->
get_parent
();
auto
cf
=
inst
->
get_parent
()
->
get_parent
();
if
(
!
use_libs
[
cf
])
if
(
!
use_libs
[
cf
])
{
{
use_libs
[
cf
]
=
true
;
use_libs
[
cf
]
=
true
;
if
(
!
in_worklist
.
count
(
cf
))
if
(
!
in_worklist
.
count
(
cf
))
{
{
in_worklist
.
emplace
(
cf
);
in_worklist
.
emplace
(
cf
);
worklist
.
emplace
(
cf
);
worklist
.
emplace
(
cf
);
}
}
}
}
}
}
}
}
log
();
log
();
}
}
Value
*
FuncInfo
::
store_ptr
(
const
StoreInst
*
st
)
Value
*
FuncInfo
::
store_ptr
(
const
StoreInst
*
st
)
{
{
return
trace_ptr
(
st
->
get_operand
(
1
));
return
trace_ptr
(
st
->
get_operand
(
1
));
}
}
Value
*
FuncInfo
::
load_ptr
(
const
LoadInst
*
ld
)
Value
*
FuncInfo
::
load_ptr
(
const
LoadInst
*
ld
)
{
{
return
trace_ptr
(
ld
->
get_operand
(
0
));
return
trace_ptr
(
ld
->
get_operand
(
0
));
}
}
std
::
unordered_set
<
Value
*>
FuncInfo
::
get_stores
(
const
CallInst
*
call
)
std
::
unordered_set
<
Value
*>
FuncInfo
::
get_stores
(
const
CallInst
*
call
)
{
{
auto
func
=
call
->
get_operand
(
0
)
->
as
<
Function
>
();
auto
func
=
call
->
get_operand
(
0
)
->
as
<
Function
>
();
if
(
func
->
is_declaration
())
return
{};
if
(
func
->
is_declaration
())
return
{};
std
::
unordered_set
<
Value
*>
ret
;
std
::
unordered_set
<
Value
*>
ret
;
for
(
auto
i
:
stores
[
func
].
globals_
)
ret
.
emplace
(
i
);
for
(
auto
i
:
stores
[
func
].
globals_
)
ret
.
emplace
(
i
);
for
(
auto
arg
:
stores
[
func
].
arguments_
)
for
(
auto
arg
:
stores
[
func
].
arguments_
)
{
{
int
arg_no
=
static_cast
<
int
>
(
arg
->
get_arg_no
());
int
arg_no
=
static_cast
<
int
>
(
arg
->
get_arg_no
());
auto
in
=
call
->
get_operand
(
arg_no
+
1
);
auto
in
=
call
->
get_operand
(
arg_no
+
1
);
ret
.
emplace
(
trace_ptr
(
in
));
ret
.
emplace
(
trace_ptr
(
in
));
}
}
return
ret
;
return
ret
;
}
std
::
unordered_set
<
Value
*>
FuncInfo
::
get_loads
(
const
CallInst
*
call
)
{
auto
func
=
call
->
get_operand
(
0
)
->
as
<
Function
>
();
if
(
func
->
is_declaration
())
return
{};
std
::
unordered_set
<
Value
*>
ret
;
for
(
auto
i
:
loads
[
func
].
globals_
)
ret
.
emplace
(
i
);
for
(
auto
arg
:
loads
[
func
].
arguments_
)
{
int
arg_no
=
static_cast
<
int
>
(
arg
->
get_arg_no
());
auto
in
=
call
->
get_operand
(
arg_no
+
1
);
ret
.
emplace
(
trace_ptr
(
in
));
}
return
ret
;
}
}
void
FuncInfo
::
log
()
const
void
FuncInfo
::
log
()
const
{
{
for
(
auto
it
:
use_libs
)
for
(
auto
it
:
use_libs
)
{
{
LOG_INFO
<<
it
.
first
->
get_name
()
<<
" is pure? "
<<
it
.
second
;
LOG_INFO
<<
it
.
first
->
get_name
()
<<
" is pure? "
<<
it
.
second
;
}
}
}
}
void
FuncInfo
::
cal_val_2_var
(
Value
*
var
,
std
::
unordered_map
<
Value
*
,
Value
*>&
val_2_var
)
void
FuncInfo
::
cal_val_2_var
(
Value
*
var
,
std
::
unordered_map
<
Value
*
,
Value
*>&
val_2_var
)
{
{
auto
global
=
dynamic_cast
<
GlobalVariable
*>
(
var
);
auto
global
=
dynamic_cast
<
GlobalVariable
*>
(
var
);
if
(
global
!=
nullptr
&&
global
->
is_const
())
return
;
if
(
global
!=
nullptr
&&
global
->
is_const
())
return
;
std
::
unordered_set
<
Value
*>
handled
;
std
::
unordered_set
<
Value
*>
handled
;
std
::
queue
<
Value
*>
wait_to_handle
;
std
::
queue
<
Value
*>
wait_to_handle
;
handled
.
emplace
(
var
);
handled
.
emplace
(
var
);
val_2_var
[
var
]
=
var
;
val_2_var
[
var
]
=
var
;
wait_to_handle
.
emplace
(
var
);
wait_to_handle
.
emplace
(
var
);
while
(
!
wait_to_handle
.
empty
())
while
(
!
wait_to_handle
.
empty
())
{
{
Value
*
v
=
wait_to_handle
.
front
();
Value
*
v
=
wait_to_handle
.
front
();
wait_to_handle
.
pop
();
wait_to_handle
.
pop
();
for
(
auto
&
use
:
v
->
get_use_list
())
for
(
auto
&
use
:
v
->
get_use_list
())
{
{
auto
inst
=
dynamic_cast
<
Instruction
*>
(
use
.
val_
);
auto
inst
=
dynamic_cast
<
Instruction
*>
(
use
.
val_
);
auto
f
=
inst
->
get_parent
()
->
get_parent
();
auto
f
=
inst
->
get_parent
()
->
get_parent
();
switch
(
inst
->
get_instr_type
())
switch
(
inst
->
get_instr_type
())
{
{
case
Instruction
::
load
:
case
Instruction
::
load
:
{
{
loads
[
f
].
add
(
var
);
loads
[
f
].
add
(
var
);
break
;
break
;
}
}
case
Instruction
::
store
:
case
Instruction
::
store
:
{
{
stores
[
f
].
add
(
var
);
stores
[
f
].
add
(
var
);
break
;
break
;
}
}
case
Instruction
::
getelementptr
:
case
Instruction
::
getelementptr
:
case
Instruction
::
phi
:
case
Instruction
::
phi
:
{
{
if
(
!
handled
.
count
(
inst
))
if
(
!
handled
.
count
(
inst
))
{
{
handled
.
emplace
(
inst
);
handled
.
emplace
(
inst
);
val_2_var
[
inst
]
=
var
;
val_2_var
[
inst
]
=
var
;
wait_to_handle
.
emplace
(
inst
);
wait_to_handle
.
emplace
(
inst
);
}
}
break
;
break
;
}
}
// case Instruction::call:
// case Instruction::call:
// {
// {
// 如果遇到不能确定行为的库函数,需要指定其其对参数同时进行了读写,目前这里遇不到
// 如果遇到不能确定行为的库函数,需要指定其其对参数同时进行了读写,目前这里遇不到
// auto callF = dynamic_cast<Function*>(inst->get_operand(0));
// auto callF = dynamic_cast<Function*>(inst->get_operand(0));
// if (callF->is_declaration())
// if (callF->is_declaration())
// {
// {
// stores[f].add(var);
// stores[f].add(var);
// loads[f].add(var);
// loads[f].add(var);
// }
// }
// break;
// break;
// }
// }
default:
default:
break
;
break
;
}
}
}
}
}
}
}
}
Value
*
FuncInfo
::
trace_ptr
(
Value
*
val
)
Value
*
FuncInfo
::
trace_ptr
(
Value
*
val
)
{
{
assert
(
val
!=
nullptr
);
assert
(
val
!=
nullptr
);
if
(
dynamic_cast
<
GlobalVariable
*>
(
val
)
!=
nullptr
if
(
dynamic_cast
<
GlobalVariable
*>
(
val
)
!=
nullptr
||
dynamic_cast
<
Argument
*>
(
val
)
!=
nullptr
||
dynamic_cast
<
Argument
*>
(
val
)
!=
nullptr
||
dynamic_cast
<
AllocaInst
*>
(
val
)
!=
nullptr
||
dynamic_cast
<
AllocaInst
*>
(
val
)
!=
nullptr
)
)
return
val
;
return
val
;
auto
inst
=
dynamic_cast
<
Instruction
*>
(
val
);
auto
inst
=
dynamic_cast
<
Instruction
*>
(
val
);
assert
(
inst
!=
nullptr
);
assert
(
inst
!=
nullptr
);
if
(
inst
->
is_gep
())
return
trace_ptr
(
inst
->
get_operand
(
0
));
if
(
inst
->
is_gep
())
return
trace_ptr
(
inst
->
get_operand
(
0
));
// 这意味着栈里面存在指针,你需要运行 Mem2Reg;或者你给 trace_ptr 传入了非指针参数
// 这意味着栈里面存在指针,你需要运行 Mem2Reg;或者你给 trace_ptr 传入了非指针参数
assert
(
!
inst
->
is_load
());
assert
(
!
inst
->
is_load
());
assert
(
inst
->
is_alloca
());
assert
(
inst
->
is_alloca
());
return
inst
;
return
inst
;
}
}
src/passes/LICM.cpp
View file @
f40efe88
...
@@ -14,23 +14,23 @@
...
@@ -14,23 +14,23 @@
*/
*/
void
LoopInvariantCodeMotion
::
run
()
void
LoopInvariantCodeMotion
::
run
()
{
{
func_info_
=
new
FuncInfo
(
m_
);
func_info_
=
new
FuncInfo
(
m_
);
func_info_
->
run
();
func_info_
->
run
();
for
(
auto
func
:
m_
->
get_functions
())
for
(
auto
func
:
m_
->
get_functions
())
{
{
if
(
func
->
is_declaration
())
continue
;
if
(
func
->
is_declaration
())
continue
;
loop_detection_
=
new
LoopDetection
(
func
);
loop_detection_
=
new
LoopDetection
(
func
);
loop_detection_
->
run
();
loop_detection_
->
run
();
for
(
auto
loop
:
loop_detection_
->
get_loops
())
for
(
auto
loop
:
loop_detection_
->
get_loops
())
{
{
// 遍历处理顶层循环
// 遍历处理顶层循环
if
(
loop
->
get_parent
()
==
nullptr
)
traverse_loop
(
loop
);
if
(
loop
->
get_parent
()
==
nullptr
)
traverse_loop
(
loop
);
}
}
delete
loop_detection_
;
delete
loop_detection_
;
loop_detection_
=
nullptr
;
loop_detection_
=
nullptr
;
}
}
delete
func_info_
;
delete
func_info_
;
func_info_
=
nullptr
;
func_info_
=
nullptr
;
}
}
/**
/**
...
@@ -40,12 +40,12 @@ void LoopInvariantCodeMotion::run()
...
@@ -40,12 +40,12 @@ void LoopInvariantCodeMotion::run()
*/
*/
void
LoopInvariantCodeMotion
::
traverse_loop
(
Loop
*
loop
)
void
LoopInvariantCodeMotion
::
traverse_loop
(
Loop
*
loop
)
{
{
// 先外层再内层,这样不用在插入 preheader 后更改循环
// 先外层再内层,这样不用在插入 preheader 后更改循环
run_on_loop
(
loop
);
run_on_loop
(
loop
);
for
(
auto
sub_loop
:
loop
->
get_sub_loops
())
for
(
auto
sub_loop
:
loop
->
get_sub_loops
())
{
{
traverse_loop
(
sub_loop
);
traverse_loop
(
sub_loop
);
}
}
}
}
// TODO: 收集并返回循环 store 过的变量
// TODO: 收集并返回循环 store 过的变量
...
@@ -56,35 +56,20 @@ void LoopInvariantCodeMotion::traverse_loop(Loop* loop)
...
@@ -56,35 +56,20 @@ void LoopInvariantCodeMotion::traverse_loop(Loop* loop)
// 则你应该返回 %a 而非 %b
// 则你应该返回 %a 而非 %b
std
::
unordered_set
<
Value
*>
LoopInvariantCodeMotion
::
collect_loop_store_vars
(
Loop
*
loop
)
std
::
unordered_set
<
Value
*>
LoopInvariantCodeMotion
::
collect_loop_store_vars
(
Loop
*
loop
)
{
{
// 可能用到
// 可能用到
// FuncInfo::store_ptr, FuncInfo::get_stores
// FuncInfo::store_ptr, FuncInfo::get_stores
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
}
// TODO: 收集并返回循环中的所有指令
// TODO: 收集并返回循环中的所有指令
std
::
vector
<
Instruction
*>
LoopInvariantCodeMotion
::
collect_insts
(
Loop
*
loop
)
std
::
vector
<
Instruction
*>
LoopInvariantCodeMotion
::
collect_insts
(
Loop
*
loop
)
{
{
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
// TODO: 实现collect_loop_info函数
// 1. 遍历当前循环及其子循环的所有指令
// 2. 收集所有指令到loop_instructions中
// 3. 检查store指令是否修改了全局变量,如果是则添加到updated_global中
// 4. 检查是否包含非纯函数调用,如果有则设置contains_impure_call为true
void
LoopInvariantCodeMotion
::
collect_loop_info
(
Loop
*
loop
,
std
::
set
<
Value
*>&
loop_instructions
,
std
::
set
<
Value
*>&
updated_global
,
bool
&
contains_impure_call
)
{
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
}
enum
InstructionType
:
std
::
uint8_t
enum
InstructionType
:
std
::
uint8_t
{
{
UNKNOWN
,
VARIANT
,
INVARIANT
UNKNOWN
,
VARIANT
,
INVARIANT
};
};
/**
/**
...
@@ -94,91 +79,95 @@ enum InstructionType: std::uint8_t
...
@@ -94,91 +79,95 @@ enum InstructionType: std::uint8_t
*/
*/
void
LoopInvariantCodeMotion
::
run_on_loop
(
Loop
*
loop
)
void
LoopInvariantCodeMotion
::
run_on_loop
(
Loop
*
loop
)
{
{
// 循环 store 过的变量
// 循环 store 过的变量
std
::
unordered_set
<
Value
*>
loop_stores_var
=
collect_loop_store_vars
(
loop
);
std
::
unordered_set
<
Value
*>
loop_stores_var
=
collect_loop_store_vars
(
loop
);
// 循环中的所有指令
// 循环中的所有指令
std
::
vector
<
Instruction
*>
instructions
=
collect_insts
(
loop
);
std
::
vector
<
Instruction
*>
instructions
=
collect_insts
(
loop
);
int
insts_count
=
static_cast
<
int
>
(
instructions
.
size
());
int
insts_count
=
static_cast
<
int
>
(
instructions
.
size
());
// 循环的所有基本块
// Value* 在 map 内说明它是循环内的指令,InstructionType 指示它是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std
::
unordered_set
<
BasicBlock
*>
bbs
;
std
::
unordered_map
<
Value
*
,
InstructionType
>
inst_type
;
for
(
auto
i
:
loop
->
get_blocks
())
bbs
.
emplace
(
i
);
for
(
auto
i
:
instructions
)
inst_type
[
i
]
=
UNKNOWN
;
// val 是否在循环内定义,可以当成函数进行调用
auto
is_val_in_loop
=
[
&
bbs
](
Value
*
val
)
->
bool
// 遍历后是不是还有指令不知道 InstructionType
{
bool
have_inst_can_not_decide
;
auto
inst
=
dynamic_cast
<
Instruction
*>
(
val
);
// 是否存在 invariant
if
(
inst
==
nullptr
)
return
true
;
bool
have_invariant
=
false
;
return
bbs
.
count
(
inst
->
get_parent
());
do
};
{
// inst_type[i] 代表 instructions[i] 是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
have_inst_can_not_decide
=
false
;
std
::
vector
<
InstructionType
>
inst_type
;
for
(
int
i
=
0
;
i
<
insts_count
;
i
++
)
inst_type
.
resize
(
insts_count
);
{
Instruction
*
inst
=
instructions
[
i
];
// 遍历后是不是还有指令不知道 InstructionType
InstructionType
type
=
inst_type
[
inst
];
bool
have_inst_can_not_decide
;
if
(
type
!=
UNKNOWN
)
continue
;
// 是否存在 invariant
// 可能有用的函数
bool
have_invariant
=
false
;
// FuncInfo::load_ptr, FuncInfo::get_stores, FuncInfo::use_io
do
{
// TODO: 识别循环不变式指令
have_inst_can_not_decide
=
false
;
// - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT
for
(
int
i
=
0
;
i
<
insts_count
;
i
++
)
// - 如果 load 指令加载的变量是循环 store 过的变量,标记为 VARIANT
{
// - 如果指令有 VARIANT 操作数,标记为 VARIANT
Instruction
*
inst
=
instructions
[
i
];
// - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
InstructionType
type
=
inst_type
[
i
];
// - 否则设置 have_inst_can_not_decide
if
(
type
!=
UNKNOWN
)
continue
;
// 可能有用的函数
// TODO: 外提循环不变的非纯函数调用
// FuncInfo::load_ptr
// 注意: 你不应该外提使用了 io 的函数调用
// TODO: 识别循环不变式指令
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
// - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT
}
// - 如果 load 指令加载的变量是循环 store 过的变量,标记为 VARIANT
}
// - 如果指令有 VARIANT 操作数,标记为 VARIANT
while
(
have_inst_can_not_decide
);
// - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
// - 否则设置 have_inst_can_not_decide
if
(
!
have_invariant
)
return
;
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
auto
header
=
loop
->
get_header
();
}
while
(
have_inst_can_not_decide
);
if
(
header
->
get_pre_basic_blocks
().
size
()
>
1
||
header
->
get_pre_basic_blocks
().
front
()
->
get_succ_basic_blocks
().
size
()
>
1
)
{
if
(
!
have_invariant
)
return
;
// 插入 preheader
auto
bb
=
BasicBlock
::
create
(
m_
,
""
,
loop
->
get_header
()
->
get_parent
());
auto
header
=
loop
->
get_header
();
loop
->
set_preheader
(
bb
);
if
(
header
->
get_pre_basic_blocks
().
size
()
>
1
||
header
->
get_pre_basic_blocks
().
front
()
->
get_succ_basic_blocks
().
size
()
>
1
)
for
(
auto
phi
:
loop
->
get_header
()
->
get_instructions
())
{
{
// 插入 preheader
if
(
phi
->
get_instr_type
()
!=
Instruction
::
phi
)
break
;
auto
bb
=
BasicBlock
::
create
(
m_
,
""
,
loop
->
get_header
()
->
get_parent
());
// 可能有用的函数
loop
->
set_preheader
(
bb
);
// PhiInst::create_phi
for
(
auto
phi
:
loop
->
get_header
()
->
get_instructions
())
// TODO: 分裂 phi 指令
{
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
if
(
phi
->
get_instr_type
()
!=
Instruction
::
phi
)
break
;
}
// TODO: 分裂 phi 指令
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
// 可能有用的函数
}
// BranchInst::replace_all_bb_match
// TODO: 维护 bb, header, 与 header 前驱块的基本块关系
// TODO: 维护 bb, header, 与 header 前驱块的基本块关系
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
bb
->
add_instruction
(
BranchInst
::
create_br
(
header
,
bb
));
BranchInst
::
create_br
(
header
,
bb
);
// 若你想维护 LoopDetection 在 LICM 后保持正确
// 若你想维护 LoopDetection 在 LICM 后保持正确
// auto loop2 = loop->get_parent();
// auto loop2 = loop->get_parent();
// while (loop2 != nullptr)
// while (loop2 != nullptr)
// {
// {
// loop2->get_parent()->add_block(bb);
// loop2->add_block(bb);
// loop2 = loop2->get_parent();
// loop2 = loop2->get_parent();
// }
// }
}
}
else
loop
->
set_preheader
(
header
->
get_pre_basic_blocks
().
front
());
else
loop
->
set_preheader
(
header
->
get_pre_basic_blocks
().
front
());
// insert preheader
// insert preheader
auto
preheader
=
loop
->
get_preheader
();
auto
preheader
=
loop
->
get_preheader
();
auto
terminator
=
preheader
->
get_instructions
().
back
();
auto
terminator
=
preheader
->
get_instructions
().
back
();
preheader
->
get_instructions
().
pop_back
();
preheader
->
get_instructions
().
pop_back
();
// TODO: 外提循环不变指令
// 可以使用 Function::check_for_block_relation_error 检查基本块间的关系是否正确维护
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
// TODO: 外提循环不变指令
preheader
->
add_instruction
(
terminator
);
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
preheader
->
add_instruction
(
terminator
);
std
::
cerr
<<
"licm done
\n
"
;
}
}
src/passes/LoopDetection.cpp
View file @
f40efe88
...
@@ -54,6 +54,21 @@ void LoopDetection::run() {
...
@@ -54,6 +54,21 @@ void LoopDetection::run() {
delete
dominators_
;
delete
dominators_
;
}
}
std
::
string
Loop
::
safe_print
()
const
{
std
::
string
ret
;
if
(
header_
==
nullptr
)
ret
+=
"b<null>"
;
else
ret
+=
header_
->
get_name
();
ret
+=
" "
;
ret
+=
std
::
to_string
(
blocks_
.
size
());
ret
+=
"b "
;
ret
+=
std
::
to_string
(
latches_
.
size
());
ret
+=
"latch "
;
ret
+=
std
::
to_string
(
sub_loops_
.
size
());
ret
+=
"sub"
;
return
ret
;
}
/**
/**
* @brief 发现循环及其子循环
* @brief 发现循环及其子循环
* @param bb 循环的header块
* @param bb 循环的header块
...
@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
...
@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
// 5. 建立正确的循环嵌套关系
// 5. 建立正确的循环嵌套关系
std
::
vector
<
BasicBlock
*>
work_list
=
{
latches
.
begin
(),
latches
.
end
()};
// 初始化工作表
std
::
vector
<
BasicBlock
*>
work_list
=
{
latches
.
begin
(),
latches
.
end
()};
// 初始化工作表
std
::
unordered_set
<
BasicBlock
*>
already_in_work_list
=
{
latches
.
begin
(),
latches
.
end
()
};
// 已经在工作表,防止重复加入
while
(
!
work_list
.
empty
())
{
// 当工作表非空时继续处理
while
(
!
work_list
.
empty
())
{
// 当工作表非空时继续处理
auto
bb2
=
work_list
.
back
();
auto
bb2
=
work_list
.
back
();
work_list
.
pop_back
();
work_list
.
pop_back
();
already_in_work_list
.
erase
(
bb2
);
// TODO-1: 处理未分配给任何循环的节点
// TODO-1: 处理未分配给任何循环的节点
if
(
bb_to_loop_
.
find
(
bb2
)
==
bb_to_loop_
.
end
())
{
if
(
bb_to_loop_
.
find
(
bb2
)
==
bb_to_loop_
.
end
())
{
...
@@ -85,7 +102,7 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
...
@@ -85,7 +102,7 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
}
}
// TODO-2: 处理已属于其他循环的节点
// TODO-2: 处理已属于其他循环的节点
if
(
bb_to_loop_
[
bb2
]
!=
loop
)
{
if
(
bb_to_loop_
[
bb2
]
!=
loop
)
{
/* 在此添加代码:
/* 在此添加代码:
* 1. 获取bb当前所属的循环sub_loop
* 1. 获取bb当前所属的循环sub_loop
* 2. 找到sub_loop的最顶层父循环
* 2. 找到sub_loop的最顶层父循环
...
...
src/passes/Mem2Reg.cpp
View file @
f40efe88
...
@@ -4,16 +4,17 @@
...
@@ -4,16 +4,17 @@
#include "Value.hpp"
#include "Value.hpp"
//
l_val 是否是非数组 alloca 变量
//
ptr 是否是非数组 alloca 变量(是则转换为 AllocaInst)
static
bool
is_not_array_alloca
(
Value
*
l_val
)
static
AllocaInst
*
is_not_array_alloca
(
Value
*
ptr
)
{
{
auto
alloca
=
dynamic_cast
<
AllocaInst
*>
(
l_val
);
auto
alloca
=
dynamic_cast
<
AllocaInst
*>
(
ptr
);
return
alloca
!=
nullptr
&&
!
alloca
->
get_alloca_type
()
->
is_array_type
();
if
(
alloca
!=
nullptr
&&
!
alloca
->
get_alloca_type
()
->
is_array_type
())
return
alloca
;
return
nullptr
;
}
}
/**
/**
* @brief Mem2Reg Pass的主入口函数
* @brief Mem2Reg Pass的主入口函数
*
*
* 该函数执行内存到寄存器的提升过程,将栈上的局部变量提升到SSA格式。
* 该函数执行内存到寄存器的提升过程,将栈上的局部变量提升到SSA格式。
* 主要步骤:
* 主要步骤:
* 1. 创建并运行支配树分析
* 1. 创建并运行支配树分析
...
@@ -21,7 +22,7 @@ static bool is_not_array_alloca(Value* l_val)
...
@@ -21,7 +22,7 @@ static bool is_not_array_alloca(Value* l_val)
* - 清空相关数据结构
* - 清空相关数据结构
* - 插入必要的phi指令
* - 插入必要的phi指令
* - 执行变量重命名
* - 执行变量重命名
*
*
* 注意:函数执行后,冗余的局部变量分配指令将由后续的死代码删除Pass处理
* 注意:函数执行后,冗余的局部变量分配指令将由后续的死代码删除Pass处理
*/
*/
void
Mem2Reg
::
run
()
{
void
Mem2Reg
::
run
()
{
...
@@ -43,7 +44,7 @@ void Mem2Reg::run() {
...
@@ -43,7 +44,7 @@ void Mem2Reg::run() {
generate_phi
();
generate_phi
();
// 确保每个局部变量的栈都有初始值
// 确保每个局部变量的栈都有初始值
for
(
auto
var
:
allocas_
)
for
(
auto
var
:
allocas_
)
var_val_stack
[
var
].
emplace_back
(
ConstantZero
::
get
(
var
->
get_alloca_type
(),
m_
));
var_val_stack
[
var
].
emplace_back
(
var
->
get_alloca_type
()
->
is_float_type
()
?
static_cast
<
Value
*>
(
ConstantFP
::
get
(
0
,
m_
))
:
static_cast
<
Value
*>
(
ConstantInt
::
get
(
0
,
m_
)
));
// 对应伪代码中重命名阶段
// 对应伪代码中重命名阶段
rename
(
func_
->
get_entry_block
());
rename
(
func_
->
get_entry_block
());
}
}
...
@@ -55,17 +56,17 @@ void Mem2Reg::run() {
...
@@ -55,17 +56,17 @@ void Mem2Reg::run() {
/**
/**
* @brief 在必要的位置插入phi指令
* @brief 在必要的位置插入phi指令
*
*
* 该函数实现了经典的phi节点插入算法:
* 该函数实现了经典的phi节点插入算法:
* 1. 收集全局活跃变量:
* 1. 收集全局活跃变量:
* - 扫描所有store指令
* - 扫描所有store指令
* - 识别在多个基本块中被赋值的变量
* - 识别在多个基本块中被赋值的变量
*
*
* 2. 插入phi指令:
* 2. 插入phi指令:
* - 对每个全局活跃变量
* - 对每个全局活跃变量
* - 在其定值点的支配边界处插入phi指令
* - 在其定值点的支配边界处插入phi指令
* - 使用工作表法处理迭代式的phi插入
* - 使用工作表法处理迭代式的phi插入
*
*
* phi指令的插入遵循最小化原则,只在必要的位置插入phi节点
* phi指令的插入遵循最小化原则,只在必要的位置插入phi节点
*/
*/
void
Mem2Reg
::
generate_phi
()
{
void
Mem2Reg
::
generate_phi
()
{
...
@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() {
...
@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() {
if
(
instr
->
is_store
())
{
if
(
instr
->
is_store
())
{
// store i32 a, i32 *b
// store i32 a, i32 *b
// a is r_val, b is l_val
// a is r_val, b is l_val
auto
l_val
=
dynamic_cast
<
StoreInst
*>
(
instr
)
->
get_lval
();
auto
l_val
=
dynamic_cast
<
StoreInst
*>
(
instr
)
->
get_ptr
();
if
(
is_not_array_alloca
(
l_val
))
{
if
(
auto
lalloca
=
is_not_array_alloca
(
l_val
))
{
auto
lalloca
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
if
(
!
not_array_allocas
.
count
(
lalloca
))
not_array_allocas
.
insert
(
lalloca
);
{
allocas_
.
emplace_back
(
lalloca
);
not_array_allocas
.
insert
(
lalloca
);
allocas_
.
emplace_back
(
lalloca
);
}
allocas_stored_bbs
[
lalloca
].
emplace_back
(
bb
);
allocas_stored_bbs
[
lalloca
].
emplace_back
(
bb
);
}
}
}
}
...
@@ -105,7 +108,7 @@ void Mem2Reg::generate_phi() {
...
@@ -105,7 +108,7 @@ void Mem2Reg::generate_phi() {
if
(
already_handled
.
count
(
bb
))
continue
;
if
(
already_handled
.
count
(
bb
))
continue
;
already_handled
.
emplace
(
bb
);
already_handled
.
emplace
(
bb
);
for
(
auto
bb_dominance_frontier_bb
:
for
(
auto
bb_dominance_frontier_bb
:
dominators_
->
get_dominance_frontier
(
bb
))
{
dominators_
->
get_dominance_frontier
(
bb
))
{
if
(
bb_has_var_phi
.
find
({
bb_dominance_frontier_bb
,
var
})
==
if
(
bb_has_var_phi
.
find
({
bb_dominance_frontier_bb
,
var
})
==
bb_has_var_phi
.
end
())
{
bb_has_var_phi
.
end
())
{
// generate phi for bb_dominance_frontier_bb & add
// generate phi for bb_dominance_frontier_bb & add
...
@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() {
...
@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() {
bb_dominance_frontier_bb
);
bb_dominance_frontier_bb
);
phi_to_alloca_
.
emplace
(
phi
,
var
);
phi_to_alloca_
.
emplace
(
phi
,
var
);
bb_to_phi_
[
bb_dominance_frontier_bb
].
emplace_back
(
phi
);
bb_to_phi_
[
bb_dominance_frontier_bb
].
emplace_back
(
phi
);
bb_dominance_frontier_bb
->
add_instr_begin
(
phi
);
work_list
.
push_back
(
bb_dominance_frontier_bb
);
work_list
.
push_back
(
bb_dominance_frontier_bb
);
bb_has_var_phi
.
emplace
(
bb_dominance_frontier_bb
,
var
);
bb_has_var_phi
.
emplace
(
bb_dominance_frontier_bb
,
var
);
}
}
...
@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) {
...
@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) {
// 可能用到的数据结构
// 可能用到的数据结构
// list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历
// list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历
// map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空
// map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空
// map<PhiInst *, AllocaInst*>
; Phi 对应的局部变量
// map<PhiInst *, AllocaInst*> phi_to_alloca_
; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>>
; 在某个基本块的 Phi
// map<BasicBlock*, list<PhiInst*>> bb_to_phi_
; 在某个基本块的 Phi
// 可能用到的函数
// 可能用到的函数
// Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a
// Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a
// BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令
// BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令
// StoreInst / LoadInst get_ptr 这些 Inst 所操作的变量
// is_not_array_alloca(Value* ptr) 一个变量是不是 Mem2Reg 所关心的非数组局部变量
// TODO
// TODO
// 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值)
// 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值)
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令(注意: 并非所有 load/store/alloca 都是 Mem2Reg 需要处理的)
// - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶)
// - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶)
// - 步骤四: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// - 步骤四: 将 phi 指令的所有使用替换为其对应的局部变量的最新值
// 步骤五:为所有后继块的 phi 添加参数
// - 步骤五: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤六:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤六:为所有后继块的 phi 添加参数
// 步骤七:pop 出所有局部变量的最新值
// 步骤七:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤八:删除需要删除的冗余指令
// 步骤八:pop 出所有局部变量的最新值
// 步骤九:删除需要删除的冗余指令
}
}
tests/4-opt/CMakeLists.txt
0 → 100644
View file @
f40efe88
add_executable
(
eval_lab4
eval_lab4.cpp
)
install
(
TARGETS eval_lab4
)
\ No newline at end of file
tests/4-opt/eval_lab4.cpp
0 → 100644
View file @
f40efe88
// ReSharper disable CppClangTidyPerformanceInefficientStringConcatenation
#include <climits>
#include <complex>
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iterator>
#include <list>
#include <optional>
#include <regex>
#include <string>
#include <unistd.h>
#include <sys/select.h>
#include <sys/wait.h>
using
namespace
std
;
enum
evaluate_result
:
uint8_t
{
SUCCESS
,
FAIL
,
PASS
};
static
enum
stage
:
uint8_t
{
raw
,
mem2reg
,
licm
,
all
}
STAGE
;
static
string
TEST_PATH
;
static
enum
test_type
:
uint8_t
{
debug
,
test
}
TYPE
;
struct
cmd_result
{
string
out_str
;
string
err_str
;
int
ret_val
;
bool
have_err_message
()
const
{
return
!
err_str
.
empty
();
}
};
struct
cmd_result_mix
{
string
str
;
int
ret_val
;
};
static
string
red
(
const
string
&
str
)
{
return
"
\033
[31;1m"
+
str
+
"
\033
[0m"
;
}
static
string
green
(
const
string
&
str
)
{
return
"
\033
[32;1m"
+
str
+
"
\033
[0m"
;
}
static
ofstream
ost
;
static
void
ext
(
int
flag
)
{
ost
.
close
();
exit
(
flag
);
}
static
void
out
(
const
string
&
str
,
bool
to_std
)
{
if
(
to_std
)
cout
<<
str
;
else
ost
<<
str
;
}
static
void
out2
(
const
string
&
str
)
{
cout
<<
str
;
ost
<<
str
;
}
static
void
out2e
(
const
string
&
str
)
{
cout
<<
red
(
str
);
ost
<<
str
;
}
static
std
::
pair
<
std
::
string
,
std
::
string
>
readPipeLine
(
int
outpipe
[],
int
errpipe
[],
int
limit
)
{
fd_set
readfds
;
int
maxFd
=
std
::
max
(
outpipe
[
0
],
errpipe
[
0
]);
char
buffer
[
1024
];
std
::
string
stdout_result
;
std
::
string
stderr_result
;
int
totalRead
=
0
;
bool
have_stdout
=
true
;
bool
have_stderr
=
true
;
while
(
true
)
{
FD_ZERO
(
&
readfds
);
if
(
have_stdout
)
FD_SET
(
outpipe
[
0
],
&
readfds
);
if
(
have_stderr
)
FD_SET
(
errpipe
[
0
],
&
readfds
);
int
ret
=
select
(
maxFd
+
1
,
&
readfds
,
nullptr
,
nullptr
,
nullptr
);
if
(
ret
==
-
1
)
{
out
(
"select() 调用失败!
\n
"
,
true
);
out
(
"select() 调用失败!
\n
"
,
false
);
ext
(
-
1
);
}
if
(
ret
==
0
)
continue
;
if
(
FD_ISSET
(
outpipe
[
0
],
&
readfds
))
{
int
bytes
=
static_cast
<
int
>
(
read
(
outpipe
[
0
],
buffer
,
sizeof
(
buffer
)
-
1
));
if
(
bytes
>
0
)
{
int
writeLen
=
std
::
min
(
bytes
,
limit
-
totalRead
);
buffer
[
writeLen
]
=
'\0'
;
stdout_result
+=
buffer
;
totalRead
+=
writeLen
;
if
(
totalRead
>=
limit
)
break
;
}
else
{
FD_CLR
(
outpipe
[
0
],
&
readfds
);
close
(
outpipe
[
0
]);
have_stdout
=
false
;
maxFd
=
have_stderr
?
errpipe
[
0
]
:
-
1
;
}
}
if
(
FD_ISSET
(
errpipe
[
0
],
&
readfds
))
{
int
bytes
=
static_cast
<
int
>
(
read
(
errpipe
[
0
],
buffer
,
sizeof
(
buffer
)
-
1
));
if
(
bytes
>
0
)
{
int
writeLen
=
std
::
min
(
bytes
,
limit
-
totalRead
);
buffer
[
writeLen
]
=
'\0'
;
stderr_result
+=
buffer
;
totalRead
+=
writeLen
;
if
(
totalRead
>=
limit
)
break
;
}
else
{
FD_CLR
(
errpipe
[
0
],
&
readfds
);
close
(
errpipe
[
0
]);
have_stderr
=
false
;
maxFd
=
have_stdout
?
outpipe
[
0
]
:
-
1
;
}
}
if
(
!
FD_ISSET
(
outpipe
[
0
],
&
readfds
)
&&
!
FD_ISSET
(
errpipe
[
0
],
&
readfds
))
break
;
}
if
(
!
stdout_result
.
empty
()
&&
stdout_result
.
back
()
!=
'\n'
)
stdout_result
+=
'\n'
;
if
(
!
stderr_result
.
empty
()
&&
stderr_result
.
back
()
!=
'\n'
)
stderr_result
+=
'\n'
;
return
{
stdout_result
,
stderr_result
};
}
static
std
::
string
readPipeLineMix
(
int
outpipe
[],
int
errpipe
[],
int
limit
)
{
fd_set
readfds
;
int
maxFd
=
std
::
max
(
outpipe
[
0
],
errpipe
[
0
]);
char
buffer
[
1024
];
std
::
string
result
;
int
totalRead
=
0
;
bool
have_stdout
=
true
;
bool
have_stderr
=
true
;
while
(
true
)
{
FD_ZERO
(
&
readfds
);
if
(
have_stdout
)
FD_SET
(
outpipe
[
0
],
&
readfds
);
if
(
have_stderr
)
FD_SET
(
errpipe
[
0
],
&
readfds
);
int
ret
=
select
(
maxFd
+
1
,
&
readfds
,
nullptr
,
nullptr
,
nullptr
);
if
(
ret
==
-
1
)
{
out
(
"select() 调用失败!
\n
"
,
true
);
out
(
"select() 调用失败!
\n
"
,
false
);
ext
(
-
1
);
}
if
(
ret
==
0
)
continue
;
if
(
FD_ISSET
(
outpipe
[
0
],
&
readfds
))
{
int
bytes
=
static_cast
<
int
>
(
read
(
outpipe
[
0
],
buffer
,
sizeof
(
buffer
)
-
1
));
if
(
bytes
>
0
)
{
int
writeLen
=
std
::
min
(
bytes
,
limit
-
totalRead
);
buffer
[
writeLen
]
=
'\0'
;
result
+=
buffer
;
totalRead
+=
writeLen
;
if
(
totalRead
>=
limit
)
break
;
}
else
{
FD_CLR
(
outpipe
[
0
],
&
readfds
);
close
(
outpipe
[
0
]);
have_stdout
=
false
;
maxFd
=
have_stderr
?
errpipe
[
0
]
:
-
1
;
}
}
if
(
FD_ISSET
(
errpipe
[
0
],
&
readfds
))
{
int
bytes
=
static_cast
<
int
>
(
read
(
errpipe
[
0
],
buffer
,
sizeof
(
buffer
)
-
1
));
if
(
bytes
>
0
)
{
int
writeLen
=
std
::
min
(
bytes
,
limit
-
totalRead
);
buffer
[
writeLen
]
=
'\0'
;
result
+=
buffer
;
totalRead
+=
writeLen
;
if
(
totalRead
>=
limit
)
break
;
}
else
{
FD_CLR
(
errpipe
[
0
],
&
readfds
);
close
(
errpipe
[
0
]);
have_stderr
=
false
;
maxFd
=
have_stdout
?
outpipe
[
0
]
:
-
1
;
}
}
if
(
!
FD_ISSET
(
outpipe
[
0
],
&
readfds
)
&&
!
FD_ISSET
(
errpipe
[
0
],
&
readfds
))
break
;
}
if
(
!
result
.
empty
()
&&
result
.
back
()
!=
'\n'
)
result
+=
'\n'
;
return
result
;
}
static
cmd_result
runCommand
(
const
std
::
string
&
command
,
int
limit
=
INT_MAX
)
{
int
outpipe
[
2
];
int
errpipe
[
2
];
if
(
pipe
(
outpipe
)
!=
0
||
pipe
(
errpipe
)
!=
0
)
{
out2
(
"pipe() 调用失败!
\n
"
);
ext
(
-
1
);
}
pid_t
pid
=
fork
();
if
(
pid
==
-
1
)
{
out2
(
"fork() 调用失败!
\n
"
);
ext
(
-
1
);
}
if
(
pid
==
0
)
{
close
(
outpipe
[
0
]);
close
(
errpipe
[
0
]);
dup2
(
outpipe
[
1
],
STDOUT_FILENO
);
dup2
(
errpipe
[
1
],
STDERR_FILENO
);
execlp
(
"sh"
,
"sh"
,
"-c"
,
command
.
c_str
(),
static_cast
<
char
*>
(
nullptr
));
perror
(
"execlp"
);
ext
(
127
);
}
close
(
outpipe
[
1
]);
close
(
errpipe
[
1
]);
auto
res
=
readPipeLine
(
outpipe
,
errpipe
,
limit
);
int
status
;
waitpid
(
pid
,
&
status
,
0
);
cmd_result
ret
;
ret
.
out_str
=
res
.
first
;
ret
.
err_str
=
res
.
second
;
ret
.
ret_val
=
WEXITSTATUS
(
status
);
return
ret
;
}
static
cmd_result_mix
runCommandMix
(
const
std
::
string
&
command
,
int
limit
=
INT_MAX
)
{
int
outpipe
[
2
];
int
errpipe
[
2
];
if
(
pipe
(
outpipe
)
!=
0
||
pipe
(
errpipe
)
!=
0
)
{
out2
(
"pipe() 调用失败!
\n
"
);
ext
(
-
1
);
}
pid_t
pid
=
fork
();
if
(
pid
==
-
1
)
{
out2
(
"fork() 调用失败!
\n
"
);
ext
(
-
1
);
}
if
(
pid
==
0
)
{
close
(
outpipe
[
0
]);
close
(
errpipe
[
0
]);
dup2
(
outpipe
[
1
],
STDOUT_FILENO
);
dup2
(
errpipe
[
1
],
STDERR_FILENO
);
execlp
(
"sh"
,
"sh"
,
"-c"
,
command
.
c_str
(),
static_cast
<
char
*>
(
nullptr
));
perror
(
"execlp"
);
ext
(
127
);
}
close
(
outpipe
[
1
]);
close
(
errpipe
[
1
]);
auto
res
=
readPipeLineMix
(
outpipe
,
errpipe
,
limit
);
int
status
;
waitpid
(
pid
,
&
status
,
0
);
cmd_result_mix
ret
;
ret
.
str
=
res
;
ret
.
ret_val
=
WEXITSTATUS
(
status
);
return
ret
;
}
static
list
<
string
>
splitString
(
const
string
&
str
)
{
list
<
string
>
lines
;
std
::
istringstream
stream
(
str
);
std
::
string
line
;
while
(
std
::
getline
(
stream
,
line
))
{
if
(
!
line
.
empty
())
lines
.
push_back
(
line
);
}
return
lines
;
}
static
std
::
string
readFile
(
const
std
::
string
&
filename
)
{
std
::
ifstream
file
(
filename
);
if
(
!
file
.
is_open
())
{
cerr
<<
"无法打开文件 "
+
filename
<<
'\n'
;
ext
(
-
1
);
}
std
::
string
content
((
std
::
istreambuf_iterator
(
file
)),
std
::
istreambuf_iterator
<
char
>
());
file
.
close
();
return
content
;
}
static
void
writeFile
(
const
std
::
string
&
content
,
const
std
::
string
&
filename
)
{
std
::
ofstream
file
(
filename
);
if
(
!
file
.
is_open
())
{
cerr
<<
"无法打开文件 "
+
filename
<<
'\n'
;
ext
(
-
1
);
}
file
<<
content
;
file
.
close
();
}
static
string
lastDotLeft
(
const
string
&
str
)
{
size_t
lastDotPos
=
str
.
find_last_of
(
'.'
);
if
(
lastDotPos
==
string
::
npos
)
{
return
str
;
}
return
str
.
substr
(
0
,
lastDotPos
);
}
static
string
lastLineRight
(
const
string
&
str
)
{
size_t
lastSlashPos
=
str
.
find_last_of
(
'/'
);
if
(
lastSlashPos
==
string
::
npos
)
{
return
str
;
}
return
str
.
substr
(
lastSlashPos
+
1
);
}
static
void
makeDir
(
const
string
&
dirPath
)
{
if
(
filesystem
::
exists
(
dirPath
))
return
;
if
(
!
filesystem
::
create_directories
(
dirPath
))
{
out2
(
"目录 "
+
dirPath
+
" 创建失败!
\n
"
);
ext
(
-
1
);
}
}
static
const
char
*
ERR_LOG
=
R"(Usage: ./eval_lab4.sh [test-stage] [path-to-testcases] [type]
test-stage: 'raw' or 'licm' or 'mem2reg' or 'all'
path-to-testcases: './testcases/functional-cases' or '../testcases_general' or 'self made cases'
type: 'debug' or 'test', debug will output .ll file
)"
;
static
int
parseCmd
(
int
argc
,
char
*
argv
[])
{
if
(
argc
!=
4
)
{
out
(
ERR_LOG
,
true
);
return
-
1
;
}
if
(
std
::
strcmp
(
argv
[
1
],
"licm"
)
==
0
)
{
STAGE
=
licm
;
ost
.
open
(
"licm_log.txt"
,
ios
::
out
);
}
else
if
(
std
::
strcmp
(
argv
[
1
],
"mem2reg"
)
==
0
)
{
STAGE
=
mem2reg
;
ost
.
open
(
"mem2reg_log.txt"
,
ios
::
out
);
}
else
if
(
std
::
strcmp
(
argv
[
1
],
"raw"
)
==
0
)
{
STAGE
=
raw
;
ost
.
open
(
"raw_log.txt"
,
ios
::
out
);
}
else
if
(
std
::
strcmp
(
argv
[
1
],
"all"
)
==
0
)
{
STAGE
=
all
;
ost
.
open
(
"all_log.txt"
,
ios
::
out
);
}
else
{
out
(
ERR_LOG
,
true
);
return
-
1
;
}
TEST_PATH
=
argv
[
2
];
if
(
TEST_PATH
.
empty
()
||
TEST_PATH
.
back
()
!=
'/'
)
TEST_PATH
+=
'/'
;
if
(
!
std
::
filesystem
::
exists
(
TEST_PATH
))
{
out2
(
"测评路径 "
+
TEST_PATH
+
" 不存在
\n
"
);
return
-
1
;
}
if
(
!
std
::
filesystem
::
is_directory
(
TEST_PATH
))
{
out2
(
"测评路径 "
+
TEST_PATH
+
" 不是文件夹
\n
"
);
return
-
1
;
}
if
(
std
::
strcmp
(
argv
[
3
],
"debug"
)
==
0
)
TYPE
=
debug
;
else
if
(
std
::
strcmp
(
argv
[
3
],
"test"
)
==
0
)
TYPE
=
test
;
else
{
out2
(
ERR_LOG
);
return
-
1
;
}
return
0
;
}
static
string
pad
(
int
count
)
{
return
count
>
0
?
std
::
string
(
count
,
' '
)
:
std
::
string
();
}
static
string
pad
(
int
count
,
char
target
)
{
return
count
>
0
?
std
::
string
(
count
,
target
)
:
std
::
string
();
}
static
int
allmain
(
int
argc
,
char
*
argv
[])
{
auto
cmd
=
R"(ls )"
+
TEST_PATH
+
R"(*.cminus | sort -V)"
;
auto
result
=
runCommand
(
cmd
);
string
flags
[
3
]
=
{
""
,
"-mem2reg "
,
"-mem2reg -licm "
};
string
tys
[
3
]
=
{
"raw"
,
"mem2reg"
,
"licm"
};
if
(
result
.
have_err_message
())
out2e
(
result
.
err_str
);
auto
io_c
=
runCommand
(
"realpath ../../"
).
out_str
;
io_c
.
pop_back
();
io_c
+=
"/src/io/io.c"
;
auto
io_h
=
io_c
;
io_h
.
back
()
=
'h'
;
auto
tests
=
splitString
(
result
.
out_str
);
string
out_path
=
"./output/"
;
out2
(
"[info] Start testing, using testcase dir: "
+
TEST_PATH
+
"
\n
"
);
int
maxLen
=
0
;
for
(
const
auto
&
line
:
tests
)
maxLen
=
std
::
max
(
maxLen
,
static_cast
<
int
>
(
line
.
size
()));
for
(
const
auto
&
line
:
tests
)
{
auto
no_path_have_suffix
=
lastLineRight
(
line
);
auto
no_path_no_suffix
=
lastDotLeft
(
no_path_have_suffix
);
makeDir
(
out_path
+
no_path_no_suffix
);
auto
in_file
=
TEST_PATH
+
no_path_no_suffix
+
".in"
;
auto
std_out_file
=
TEST_PATH
+
no_path_no_suffix
+
".out"
;
out2
(
"=========="
+
no_path_have_suffix
+
pad
(
maxLen
-
static_cast
<
int
>
(
line
.
length
()),
'='
)
+
"==========
\n
"
);
int
sz
[
2
]
=
{};
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
const
auto
&
arg
=
flags
[
i
];
const
auto
&
ty
=
tys
[
i
];
auto
ll_file
=
out_path
+
no_path_no_suffix
+
"/"
+
ty
+
".ll"
;
auto
asm_file
=
out_path
+
no_path_no_suffix
+
"/"
+
ty
+
".s"
;
auto
exe_file
=
out_path
+
no_path_no_suffix
+
"/"
+
ty
+
"o"
;
auto
out_file
=
out_path
+
no_path_no_suffix
+
"/"
+
ty
+
".out"
;
auto
eval_file
=
out_path
+
no_path_no_suffix
+
"/eval_"
+
ty
+
".txt"
;
out
(
ty
+
pad
(
7
-
static_cast
<
int
>
(
ty
.
length
()))
+
" "
,
true
);
out
(
"=========="
+
ty
+
pad
(
7
-
static_cast
<
int
>
(
ty
.
length
()),
'='
)
+
"==========
\n
"
,
false
);
cout
.
flush
();
ost
.
flush
();
auto
cmd2
=
runCommandMix
(
"cminusfc -S "
+
arg
+
line
+
" -o "
+
asm_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: cminusfc compiler .cminus error
\n
"
);
continue
;
}
if
(
TYPE
==
debug
)
{
cmd2
=
runCommandMix
(
"loongarch64-unknown-linux-gnu-gcc -g -static "
+
asm_file
+
" "
+
io_c
+
" -o "
+
exe_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: gcc compiler .s error
\n
"
);
continue
;
}
}
else
{
cmd2
=
runCommandMix
(
"loongarch64-unknown-linux-gnu-gcc -static "
+
asm_file
+
" "
+
io_c
+
" -o "
+
exe_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: gcc compiler .s error
\n
"
);
continue
;
}
}
cmd_result
ret
;
if
(
filesystem
::
exists
(
in_file
))
ret
=
runCommand
(
"qemu-loongarch64 "
+
exe_file
+
" >"
+
out_file
+
" <"
+
in_file
);
else
ret
=
runCommand
(
"qemu-loongarch64 "
+
exe_file
+
" >"
+
out_file
);
auto
o
=
readFile
(
out_file
);
writeFile
(
o
+
to_string
(
ret
.
ret_val
)
+
"
\n
"
,
out_file
);
writeFile
(
ret
.
err_str
,
eval_file
);
cmd2
=
runCommandMix
(
"diff --strip-trailing-cr "
+
std_out_file
+
" "
+
out_file
+
" -y"
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
!=
0
)
{
out2e
(
"WA: output differ, check "
+
std_out_file
+
" and "
+
out_file
+
"
\n
"
);
continue
;
}
out
(
green
(
" OK"
),
true
);
out
(
"OK
\n
"
,
false
);
auto
strs
=
splitString
(
ret
.
err_str
);
if
(
strs
.
size
()
>=
6
)
{
out
(
" Take Time (us): "
+
green
(
strs
.
back
())
+
pad
(
sz
[
0
]
==
0
?
1
:
(
sz
[
0
]
-
static_cast
<
int
>
(
strs
.
back
().
size
()))),
true
);
out
(
" Take Time (us): "
+
strs
.
back
()
+
pad
(
sz
[
0
]
==
0
?
1
:
(
sz
[
0
]
-
static_cast
<
int
>
(
strs
.
back
().
size
()))),
false
);
if
(
sz
[
0
]
==
0
)
sz
[
0
]
=
static_cast
<
int
>
(
strs
.
back
().
size
())
+
1
;
strs
.
pop_back
();
strs
.
pop_back
();
out
(
" Inst Execute Cost: "
+
green
(
strs
.
back
())
+
pad
(
sz
[
1
]
-
static_cast
<
int
>
(
strs
.
back
().
size
())),
true
);
out
(
" Inst Execute Cost: "
+
strs
.
back
()
+
pad
(
sz
[
1
]
-
static_cast
<
int
>
(
strs
.
back
().
size
())),
false
);
if
(
sz
[
1
]
==
0
)
sz
[
1
]
=
static_cast
<
int
>
(
strs
.
back
().
size
());
strs
.
pop_back
();
strs
.
pop_back
();
out
(
" Allocate Size (bytes): "
+
green
(
strs
.
back
())
+
"
\n
"
,
true
);
out
(
" Allocate Size (bytes): "
+
strs
.
back
()
+
"
\n
"
,
false
);
}
else
cout
<<
"
\n
"
;
filesystem
::
remove
(
exe_file
);
filesystem
::
remove
(
out_file
);
filesystem
::
remove
(
asm_file
);
}
}
return
0
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
if
(
parseCmd
(
argc
,
argv
))
ext
(
-
1
);
if
(
STAGE
==
all
)
{
return
allmain
(
argc
,
argv
);
}
auto
cmd
=
R"(ls )"
+
TEST_PATH
+
R"(*.cminus | sort -V)"
;
auto
result
=
runCommand
(
cmd
);
string
flags
=
(
STAGE
==
mem2reg
?
"-mem2reg "
:
(
STAGE
==
raw
?
""
:
"-mem2reg -licm "
));
if
(
result
.
have_err_message
())
out2e
(
result
.
err_str
);
auto
io_c
=
runCommand
(
"realpath ../../"
).
out_str
;
io_c
.
pop_back
();
io_c
+=
"/src/io/io.c"
;
auto
io_h
=
io_c
;
io_h
.
back
()
=
'h'
;
auto
tests
=
splitString
(
result
.
out_str
);
string
out_path
=
"./output/"
;
out2
(
"[info] Start testing, using testcase dir: "
+
TEST_PATH
+
"
\n
"
);
int
maxLen
=
0
;
for
(
const
auto
&
line
:
tests
)
maxLen
=
std
::
max
(
maxLen
,
static_cast
<
int
>
(
line
.
size
()));
for
(
const
auto
&
line
:
tests
)
{
auto
no_path_have_suffix
=
lastLineRight
(
line
);
auto
no_path_no_suffix
=
lastDotLeft
(
no_path_have_suffix
);
makeDir
(
out_path
+
no_path_no_suffix
);
auto
ll_file
=
out_path
+
no_path_no_suffix
+
"/"
+
argv
[
1
]
+
".ll"
;
auto
asm_file
=
out_path
+
no_path_no_suffix
+
"/"
+
argv
[
1
]
+
".s"
;
auto
exe_file
=
out_path
+
no_path_no_suffix
+
"/"
+
argv
[
1
]
+
"o"
;
auto
out_file
=
out_path
+
no_path_no_suffix
+
"/"
+
argv
[
1
]
+
".out"
;
auto
eval_file
=
out_path
+
no_path_no_suffix
+
"/eval_"
+
argv
[
1
]
+
".txt"
;
auto
in_file
=
TEST_PATH
+
no_path_no_suffix
+
".in"
;
auto
std_out_file
=
TEST_PATH
+
no_path_no_suffix
+
".out"
;
out
(
no_path_have_suffix
+
pad
(
maxLen
-
static_cast
<
int
>
(
line
.
length
()))
+
" "
,
true
);
out
(
"=========="
+
no_path_have_suffix
+
pad
(
maxLen
-
static_cast
<
int
>
(
line
.
length
()),
'='
)
+
"==========
\n
"
,
false
);
cout
.
flush
();
ost
.
flush
();
auto
cmd2
=
runCommandMix
(
"cminusfc -S "
+
flags
+
line
+
" -o "
+
asm_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: cminusfc compiler .cminus error
\n
"
);
continue
;
}
if
(
TYPE
==
debug
)
{
cmd2
=
runCommandMix
(
"loongarch64-unknown-linux-gnu-gcc -g -static "
+
asm_file
+
" "
+
io_c
+
" -o "
+
exe_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: gcc compiler .s error
\n
"
);
continue
;
}
}
else
{
cmd2
=
runCommandMix
(
"loongarch64-unknown-linux-gnu-gcc -static "
+
asm_file
+
" "
+
io_c
+
" -o "
+
exe_file
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
)
{
out2e
(
"CE: gcc compiler .s error
\n
"
);
continue
;
}
}
cmd_result
ret
;
if
(
filesystem
::
exists
(
in_file
))
ret
=
runCommand
(
"qemu-loongarch64 "
+
exe_file
+
" >"
+
out_file
+
" <"
+
in_file
);
else
ret
=
runCommand
(
"qemu-loongarch64 "
+
exe_file
+
" >"
+
out_file
);
auto
o
=
readFile
(
out_file
);
writeFile
(
o
+
to_string
(
ret
.
ret_val
)
+
"
\n
"
,
out_file
);
writeFile
(
ret
.
err_str
,
eval_file
);
cmd2
=
runCommandMix
(
"diff --strip-trailing-cr "
+
std_out_file
+
" "
+
out_file
+
" -y"
);
out
(
cmd2
.
str
,
false
);
if
(
cmd2
.
ret_val
!=
0
)
{
out2e
(
"WA: output differ, check "
+
std_out_file
+
" and "
+
out_file
+
"
\n
"
);
continue
;
}
out
(
green
(
" OK"
),
true
);
out
(
"OK
\n
"
,
false
);
auto
strs
=
splitString
(
ret
.
err_str
);
if
(
strs
.
size
()
>=
6
)
{
out
(
" Take Time (us): "
+
green
(
strs
.
back
()),
true
);
out
(
" Take Time (us): "
+
strs
.
back
(),
false
);
strs
.
pop_back
();
strs
.
pop_back
();
out
(
" Inst Execute Cost: "
+
green
(
strs
.
back
()),
true
);
out
(
" Inst Execute Cost: "
+
strs
.
back
(),
false
);
strs
.
pop_back
();
strs
.
pop_back
();
out
(
" Allocate Size (bytes): "
+
green
(
strs
.
back
())
+
"
\n
"
,
true
);
out
(
" Allocate Size (bytes): "
+
strs
.
back
()
+
"
\n
"
,
false
);
}
else
cout
<<
"
\n
"
;
filesystem
::
remove
(
exe_file
);
filesystem
::
remove
(
out_file
);
filesystem
::
remove
(
asm_file
);
}
}
tests/CMakeLists.txt
View file @
f40efe88
add_subdirectory
(
"2-ir-gen/warmup"
)
# add_subdirectory("2-ir-gen/warmup")
add_subdirectory
(
"3-codegen/warmup"
)
# add_subdirectory("3-codegen/warmup")
\ No newline at end of file
add_subdirectory
(
"4-opt"
)
\ No newline at end of file
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