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
Show 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})
include_directories
(
${
PROJECT_SOURCE_DIR
}
)
include_directories
(
${
PROJECT_BINARY_DIR
}
)
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 {
auto
*
output_float_fun
=
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
.
push
(
"input"
,
input_fun
);
scope
.
push
(
"output"
,
output_fun
);
scope
.
push
(
"outputFloat"
,
output_float_fun
);
scope
.
push
(
"neg_idx_except"
,
neg_idx_except_fun
);
}
Module
*
getModule
()
const
{
return
module
;
}
...
...
include/codegen/CodeGen.hpp
View file @
f40efe88
...
...
@@ -64,18 +64,6 @@ class CodeGen {
void
gen_fptosi
();
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
{
/* 随着ir遍历设置 */
Function
*
func
{
nullptr
};
// 当前函数
...
...
@@ -84,14 +72,12 @@ class CodeGen {
/* 在allocate()中设置 */
unsigned
frame_size
{
0
};
// 当前函数的栈帧大小
std
::
unordered_map
<
Value
*
,
int
>
offset_map
{};
// 指针相对 fp 的偏移
unsigned
fcmp_cnt
{
0
};
// fcmp 的计数器, 用于创建 fcmp 需要的 label
void
clear
()
{
func
=
nullptr
;
bb
=
nullptr
;
inst
=
nullptr
;
frame_size
=
0
;
fcmp_cnt
=
0
;
offset_map
.
clear
();
}
...
...
include/codegen/Register.hpp
View file @
f40efe88
include/lightir/BasicBlock.hpp
View file @
f40efe88
...
...
@@ -20,8 +20,7 @@ class BasicBlock : public Value {
~
BasicBlock
()
override
;
static
BasicBlock
*
create
(
Module
*
m
,
const
std
::
string
&
name
,
Function
*
parent
)
{
auto
prefix
=
name
.
empty
()
?
""
:
"label_"
;
return
new
BasicBlock
(
m
,
prefix
+
name
,
parent
);
return
new
BasicBlock
(
m
,
name
,
parent
);
}
/****************api about cfg****************/
...
...
include/lightir/Instruction.hpp
View file @
f40efe88
...
...
@@ -214,6 +214,8 @@ public:
Value
*
get_condition
()
const
{
return
get_operand
(
0
);
}
void
replace_all_bb_match
(
BasicBlock
*
need_replace
,
BasicBlock
*
replace_to
);
std
::
string
print
()
override
;
};
...
...
@@ -251,8 +253,8 @@ class StoreInst : public Instruction {
public:
static
StoreInst
*
create_store
(
Value
*
val
,
Value
*
ptr
,
BasicBlock
*
bb
);
Value
*
get_
r
val
()
const
{
return
this
->
get_operand
(
0
);
}
Value
*
get_
lval
()
const
{
return
this
->
get_operand
(
1
);
}
Value
*
get_val
()
const
{
return
this
->
get_operand
(
0
);
}
Value
*
get_
ptr
()
const
{
return
this
->
get_operand
(
1
);
}
std
::
string
print
()
override
;
};
...
...
@@ -264,7 +266,7 @@ class LoadInst : public Instruction {
public:
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
();
}
std
::
string
print
()
override
;
...
...
include/passes/DeadCode.hpp
View file @
f40efe88
include/passes/Dominators.hpp
View file @
f40efe88
...
...
@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass {
void
run
()
override
;
// 获取基本块的直接支配节点
BasicBlock
*
get_idom
(
const
BasicBlock
*
bb
)
const
{
return
idom_
.
at
(
bb
);
}
const
std
::
set
<
BasicBlock
*>
&
get_dominance_frontier
(
const
BasicBlock
*
bb
)
{
BasicBlock
*
get_idom
(
BasicBlock
*
bb
)
const
{
return
idom_
.
at
(
bb
);
}
const
std
::
set
<
BasicBlock
*>
&
get_dominance_frontier
(
BasicBlock
*
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
);
}
...
...
@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass {
void
dump_dominator_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
)
&&
dom_tree_R_
.
at
(
bb1
)
>=
dom_tree_L_
.
at
(
bb2
);
}
...
...
@@ -54,33 +54,33 @@ class Dominators : public FunctionAnalysisPass {
void
create_dom_tree_succ
();
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
set_idom
(
const
BasicBlock
*
bb
,
BasicBlock
*
idom
)
{
idom_
[
bb
]
=
idom
;
}
void
set_dominance_frontier
(
const
BasicBlock
*
bb
,
std
::
set
<
BasicBlock
*>&
df
)
{
void
set_idom
(
BasicBlock
*
bb
,
BasicBlock
*
idom
)
{
idom_
[
bb
]
=
idom
;
}
void
set_dominance_frontier
(
BasicBlock
*
bb
,
std
::
set
<
BasicBlock
*>&
df
)
{
dom_frontier_
[
bb
].
clear
();
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
);
}
unsigned
int
get_
post_order
(
const
BasicBlock
*
bb
)
const
{
return
post_order_
.
at
(
bb
);
unsigned
int
get_
reversed_post_order
(
BasicBlock
*
bb
)
const
{
return
reversed_
post_order_
.
at
(
bb
);
}
// for debug
void
print_idom
()
const
;
void
print_dominance_frontier
();
std
::
vector
<
BasicBlock
*>
post_order_vec_
{};
// 逆后序
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
post_order_
{};
// 逆后序
std
::
map
<
const
BasicBlock
*
,
BasicBlock
*>
idom_
{};
// 直接支配
std
::
map
<
const
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_frontier_
{};
// 支配边界集合
std
::
map
<
const
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_tree_succ_blocks_
{};
// 支配树中的后继节点
std
::
vector
<
BasicBlock
*>
reversed_
post_order_vec_
{};
// 逆后序
std
::
map
<
BasicBlock
*
,
unsigned
int
>
reversed_post_order_
{};
// 逆后序索引
std
::
map
<
BasicBlock
*
,
BasicBlock
*>
idom_
{};
// 直接支配
std
::
map
<
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_frontier_
{};
// 支配边界集合
std
::
map
<
BasicBlock
*
,
std
::
set
<
BasicBlock
*>>
dom_tree_succ_blocks_
{};
// 支配树中的后继节点
// 支配树上的dfs序L,R
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
dom_tree_L_
;
std
::
map
<
const
BasicBlock
*
,
unsigned
int
>
dom_tree_R_
;
std
::
map
<
BasicBlock
*
,
unsigned
int
>
dom_tree_L_
;
std
::
map
<
BasicBlock
*
,
unsigned
int
>
dom_tree_R_
;
std
::
vector
<
BasicBlock
*>
dom_dfs_order_
;
std
::
vector
<
BasicBlock
*>
dom_post_order_
;
...
...
include/passes/FuncInfo.hpp
View file @
f40efe88
...
...
@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass {
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 存入的变量(全局/局部变量或函数参数)
static
Value
*
store_ptr
(
const
StoreInst
*
st
);
// 返回 LoadInst 加载的变量(全局/局部变量或函数参数)
static
Value
*
load_ptr
(
const
LoadInst
*
ld
);
// 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数)
std
::
unordered_set
<
Value
*>
get_stores
(
const
CallInst
*
call
);
// 返回 CallInst 代表的函数调用间接加载的变量(全局/局部变量或函数参数)
std
::
unordered_set
<
Value
*>
get_loads
(
const
CallInst
*
call
);
private:
// 函数存储的值
std
::
unordered_map
<
Function
*
,
UseMessage
>
stores
;
...
...
include/passes/LICM.hpp
View file @
f40efe88
...
...
@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass {
std
::
vector
<
Instruction
*>
collect_insts
(
Loop
*
loop
);
void
traverse_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 {
const
std
::
vector
<
Loop
*>&
get_sub_loops
()
{
return
sub_loops_
;
}
const
std
::
unordered_set
<
BasicBlock
*>&
get_latches
()
{
return
latches_
;
}
void
add_latch
(
BasicBlock
*
bb
)
{
latches_
.
insert
(
bb
);
}
std
::
string
safe_print
()
const
;
};
class
LoopDetection
:
public
FunctionAnalysisPass
{
...
...
lldb_formatters.py
View file @
f40efe88
...
...
@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
,
"BasicBlock"
,
"GlobalVariable"
,
"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
:
debugger
.
HandleCommand
(
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) {
}
}
else
{
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
())
{
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
;
if
(
is_int
||
is_float
)
{
tmp_ptr
=
builder
->
create_gep
(
var
,
{
val
});
...
...
src/cminusfc/main.cpp
View file @
f40efe88
...
...
@@ -23,30 +23,30 @@ struct Config {
std
::
filesystem
::
path
input_file
;
std
::
filesystem
::
path
output_file
;
bool
emitast
{
false
};
bool
emitasm
{
false
};
bool
emitllvm
{
false
};
bool
emitast
{
false
};
bool
emitasm
{
false
};
bool
emitllvm
{
false
};
// optization conifg
bool
mem2reg
{
false
};
bool
licm
{
false
};
bool
mem2reg
{
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
();
check
();
}
private:
int
argc
{
-
1
};
char
**
argv
{
nullptr
};
private:
int
argc
{
-
1
};
char
**
argv
{
nullptr
};
void
parse_cmd_line
();
void
check
();
// print helper infomation and exit
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
);
auto
syntax_tree
=
parse
(
config
.
input_file
.
c_str
());
...
...
@@ -55,7 +55,8 @@ int main(int argc, char **argv) {
if
(
config
.
emitast
)
{
// if emit ast (lab1), print ast and return
ASTPrinter
printer
;
ast
.
run_visitor
(
printer
);
}
else
{
}
else
{
Module
*
m
;
CminusfBuilder
builder
;
ast
.
run_visitor
(
builder
);
...
...
@@ -63,11 +64,12 @@ int main(int argc, char **argv) {
PassManager
PM
(
m
);
// optimization
if
(
config
.
mem2reg
)
{
if
(
config
.
mem2reg
)
{
PM
.
add_pass
<
DeadCode
>
(
true
);
PM
.
add_pass
<
Mem2Reg
>
();
PM
.
add_pass
<
DeadCode
>
(
false
);
}
if
(
config
.
licm
)
{
if
(
config
.
licm
)
{
PM
.
add_pass
<
LoopInvariantCodeMotion
>
();
PM
.
add_pass
<
DeadCode
>
(
false
);
}
...
...
@@ -79,7 +81,14 @@ int main(int argc, char **argv) {
output_stream
<<
"; ModuleID = 'cminus'
\n
"
;
output_stream
<<
"source_filename = "
<<
abs_path
<<
"
\n\n
"
;
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
.
run
();
output_stream
<<
codegen
.
print
();
...
...
@@ -96,27 +105,36 @@ void Config::parse_cmd_line() {
for
(
int
i
=
1
;
i
<
argc
;
++
i
)
{
if
(
argv
[
i
]
==
"-h"
s
||
argv
[
i
]
==
"--help"
s
)
{
print_help
();
}
else
if
(
argv
[
i
]
==
"-o"
s
)
{
}
else
if
(
argv
[
i
]
==
"-o"
s
)
{
if
(
output_file
.
empty
()
&&
i
+
1
<
argc
)
{
output_file
=
argv
[
i
+
1
];
i
+=
1
;
}
else
{
}
else
{
print_err
(
"bad output file"
);
}
}
else
if
(
argv
[
i
]
==
"-emit-ast"
s
)
{
}
else
if
(
argv
[
i
]
==
"-emit-ast"
s
)
{
emitast
=
true
;
}
else
if
(
argv
[
i
]
==
"-S"
s
)
{
}
else
if
(
argv
[
i
]
==
"-S"
s
)
{
emitasm
=
true
;
}
else
if
(
argv
[
i
]
==
"-emit-llvm"
s
)
{
}
else
if
(
argv
[
i
]
==
"-emit-llvm"
s
)
{
emitllvm
=
true
;
}
else
if
(
argv
[
i
]
==
"-mem2reg"
s
)
{
}
else
if
(
argv
[
i
]
==
"-mem2reg"
s
)
{
mem2reg
=
true
;
}
else
if
(
argv
[
i
]
==
"-licm"
s
)
{
}
else
if
(
argv
[
i
]
==
"-licm"
s
)
{
licm
=
true
;
}
else
{
}
else
{
if
(
input_file
.
empty
())
{
input_file
=
argv
[
i
];
}
else
{
}
else
{
string
err
=
"unrecognized command-line option
\'
"
s
+
argv
[
i
]
+
"
\'
"
s
;
print_err
(
err
);
...
...
@@ -143,11 +161,12 @@ void Config::check() {
}
if
(
output_file
.
empty
())
{
output_file
=
input_file
.
stem
();
}
if
(
emitllvm
)
{
output_file
.
replace_extension
(
".ll"
);
}
else
if
(
emitasm
)
{
output_file
.
replace_extension
(
".s"
);
}
else
if
(
emitasm
)
{
output_file
.
replace_extension
(
".s"
);
}
}
...
...
@@ -160,7 +179,7 @@ void Config::print_help() const {
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
;
exit
(
-
1
);
}
src/codegen/CodeGen.cpp
View file @
f40efe88
#include "CodeGen.hpp"
#include <cstring>
#include "ASMInstruction.hpp"
#include "BasicBlock.hpp"
#include "CodeGenUtil.hpp"
#include "Function.hpp"
#include "Instruction.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
;
// 为每个参数分配栈空间
for
(
auto
&
arg
:
context
.
func
->
get_args
())
{
for
(
auto
&
arg
:
context
.
func
->
get_args
())
{
auto
size
=
arg
->
get_type
()
->
get_size
();
offset
=
offset
+
size
;
offset
=
ALIGN
(
offset
+
size
,
size
)
;
context
.
offset_map
[
arg
]
=
-
static_cast
<
int
>
(
offset
);
}
// 为指令结果分配栈空间
for
(
auto
bb
:
context
.
func
->
get_basic_blocks
())
{
for
(
auto
instr
:
bb
->
get_instructions
())
{
// 每个非 void 的定值都分配栈空间
if
(
not
instr
->
is_void
())
{
for
(
auto
&
bb
:
context
.
func
->
get_basic_blocks
())
{
for
(
auto
&
instr
:
bb
->
get_instructions
())
{
if
(
not
instr
->
is_void
())
{
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
);
}
// alloca 的副作用:分配额外空间
if
(
instr
->
is_alloca
())
{
auto
*
alloca_inst
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
if
(
instr
->
is_alloca
())
{
auto
*
alloca_inst
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
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
);
}
void
CodeGen
::
copy_stmt
()
{
for
(
auto
succ
:
context
.
bb
->
get_succ_basic_blocks
())
{
for
(
auto
inst
:
succ
->
get_instructions
())
{
if
(
inst
->
is_phi
())
{
// 遍历后继块中 phi 的定值 bb
for
(
unsigned
i
=
1
;
i
<
inst
->
get_operands
().
size
();
i
+=
2
)
{
// phi 的定值 bb 是当前翻译块
if
(
inst
->
get_operand
(
i
)
==
context
.
bb
)
{
auto
*
lvalue
=
inst
->
get_operand
(
i
-
1
);
if
(
lvalue
->
get_type
()
->
is_float_type
())
{
void
CodeGen
::
copy_stmt
()
{
for
(
auto
&
succ
:
context
.
bb
->
get_succ_basic_blocks
())
{
for
(
auto
&
inst
:
succ
->
get_instructions
())
{
if
(
inst
->
is_phi
())
{
for
(
unsigned
i
=
1
;
i
<
inst
->
get_operands
().
size
();
i
+=
2
)
{
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
));
store_from_freg
(
inst
,
FReg
::
fa
(
0
));
}
else
{
}
else
{
load_to_greg
(
lvalue
,
Reg
::
a
(
0
));
store_from_greg
(
inst
,
Reg
::
a
(
0
));
}
break
;
}
// 如果没有找到当前翻译块,说明是 undef,无事可做
}
}
else
{
}
else
{
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
()
||
val
->
get_type
()
->
is_pointer_type
());
if
(
auto
*
constant
=
dynamic_cast
<
ConstantInt
*>
(
val
))
{
int32_t
val
=
constant
->
get_value
();
i
f
(
IS_IMM_12
(
val
))
{
append_inst
(
ADDI
WORD
,
{
reg
.
print
(),
"$zero"
,
std
::
to_string
(
val
)});
}
else
{
load_large_int32
(
val
,
reg
);
if
(
auto
*
constant
=
dynamic_cast
<
ConstantInt
*>
(
val
))
{
i
nt32_t
val1
=
constant
->
get_value
();
if
(
IS_IMM_12
(
val1
))
{
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
()});
}
else
{
}
else
{
load_from_stack_to_greg
(
val
,
reg
);
}
}
void
CodeGen
::
load_large_int32
(
int32_t
val
,
const
Reg
&
reg
)
{
int32_t
high_20
=
val
>>
12
;
// si20
void
CodeGen
::
load_large_int32
(
int32_t
val
,
const
Reg
&
reg
)
{
int32_t
high_20
=
val
>>
12
;
uint32_t
low_12
=
val
&
LOW_12_MASK
;
append_inst
(
LU12I_W
,
{
reg
.
print
(),
std
::
to_string
(
high_20
)});
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
);
load_large_int32
(
low_32
,
reg
);
auto
high_32
=
static_cast
<
int32_t
>
(
val
>>
32
);
int32_t
high_32_low_20
=
(
high_32
<<
12
)
>>
12
;
// si20
int32_t
high_32_high_12
=
high_32
>>
20
;
// si12
int32_t
high_32_low_20
=
(
high_32
<<
12
)
>>
12
;
int32_t
high_32_high_12
=
high_32
>>
20
;
append_inst
(
LU32I_D
,
{
reg
.
print
(),
std
::
to_string
(
high_32_low_20
)});
append_inst
(
LU52I_D
,
{
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_str
=
std
::
to_string
(
offset
);
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
type
->
is_int1_type
())
{
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
type
->
is_int1_type
())
{
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
});
}
else
{
// Pointer
}
else
{
append_inst
(
LOAD
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
}
else
{
}
else
{
load_large_int64
(
offset
,
reg
);
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"
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
LOAD
WORD
,
{
reg
.
print
(),
reg
.
print
(),
"0"
});
}
else
{
// Pointer
}
else
{
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_str
=
std
::
to_string
(
offset
);
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
type
->
is_int1_type
())
{
auto
*
type
=
val
->
get_type
();
if
(
IS_IMM_12
(
offset
))
{
if
(
type
->
is_int1_type
())
{
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
});
}
else
{
// Pointer
}
else
{
append_inst
(
STORE
DOUBLE
,
{
reg
.
print
(),
"$fp"
,
offset_str
});
}
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
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"
});
}
else
if
(
type
->
is_int32_type
())
{
}
else
if
(
type
->
is_int32_type
())
{
append_inst
(
STORE
WORD
,
{
reg
.
print
(),
addr
.
print
(),
"0"
});
}
else
{
// Pointer
}
else
{
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
());
if
(
auto
*
constant
=
dynamic_cast
<
ConstantFP
*>
(
val
))
{
float
val
=
constant
->
get_value
();
load_float_imm
(
val
,
freg
);
}
else
{
if
(
auto
*
constant
=
dynamic_cast
<
ConstantFP
*>
(
val
))
{
float
val1
=
constant
->
get_value
();
load_float_imm
(
val1
,
freg
);
}
else
{
auto
offset
=
context
.
offset_map
.
at
(
val
);
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
});
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
...
...
@@ -185,18 +229,24 @@ void CodeGen::load_to_freg(Value *val, const FReg &freg) {
}
}
void
CodeGen
::
load_float_imm
(
float
val
,
const
FReg
&
r
)
{
int32_t
bytes
=
*
reinterpret_cast
<
int32_t
*>
(
&
val
);
void
CodeGen
::
load_float_imm
(
float
val
,
const
FReg
&
r
)
{
int32_t
bytes
=
0
;
memcpy
(
&
bytes
,
&
val
,
sizeof
(
float
));
load_large_int32
(
bytes
,
Reg
::
t
(
8
));
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
);
if
(
IS_IMM_12
(
offset
))
{
if
(
IS_IMM_12
(
offset
))
{
auto
offset_str
=
std
::
to_string
(
offset
);
append_inst
(
FSTORE
SINGLE
,
{
r
.
print
(),
"$fp"
,
offset_str
});
}
else
{
}
else
{
auto
addr
=
Reg
::
t
(
8
);
load_large_int64
(
offset
,
addr
);
append_inst
(
ADD
DOUBLE
,
{
addr
.
print
(),
"$fp"
,
addr
.
print
()});
...
...
@@ -204,14 +254,18 @@ void CodeGen::store_from_freg(Value *val, const FReg &r) {
}
}
void
CodeGen
::
gen_prologue
()
{
if
(
IS_IMM_12
(
-
static_cast
<
int
>
(
context
.
frame_size
)))
{
void
CodeGen
::
gen_prologue
()
{
if
(
IS_IMM_12
(
-
static_cast
<
int
>
(
context
.
frame_size
)))
{
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $fp, $sp, -16"
);
append_inst
(
"addi.d $fp, $sp, 0"
);
append_inst
(
"addi.d $sp, $sp, "
+
std
::
to_string
(
-
static_cast
<
int
>
(
context
.
frame_size
)));
}
else
{
}
else
{
load_large_int64
(
context
.
frame_size
,
Reg
::
t
(
0
));
append_inst
(
"st.d $ra, $sp, -8"
);
append_inst
(
"st.d $fp, $sp, -16"
);
...
...
@@ -221,177 +275,405 @@ void CodeGen::gen_prologue() {
int
garg_cnt
=
0
;
int
farg_cnt
=
0
;
for
(
auto
arg
:
context
.
func
->
get_args
())
{
if
(
arg
->
get_type
()
->
is_float_type
())
{
for
(
auto
arg
:
context
.
func
->
get_args
())
{
if
(
arg
->
get_type
()
->
is_float_type
())
{
store_from_freg
(
arg
,
FReg
::
fa
(
farg_cnt
++
));
}
else
{
// int or pointer
}
else
{
store_from_greg
(
arg
,
Reg
::
a
(
garg_cnt
++
));
}
}
}
void
CodeGen
::
gen_epilogue
()
{
// TODO 根据你的理解设定函数的 epilogue
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_epilogue
()
{
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
()
{
// TODO 函数返回,思考如何处理返回值、寄存器备份,如何返回调用者地址
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_ret
()
{
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
()
{
auto
*
branchInst
=
static_cast
<
BranchInst
*>
(
context
.
inst
);
if
(
branchInst
->
is_cond_br
())
{
// TODO 补全条件跳转的情况
throw
not_implemented_error
{
__FUNCTION__
};
}
else
{
auto
*
branchbb
=
static_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
0
));
append_inst
(
"b "
+
label_name
(
branchbb
));
void
CodeGen
::
gen_br
()
{
auto
*
branchInst
=
dynamic_cast
<
BranchInst
*>
(
context
.
inst
);
if
(
branchInst
->
is_cond_br
())
{
load_to_greg
(
branchInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
auto
*
trueBB
=
dynamic_cast
<
BasicBlock
*>
(
branchInst
->
get_operand
(
1
));
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
(
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"
);
output
.
emplace_back
(
"add.w $t2, $t0, $t1"
);
break
;
case
Instruction
::
sub
:
append_inst
(
"sub.w $t2, $t0, $t1"
);
output
.
emplace_back
(
"sub.w $t2, $t0, $t1"
);
break
;
case
Instruction
::
mul
:
append_inst
(
"mul.w $t2, $t0, $t1"
);
output
.
emplace_back
(
"mul.w $t2, $t0, $t1"
);
break
;
case
Instruction
::
sdiv
:
append_inst
(
"div.w $t2, $t0, $t1"
);
output
.
emplace_back
(
"div.w $t2, $t0, $t1"
);
break
;
default:
assert
(
false
);
}
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
()
{
// TODO 浮点类型的二元指令
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_float_binary
()
{
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
()
{
/* 我们已经为 alloca 的内容分配空间,在此我们还需保存 alloca
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针
*/
// TODO 将 alloca 出空间的起始地址保存在栈帧上
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_alloca
()
{
auto
*
allocaInst
=
dynamic_cast
<
AllocaInst
*>
(
context
.
inst
);
auto
offset
=
context
.
offset_map
[
allocaInst
];
auto
trueOffset
=
offset
-
static_cast
<
int
>
(
allocaInst
->
get_alloca_type
()
->
get_size
());
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
()
{
auto
*
ptr
=
context
.
inst
->
get_operand
(
0
);
auto
*
type
=
context
.
inst
->
get_type
();
void
CodeGen
::
gen_load
()
{
auto
*
ptr
=
context
.
inst
->
get_operand
(
0
);
auto
*
type
=
context
.
inst
->
get_type
();
load_to_greg
(
ptr
,
Reg
::
t
(
0
));
if
(
type
->
is_float_type
())
{
if
(
type
->
is_float_type
())
{
append_inst
(
"fld.s $ft0, $t0, 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
()
{
// TODO 翻译 store 指令
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_store
()
{
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
()
{
// TODO 处理各种整数比较的情况
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_icmp
()
{
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
()
{
// TODO 处理各种浮点数比较的情况
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_fcmp
()
{
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
()
{
// TODO 将窄位宽的整数数据进行零扩展
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_zext
()
{
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
()
{
// TODO 函数调用,注意我们只需要通过寄存器传递参数,即不需考虑栈上传参的情况
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_call
()
{
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
));
}
}
/*
* %op = getelementptr [10 x i32], [10 x i32]* %op, i32 0, i32 %op
* %op = getelementptr i32, i32* %op, i32 %op
*
* Memory layout
* - ^
* +-----------+ | Smaller address
* | arg ptr |---+ |
* +-----------+ | |
* | | | |
* +-----------+ / |
* | |<-- |
* | | \ |
* | | | |
* | Array | | |
* | | | |
* | | | |
* | | | |
* +-----------+ | |
* | Pointer |---+ |
* +-----------+ |
* | | |
* +-----------+ |
* | | |
* +-----------+ |
* | | |
* +-----------+ | Larger address
* +
*/
void
CodeGen
::
gen_gep
()
{
// TODO 计算内存地址
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_gep
()
{
auto
*
getElementPtrInst
=
dynamic_cast
<
GetElementPtrInst
*>
(
context
.
inst
);
unsigned
int
num
=
getElementPtrInst
->
get_num_operand
();
load_to_greg
(
getElementPtrInst
->
get_operand
(
0
),
Reg
::
t
(
0
));
load_to_greg
(
getElementPtrInst
->
get_operand
(
num
-
1
),
Reg
::
t
(
1
));
auto
elementType
=
getElementPtrInst
->
get_element_type
();
append_inst
(
"addi.d $t2, $zero, 4"
);
if
(
elementType
->
is_float_type
()
||
elementType
->
is_int32_type
())
{
append_inst
(
"mul.d $t1, $t1, $t2"
);
}
else
{
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
));
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"
);
}
void
CodeGen
::
gen_sitofp
()
{
// TODO 整数转向浮点数
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_sitofp
()
{
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
()
{
// TODO 浮点数转向整数,注意向下取整(round to zero)
throw
not_implemented_error
{
__FUNCTION__
};
void
CodeGen
::
gen_fptosi
()
{
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
();
/* 使用 GNU 伪指令为全局变量分配空间
* 你可以使用 `la.local` 指令将标签 (全局变量) 的地址载入寄存器中, 比如
* 要将 `a` 的地址载入 $t0, 只需要 `la.local $t0, a`
*/
if
(
!
m
->
get_global_variable
().
empty
())
{
if
(
!
m
->
get_global_variable
().
empty
())
{
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
(
".section"
,
{
".bss"
,
"
\"
aw
\"
"
,
"@nobits"
},
ASMInstruction
::
Attribute
);
for
(
auto
global
:
m
->
get_global_variable
())
{
auto
size
=
global
->
get_type
()
->
get_pointer_element_type
()
->
get_size
();
for
(
auto
global
:
m
->
get_global_variable
())
{
auto
size
=
global
->
get_type
()
->
get_pointer_element_type
()
->
get_size
();
append_inst
(
".globl"
,
{
global
->
get_name
()},
ASMInstruction
::
Attribute
);
append_inst
(
".type"
,
{
global
->
get_name
(),
"@object"
},
...
...
@@ -404,33 +686,32 @@ void CodeGen::run() {
}
}
// 函数代码段
output
.
emplace_back
(
".text"
,
ASMInstruction
::
Attribute
);
for
(
auto
func
:
m
->
get_functions
())
{
if
(
not
func
->
is_declaration
())
{
// 更新 context
for
(
auto
func
:
m
->
get_functions
())
{
if
(
not
func
->
is_declaration
())
{
context
.
clear
();
context
.
func
=
func
;
// 函数信息
append_inst
(
".globl"
,
{
func
->
get_name
()},
ASMInstruction
::
Attribute
);
append_inst
(
".type"
,
{
func
->
get_name
(),
"@function"
},
ASMInstruction
::
Attribute
);
append_inst
(
func
->
get_name
(),
ASMInstruction
::
Label
);
// 分配函数栈帧
allocate
();
// 生成 prologue
gen_prologue
();
for
(
auto
bb
:
func
->
get_basic_blocks
())
{
for
(
auto
&
bb
:
func
->
get_basic_blocks
())
{
context
.
bb
=
bb
;
append_inst
(
label_name
(
context
.
bb
),
ASMInstruction
::
Label
);
for
(
auto
instr
:
bb
->
get_instructions
())
{
// For debug
append_inst
(
context
.
bb
->
get_name
(
),
ASMInstruction
::
Label
);
for
(
auto
&
instr
:
bb
->
get_instructions
())
{
append_inst
(
instr
->
print
(),
ASMInstruction
::
Comment
);
context
.
inst
=
instr
;
// 更新 context
switch
(
instr
->
get_instr_type
())
{
context
.
inst
=
instr
;
switch
(
instr
->
get_instr_type
())
{
case
Instruction
::
ret
:
gen_ret
();
break
;
...
...
@@ -451,10 +732,6 @@ void CodeGen::run() {
gen_float_binary
();
break
;
case
Instruction
::
alloca
:
/* 对于 alloca 指令,我们已经为 alloca
* 的内容分配空间,在此我们还需保存 alloca
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针
*/
gen_alloca
();
break
;
case
Instruction
::
load
:
...
...
@@ -480,10 +757,6 @@ void CodeGen::run() {
gen_fcmp
();
break
;
case
Instruction
::
phi
:
/* for phi, just convert to a series of
* copy-stmts */
/* we can collect all phi and deal them at
* the end */
break
;
case
Instruction
::
call
:
gen_call
();
...
...
@@ -503,15 +776,16 @@ void CodeGen::run() {
}
}
}
// 生成 epilogue
gen_epilogue
();
}
}
}
std
::
string
CodeGen
::
print
()
const
{
std
::
string
CodeGen
::
print
()
const
{
std
::
string
result
;
for
(
const
auto
&
inst
:
output
)
{
for
(
const
auto
&
inst
:
output
)
{
result
+=
inst
.
format
();
}
return
result
;
...
...
src/io/io.c
View file @
f40efe88
#include <stdio.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
;
scanf
(
"%d"
,
&
a
);
gettimeofday
(
&
time_start
,
NULL
);
end_set
=
0
;
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
()
{
printf
(
"negative index exception
\n
"
);
exit
(
0
);
__attribute
((
destructor
))
void
after_main
(
void
)
{
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
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
...
...
@@ -12,13 +12,13 @@
BasicBlock
::
BasicBlock
(
const
Module
*
m
,
const
std
::
string
&
name
=
""
,
Function
*
parent
=
nullptr
)
:
Value
(
m
->
get_label_type
(),
parent
==
nullptr
?
GLOBAL_BASICBLOCK_NAMES_
.
get_name
(
name
)
:
parent
->
names4blocks_
.
get_name
(
name
))
,
parent_
(
parent
)
{
parent
==
nullptr
?
GLOBAL_BASICBLOCK_NAMES_
.
get_name
(
name
)
:
parent
->
names4blocks_
.
get_name
(
name
))
,
parent_
(
parent
)
{
assert
(
parent
&&
"currently parent should not be nullptr"
);
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
);
}
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
()
&&
"Trying to get terminator from an bb which is not terminated"
);
return
instr_list_
.
back
();
}
void
BasicBlock
::
add_instruction
(
Instruction
*
instr
)
{
void
BasicBlock
::
add_instruction
(
Instruction
*
instr
)
{
if
(
instr
->
is_alloca
()
||
instr
->
is_phi
())
{
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
);
return
;
}
...
...
@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const
return
parent_
->
get_entry_block
();
}
Names
GLOBAL_BASICBLOCK_NAMES_
{
"label"
,
"_"
};
\ No newline at end of file
Names
GLOBAL_BASICBLOCK_NAMES_
{
"label"
,
"_"
};
\ No newline at end of file
src/lightir/Function.cpp
View file @
f40efe88
...
...
@@ -7,17 +7,8 @@
#include <unordered_set>
#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
)
:
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();
parent
->
add_function
(
this
);
// build args
...
...
src/lightir/IRprinter.cpp
View file @
f40efe88
...
...
@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const
}
else
{
if
(
auto
fty
=
dynamic_cast
<
FunctionType
*>
(
ty
))
if
(
auto
fty
=
dynamic_cast
<
FunctionType
*>
(
op0
->
get_type
()
))
{
auto
ty3
=
fty
->
get_return_type
();
if
(
ty3
==
nullptr
)
...
...
src/lightir/Instruction.cpp
View file @
f40efe88
...
...
@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *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
)
:
Instruction
(
bb
->
get_module
()
->
get_void_type
(),
ret
,
""
,
bb
)
{
if
(
val
==
nullptr
)
{
...
...
@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str
PhiInst
::
PhiInst
(
Type
*
ty
,
const
std
::
vector
<
Value
*>&
vals
,
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"
);
for
(
unsigned
i
=
0
;
i
<
vals
.
size
();
i
++
)
{
assert
(
ty
==
vals
[
i
]
->
get_type
()
&&
"Bad type for phi"
);
add_operand
(
vals
[
i
]);
add_operand
(
val_bbs
[
i
]);
}
this
->
set_parent
(
bb
);
}
PhiInst
*
PhiInst
::
create_phi
(
Type
*
ty
,
BasicBlock
*
bb
,
...
...
src/lightir/Module.cpp
View file @
f40efe88
...
...
@@ -27,48 +27,48 @@ Module::~Module()
for
(
auto
i
:
global_list_
)
delete
i
;
}
Type
*
Module
::
get_void_type
()
const
{
return
void_ty_
;
}
Type
*
Module
::
get_label_type
()
const
{
return
label_ty_
;
}
IntegerType
*
Module
::
get_int1_type
()
const
{
return
int1_ty_
;
}
IntegerType
*
Module
::
get_int32_type
()
const
{
return
int32_ty_
;
}
FloatType
*
Module
::
get_float_type
()
const
{
return
float32_ty_
;
}
PointerType
*
Module
::
get_int32_ptr_type
()
{
Type
*
Module
::
get_void_type
()
const
{
return
void_ty_
;
}
Type
*
Module
::
get_label_type
()
const
{
return
label_ty_
;
}
IntegerType
*
Module
::
get_int1_type
()
const
{
return
int1_ty_
;
}
IntegerType
*
Module
::
get_int32_type
()
const
{
return
int32_ty_
;
}
FloatType
*
Module
::
get_float_type
()
const
{
return
float32_ty_
;
}
PointerType
*
Module
::
get_int32_ptr_type
()
{
return
get_pointer_type
(
int32_ty_
);
}
PointerType
*
Module
::
get_float_ptr_type
()
{
PointerType
*
Module
::
get_float_ptr_type
()
{
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
())
{
pointer_map_
[
contained
]
=
new
PointerType
(
contained
);
}
return
pointer_map_
[
contained
];
}
ArrayType
*
Module
::
get_array_type
(
Type
*
contained
,
unsigned
num_elements
)
{
if
(
array_map_
.
find
({
contained
,
num_elements
})
==
array_map_
.
end
())
{
ArrayType
*
Module
::
get_array_type
(
Type
*
contained
,
unsigned
num_elements
)
{
if
(
array_map_
.
find
({
contained
,
num_elements
})
==
array_map_
.
end
())
{
array_map_
[{
contained
,
num_elements
}]
=
new
ArrayType
(
contained
,
num_elements
);
}
return
array_map_
[{
contained
,
num_elements
}];
}
FunctionType
*
Module
::
get_function_type
(
Type
*
retty
,
std
::
vector
<
Type
*>
&
args
)
{
if
(
not
function_map_
.
count
({
retty
,
args
}))
{
FunctionType
*
Module
::
get_function_type
(
Type
*
retty
,
std
::
vector
<
Type
*>&
args
)
{
if
(
not
function_map_
.
count
({
retty
,
args
}))
{
function_map_
[{
retty
,
args
}]
=
new
FunctionType
(
retty
,
args
);
}
return
function_map_
[{
retty
,
args
}];
}
void
Module
::
add_function
(
Function
*
f
)
{
function_list_
.
push_back
(
f
);
}
std
::
list
<
Function
*>
&
Module
::
get_functions
()
{
return
function_list_
;
}
void
Module
::
add_global_variable
(
GlobalVariable
*
g
)
{
void
Module
::
add_function
(
Function
*
f
)
{
function_list_
.
push_back
(
f
);
}
std
::
list
<
Function
*>
&
Module
::
get_functions
()
{
return
function_list_
;
}
void
Module
::
add_global_variable
(
GlobalVariable
*
g
)
{
global_list_
.
push_back
(
g
);
}
std
::
list
<
GlobalVariable
*>
&
Module
::
get_global_variable
()
{
std
::
list
<
GlobalVariable
*>
&
Module
::
get_global_variable
()
{
return
global_list_
;
}
...
...
src/lightir/User.cpp
View file @
f40efe88
src/passes/DeadCode.cpp
View file @
f40efe88
...
...
@@ -15,6 +15,7 @@ void DeadCode::run() {
do
{
changed
=
false
;
for
(
auto
func
:
m_
->
get_functions
())
{
if
(
func
->
is_declaration
())
continue
;
if
(
remove_bb_
)
changed
|=
clear_basic_blocks
(
func
);
mark
(
func
);
changed
|=
sweep
(
func
);
...
...
src/passes/Dominators.cpp
View file @
f40efe88
...
...
@@ -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
(
get_
post_order
(
b1
)
<
get
_post_order
(
b2
))
{
while
(
get_
reversed_post_order
(
b1
)
>
get_reversed
_post_order
(
b2
))
{
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
);
}
}
...
...
@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
void
Dominators
::
create_reverse_post_order
()
{
std
::
set
<
BasicBlock
*>
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) {
dfs
(
succ
,
visited
);
}
}
post_order_vec_
.
push_back
(
bb
);
post_order_
.
insert
({
bb
,
post_order_
.
size
()});
reversed_
post_order_vec_
.
push_back
(
bb
);
reversed_post_order_
.
insert
({
bb
,
reversed_
post_order_
.
size
()});
}
/**
...
...
@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
*/
void
Dominators
::
create_idom
()
{
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
post_order_ map<BasicBlock*, unsigned int>, 每个基本块在
post_order_vec_ 中的索引
//
reversed_
post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_
post_order_vec_ 中的索引
// 可能有用的函数
// intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先
// 需要填写
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者)
// 代表基本块的直接支配者是否已经确定, 不会在迭代中改变 (默认初始化为 false)
bool
*
already_determined
=
new
bool
[
post_order_vec_
.
size
()]{};
int
bb_count
=
static_cast
<
int
>
(
reversed_post_order_vec_
.
size
());
int
bb_count
=
static_cast
<
int
>
(
post_order_vec_
.
size
());
for
(
int
i
=
0
;
i
<
bb_count
;
i
++
)
{
auto
bb
=
post_order_vec_
[
i
];
// TODO 填写可以直接确定直接支配者, 无需参与迭代的基本块的 idom_ 和 already_determined
throw
"Unimplemented create_idom"
;
}
idom_
[
reversed_post_order_vec_
[
0
]]
=
reversed_post_order_vec_
[
0
];
bool
changed
;
do
{
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
=
post_order_vec_
[
i
];
auto
bb
=
reversed_post_order_vec_
[
i
];
// TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化)
throw
"Unimplemented create_idom"
;
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
)
;
}
}
while
(
changed
);
delete
[]
already_determined
;
}
/**
...
...
@@ -154,19 +150,19 @@ void Dominators::create_idom() {
*/
void
Dominators
::
create_dominance_frontier
()
{
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
post_order_ map<BasicBlock*, unsigned int>, 每个基本块在
post_order_vec_ 中的索引
//
reversed_
post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
//
reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_
post_order_vec_ 中的索引
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// (或者 idom_[a] = a 代表 a 没有直接支配者)
// 需要填写
// 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
++
)
{
auto
bb
=
post_order_vec_
[
i
];
auto
bb
=
reversed_
post_order_vec_
[
i
];
// TODO 计算 bb 的支配边界集合, 填入 dom_frontier_
throw
"Unimplemented create_dominance_frontier"
;
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
)
;
}
}
...
...
@@ -183,7 +179,8 @@ void Dominators::create_dom_tree_succ() {
// dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点
// 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
...
...
@@ -174,6 +174,21 @@ std::unordered_set<Value*> FuncInfo::get_stores(const CallInst* call)
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
{
for
(
auto
it
:
use_libs
)
...
...
src/passes/LICM.cpp
View file @
f40efe88
...
...
@@ -67,21 +67,6 @@ std::vector<Instruction*> LoopInvariantCodeMotion::collect_insts(Loop* loop)
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
{
UNKNOWN
,
VARIANT
,
INVARIANT
...
...
@@ -99,19 +84,9 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
// 循环中的所有指令
std
::
vector
<
Instruction
*>
instructions
=
collect_insts
(
loop
);
int
insts_count
=
static_cast
<
int
>
(
instructions
.
size
());
// 循环的所有基本块
std
::
unordered_set
<
BasicBlock
*>
bbs
;
for
(
auto
i
:
loop
->
get_blocks
())
bbs
.
emplace
(
i
);
// val 是否在循环内定义,可以当成函数进行调用
auto
is_val_in_loop
=
[
&
bbs
](
Value
*
val
)
->
bool
{
auto
inst
=
dynamic_cast
<
Instruction
*>
(
val
);
if
(
inst
==
nullptr
)
return
true
;
return
bbs
.
count
(
inst
->
get_parent
());
};
// inst_type[i] 代表 instructions[i] 是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std
::
vector
<
InstructionType
>
inst_type
;
inst_type
.
resize
(
insts_count
);
// Value* 在 map 内说明它是循环内的指令,InstructionType 指示它是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std
::
unordered_map
<
Value
*
,
InstructionType
>
inst_type
;
for
(
auto
i
:
instructions
)
inst_type
[
i
]
=
UNKNOWN
;
// 遍历后是不是还有指令不知道 InstructionType
bool
have_inst_can_not_decide
;
...
...
@@ -123,10 +98,10 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
for
(
int
i
=
0
;
i
<
insts_count
;
i
++
)
{
Instruction
*
inst
=
instructions
[
i
];
InstructionType
type
=
inst_type
[
i
];
InstructionType
type
=
inst_type
[
inst
];
if
(
type
!=
UNKNOWN
)
continue
;
// 可能有用的函数
// FuncInfo::load_ptr
// FuncInfo::load_ptr, FuncInfo::get_stores, FuncInfo::use_io
// TODO: 识别循环不变式指令
// - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT
...
...
@@ -134,6 +109,10 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
// - 如果指令有 VARIANT 操作数,标记为 VARIANT
// - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
// - 否则设置 have_inst_can_not_decide
// TODO: 外提循环不变的非纯函数调用
// 注意: 你不应该外提使用了 io 的函数调用
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
}
...
...
@@ -152,20 +131,26 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
for
(
auto
phi
:
loop
->
get_header
()
->
get_instructions
())
{
if
(
phi
->
get_instr_type
()
!=
Instruction
::
phi
)
break
;
// 可能有用的函数
// PhiInst::create_phi
// TODO: 分裂 phi 指令
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
}
// 可能有用的函数
// BranchInst::replace_all_bb_match
// TODO: 维护 bb, header, 与 header 前驱块的基本块关系
throw
std
::
runtime_error
(
"Lab4: 你有一个TODO需要完成!"
);
bb
->
add_instruction
(
BranchInst
::
create_br
(
header
,
bb
)
);
BranchInst
::
create_br
(
header
,
bb
);
// 若你想维护 LoopDetection 在 LICM 后保持正确
// auto loop2 = loop->get_parent();
// while (loop2 != nullptr)
// {
// loop2->get_parent()
->add_block(bb);
// loop2
->add_block(bb);
// loop2 = loop2->get_parent();
// }
}
...
...
@@ -177,8 +162,12 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
auto
terminator
=
preheader
->
get_instructions
().
back
();
preheader
->
get_instructions
().
pop_back
();
// 可以使用 Function::check_for_block_relation_error 检查基本块间的关系是否正确维护
// TODO: 外提循环不变指令
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() {
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 发现循环及其子循环
* @param bb 循环的header块
...
...
@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
// 5. 建立正确的循环嵌套关系
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
())
{
// 当工作表非空时继续处理
auto
bb2
=
work_list
.
back
();
work_list
.
pop_back
();
already_in_work_list
.
erase
(
bb2
);
// TODO-1: 处理未分配给任何循环的节点
if
(
bb_to_loop_
.
find
(
bb2
)
==
bb_to_loop_
.
end
())
{
...
...
src/passes/Mem2Reg.cpp
View file @
f40efe88
...
...
@@ -4,11 +4,12 @@
#include "Value.hpp"
//
l_val 是否是非数组 alloca 变量
static
bool
is_not_array_alloca
(
Value
*
l_val
)
//
ptr 是否是非数组 alloca 变量(是则转换为 AllocaInst)
static
AllocaInst
*
is_not_array_alloca
(
Value
*
ptr
)
{
auto
alloca
=
dynamic_cast
<
AllocaInst
*>
(
l_val
);
return
alloca
!=
nullptr
&&
!
alloca
->
get_alloca_type
()
->
is_array_type
();
auto
alloca
=
dynamic_cast
<
AllocaInst
*>
(
ptr
);
if
(
alloca
!=
nullptr
&&
!
alloca
->
get_alloca_type
()
->
is_array_type
())
return
alloca
;
return
nullptr
;
}
/**
...
...
@@ -43,7 +44,7 @@ void Mem2Reg::run() {
generate_phi
();
// 确保每个局部变量的栈都有初始值
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
());
}
...
...
@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() {
if
(
instr
->
is_store
())
{
// store i32 a, i32 *b
// a is r_val, b is l_val
auto
l_val
=
dynamic_cast
<
StoreInst
*>
(
instr
)
->
get_lval
();
if
(
is_not_array_alloca
(
l_val
))
{
auto
lalloca
=
dynamic_cast
<
AllocaInst
*>
(
instr
);
auto
l_val
=
dynamic_cast
<
StoreInst
*>
(
instr
)
->
get_ptr
();
if
(
auto
lalloca
=
is_not_array_alloca
(
l_val
))
{
if
(
!
not_array_allocas
.
count
(
lalloca
))
{
not_array_allocas
.
insert
(
lalloca
);
allocas_
.
emplace_back
(
lalloca
);
}
allocas_stored_bbs
[
lalloca
].
emplace_back
(
bb
);
}
}
...
...
@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() {
bb_dominance_frontier_bb
);
phi_to_alloca_
.
emplace
(
phi
,
var
);
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
);
bb_has_var_phi
.
emplace
(
bb_dominance_frontier_bb
,
var
);
}
...
...
@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) {
// 可能用到的数据结构
// list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历
// map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空
// map<PhiInst *, AllocaInst*>
; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>>
; 在某个基本块的 Phi
// map<PhiInst *, AllocaInst*> phi_to_alloca_
; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>> bb_to_phi_
; 在某个基本块的 Phi
// 可能用到的函数
// Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a
// BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令
// StoreInst / LoadInst get_ptr 这些 Inst 所操作的变量
// is_not_array_alloca(Value* ptr) 一个变量是不是 Mem2Reg 所关心的非数组局部变量
// TODO
// 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值)
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令
(注意: 并非所有 load/store/alloca 都是 Mem2Reg 需要处理的)
// - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶)
// - 步骤四: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤五:为所有后继块的 phi 添加参数
// 步骤六:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤七:pop 出所有局部变量的最新值
// 步骤八:删除需要删除的冗余指令
// - 步骤四: 将 phi 指令的所有使用替换为其对应的局部变量的最新值
// - 步骤五: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤六:为所有后继块的 phi 添加参数
// 步骤七:对 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
(
"3-codegen/warmup"
)
\ No newline at end of file
# add_subdirectory("2-ir-gen/warmup")
# add_subdirectory("3-codegen/warmup")
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