Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
2
2022fall-Compiler_CMinus
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
6
Merge Requests
6
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李晓奇
2022fall-Compiler_CMinus
Commits
83f09476
You need to sign in or sign up before continuing.
Commit
83f09476
authored
Jan 28, 2023
by
lxq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
should pass the functional test
parent
33502fa9
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
224 additions
and
188 deletions
+224
-188
include/codegen.hpp
include/codegen.hpp
+20
-15
src/cminusfc/cminusfc.cpp
src/cminusfc/cminusfc.cpp
+19
-10
src/codegen/codegen.cpp
src/codegen/codegen.cpp
+163
-152
tests/5-bonus/test_time.py
tests/5-bonus/test_time.py
+22
-11
No files found.
include/codegen.hpp
View file @
83f09476
...
...
@@ -43,18 +43,17 @@ class CodeGen {
void
IR2assem
(
GetElementPtrInst
*
);
void
IR2assem
(
CallInst
*
);
void
IR2assem
(
BranchInst
*
);
void
IR2assem
(
BinaryInst
*
);
void
IR2assem
(
FpToSiInst
*
);
void
IR2assem
(
SiToFpInst
*
);
// The Instructions below will do nothing
void
IR2assem
(
AllocaInst
*
)
{}
// integration with BranchInst
void
IR2assem
(
CmpInst
*
)
{}
void
IR2assem
(
FCmpInst
*
)
{}
void
IR2assem
(
ZextInst
*
)
{}
void
IR2assem
(
BinaryInst
*
);
void
IR2assem
(
PhiInst
*
)
{}
void
IR2assem
(
FCmpInst
*
)
{}
void
IR2assem
(
FpToSiInst
*
)
{}
void
IR2assem
(
SiToFpInst
*
)
{}
void
stackMemAlloc
();
void
stackMemDealloc
();
...
...
@@ -63,7 +62,7 @@ class CodeGen {
// - for global variables and pointers from alloca and GEP, read through
// address
// only use register a_id and t_
void
value2reg
(
Value
*
,
int
id
=
0
,
bool
is_float
=
false
);
void
value2reg
(
Value
*
,
int
id
=
0
);
// load the content in ptr to specified register.
// only use register a_id and t_
void
ptrContent2reg
(
Value
*
,
int
id
=
0
);
...
...
@@ -92,21 +91,27 @@ class CodeGen {
}
}
void
back2stack
(
Instruction
*
instr
,
string
reg
=
"$a0"
)
{
// assert the value needed to store back is in $a0 or $f0, according to the
// value type
void
back2stack
(
Instruction
*
instr
)
{
// std::cerr << instr->print() << std::endl;
string
suff
=
suffix
(
typeLen
(
instr
->
get_type
()));
auto
type
=
instr
->
get_type
();
string
instr_ir
=
type
->
is_float_type
()
?
"fst"
:
"st"
;
string
suff
=
suffix
(
type
);
string
reg
=
type
->
is_float_type
()
?
"$fa0"
:
"$a0"
;
string
addr
=
"$fp, -"
+
std
::
to_string
(
off
[
instr
]);
output
.
push_back
(
"st"
+
suff
+
" "
+
reg
+
"
"
+
addr
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
",
"
+
addr
);
}
string
suffix
(
int
len
)
{
string
suffix
(
Type
*
type
)
{
int
len
=
typeLen
(
type
);
switch
(
len
)
{
case
1
:
return
".b"
;
case
2
:
return
".h"
;
case
4
:
return
".w"
;
return
type
->
is_float_type
()
?
".s"
:
".w"
;
case
8
:
return
".d"
;
}
...
...
@@ -116,16 +121,16 @@ class CodeGen {
bool
no_stack_alloca
(
Instruction
*
instr
)
{
if
(
instr
->
is_void
())
return
true
;
if
(
instr
->
is_cmp
()
or
instr
->
is_zext
())
if
(
instr
->
is_
fcmp
()
or
instr
->
is_
cmp
()
or
instr
->
is_zext
())
return
true
;
return
false
;
}
std
::
map
<
Value
*
,
unsigned
int
>
off
;
//
to $fp
std
::
map
<
Value
*
,
unsigned
int
>
off
;
// stack offset
to $fp
std
::
map
<
Function
*
,
std
::
map
<
int
,
int
>>
func_arg_off
;
// to $sp
std
::
map
<
Function
*
,
int
>
func_arg_N
;
unsigned
int
stackN
;
std
::
map
<
Function
*
,
int
>
func_arg_N
;
// total space for args
unsigned
int
stackN
;
// function local vars and so on
Function
*
cur_func
;
...
...
src/cminusfc/cminusfc.cpp
View file @
83f09476
...
...
@@ -17,13 +17,16 @@
using
namespace
std
::
literals
::
string_literals
;
void
print_help
(
std
::
string
exe_name
)
{
void
print_help
(
std
::
string
exe_name
)
{
std
::
cout
<<
"Usage: "
<<
exe_name
<<
" [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] [-mem2reg] [-gvn] [-dump-json] <input-file>"
<<
" [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] "
"[-mem2reg] [-gvn] [-dump-json] <input-file>"
<<
std
::
endl
;
}
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
std
::
string
target_path
;
std
::
string
input_path
;
...
...
@@ -36,9 +39,11 @@ int main(int argc, char **argv) {
if
(
argv
[
i
]
==
"-h"
s
||
argv
[
i
]
==
"--help"
s
)
{
print_help
(
argv
[
0
]);
return
0
;
}
else
if
(
argv
[
i
]
==
"-o"
s
)
{
}
else
if
(
argv
[
i
]
==
"-o"
s
||
argv
[
i
]
==
"-S"
s
)
{
if
(
target_path
.
empty
()
&&
i
+
1
<
argc
)
{
target_path
=
argv
[
i
+
1
];
if
(
target_path
.
rfind
(
"."
)
!=
std
::
string
::
npos
)
target_path
=
target_path
.
substr
(
0
,
target_path
.
rfind
(
"."
));
i
+=
1
;
}
else
{
print_help
(
argv
[
0
]);
...
...
@@ -71,12 +76,13 @@ int main(int argc, char **argv) {
if
(
target_path
.
empty
())
{
auto
pos
=
input_path
.
rfind
(
'.'
);
if
(
pos
==
std
::
string
::
npos
)
{
std
::
cerr
<<
argv
[
0
]
<<
": input file "
<<
input_path
<<
" has unknown filetype!"
<<
std
::
endl
;
std
::
cerr
<<
argv
[
0
]
<<
": input file "
<<
input_path
<<
" has unknown filetype!"
<<
std
::
endl
;
return
-
1
;
}
else
{
// if (input_path.substr(pos) != ".cminus") {
// std::cerr << argv[0] << ": input file " << input_path << "
has unknown filetype!" << std::endl;
// return -1;
// std::cerr << argv[0] << ": input file " << input_path << "
//
has unknown filetype!" << std::endl;
return -1;
// }
target_path
=
input_path
.
substr
(
0
,
pos
);
}
...
...
@@ -89,7 +95,8 @@ int main(int argc, char **argv) {
a
.
run_visitor
(
builder
);
}
catch
(
std
::
exception
e
)
{
std
::
cout
<<
"Exception catched:
\n\t
"
<<
e
.
what
()
<<
std
::
endl
;
std
::
cout
<<
"Already generated IR code:
\n
"
<<
builder
.
getModule
()
->
print
();
std
::
cout
<<
"Already generated IR code:
\n
"
<<
builder
.
getModule
()
->
print
();
return
-
1
;
}
...
...
@@ -104,7 +111,8 @@ int main(int argc, char **argv) {
if
(
gvn
)
{
PM
.
add_pass
<
DeadCode
>
(
false
);
// remove some undef
PM
.
add_pass
<
GVN
>
(
emit
,
dump_json
);
PM
.
add_pass
<
DeadCode
>
(
false
);
// delete unused instructions created by GVN
PM
.
add_pass
<
DeadCode
>
(
false
);
// delete unused instructions created by GVN
}
PM
.
run
();
...
...
@@ -132,7 +140,8 @@ int main(int argc, char **argv) {
lib_path
.
erase
(
lib_path
.
rfind
(
'/'
));
else
lib_path
.
clear
();
auto
cmd_str
=
"clang -O0 -w -no-pie "
s
+
target_path
+
".ll -o "
+
target_path
+
lib_path
+
" -lcminus_io"
;
auto
cmd_str
=
"clang -O0 -w -no-pie "
s
+
target_path
+
".ll -o "
+
target_path
+
lib_path
+
" -lcminus_io"
;
int
re_code0
=
std
::
system
(
cmd_str
.
c_str
());
cmd_str
=
"rm "
s
+
target_path
+
".ll"
;
int
re_code1
=
std
::
system
(
cmd_str
.
c_str
());
...
...
src/codegen/codegen.cpp
View file @
83f09476
...
...
@@ -13,6 +13,8 @@
#include "Type.h"
#include "Value.h"
#include <cstdint>
#include <cstring>
#include <string>
// $r0 $zero constant 0
...
...
@@ -98,50 +100,67 @@ CodeGen::run() {
void
CodeGen
::
ptrContent2reg
(
Value
*
ptr
,
int
id
)
{
auto
reg_name
=
"$a"
+
to_string
(
id
);
auto
ele_tp
=
ptr
->
get_type
()
->
get_pointer_element_type
();
assert
(
ele_tp
);
bool
is_float
=
ele_tp
->
is_float_type
();
string
instr_ir
=
(
is_float
?
"fld"
:
"ld"
);
string
reg_name
=
(
is_float
?
"$fa"
:
"$a"
)
+
to_string
(
id
);
string
suff
=
suffix
(
ele_tp
);
if
(
dynamic_cast
<
GlobalVariable
*>
(
ptr
))
{
auto
type
=
static_cast
<
GlobalVariable
*>
(
ptr
)
->
get_type
()
->
get_pointer_element_type
();
auto
suff
=
suffix
(
typeLen
(
type
));
output
.
push_back
(
"la.local "
+
reg_name
+
", "
+
ptr
->
get_name
());
output
.
push_back
(
"ldx"
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
",
$r
0"
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
", 0"
);
}
else
if
(
dynamic_cast
<
AllocaInst
*>
(
ptr
))
{
auto
alloc_instr
=
static_cast
<
AllocaInst
*>
(
ptr
);
string
suff
=
suffix
(
typeLen
(
alloc_instr
->
get_alloca_type
()));
output
.
push_back
(
"ld"
+
suff
+
" "
+
reg_name
+
", $fp, -"
+
/*
auto alloc_instr = static_cast<AllocaInst *>(ptr);
* string suff = suffix(alloc_instr->get_alloca_type()); */
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
ptr
]));
}
else
if
(
dynamic_cast
<
GetElementPtrInst
*>
(
ptr
))
{
auto
GEP_instr
=
static_cast
<
GetElementPtrInst
*>
(
ptr
);
auto
suff
=
suffix
(
typeLen
(
GEP_instr
->
get_element_type
()));
// auto GEP_instr = static_cast<GetElementPtrInst *>(ptr);
output
.
push_back
(
"ld.d "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
ptr
]));
output
.
push_back
(
"ldx"
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
",
$r
0"
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg_name
+
", "
+
reg_name
+
", 0"
);
}
else
assert
(
false
&&
"unknown type"
);
}
void
CodeGen
::
value2reg
(
Value
*
v
,
int
id
,
bool
is_float
)
{
auto
reg_name
=
(
is_float
?
"$f"
:
"$a"
)
+
to_string
(
id
);
CodeGen
::
value2reg
(
Value
*
v
,
int
id
)
{
bool
is_float
=
v
->
get_type
()
->
is_float_type
();
auto
reg_name
=
(
is_float
?
"$fa"
:
"$a"
)
+
to_string
(
id
);
if
(
dynamic_cast
<
Constant
*>
(
v
))
{
auto
constant
=
static_cast
<
Constant
*>
(
v
);
if
(
dynamic_cast
<
ConstantInt
*>
(
constant
))
{
int
k
=
static_cast
<
ConstantInt
*>
(
constant
)
->
get_value
();
if
((
k
&
0xfff
)
!=
k
)
{
output
.
push_back
(
"lui.w "
+
reg_name
+
", "
+
output
.
push_back
(
"lu
12
i.w "
+
reg_name
+
", "
+
to_string
(
k
>>
12
));
output
.
push_back
(
"ori "
+
reg_name
+
", "
+
reg_name
+
", "
+
to_string
(
k
&
0xfff
));
}
else
output
.
push_back
(
"ori "
+
reg_name
+
", $r0, "
+
to_string
(
k
));
}
else
if
(
dynamic_cast
<
ConstantFP
*>
(
constant
))
{
// move the binary code to int-reg, then use movgr2fr to move the
// value to float-reg
string
tmp_ireg
=
"$t0"
;
float
k
=
static_cast
<
ConstantFP
*>
(
constant
)
->
get_value
();
int
hex_int
=
*
(
uint32_t
*
)
&
k
;
if
((
hex_int
&
0xfff
)
!=
hex_int
)
output
.
push_back
(
"lu12i.w "
+
tmp_ireg
+
", "
+
to_string
(
hex_int
>>
12
));
if
(
hex_int
&
0xfff
)
output
.
push_back
(
"ori "
+
tmp_ireg
+
", "
+
tmp_ireg
+
", "
+
to_string
(
hex_int
&
0xfff
));
output
.
push_back
(
"movgr2fr.w "
+
reg_name
+
", "
+
tmp_ireg
);
// output.push_back("ffint.s.w " + reg_name + ", " + reg_name);
}
else
assert
(
false
&&
"wait for completion"
);
}
else
if
(
dynamic_cast
<
GlobalVariable
*>
(
v
))
{
output
.
push_back
(
"la.local "
+
reg_name
+
", "
+
v
->
get_name
());
}
else
if
(
dynamic_cast
<
AllocaInst
*>
(
v
))
{
// auto alloc_instr = dynamic_cast<AllocaInst *>(v);
// give the stack address
output
.
push_back
(
"addi.d "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
v
]));
}
else
if
(
dynamic_cast
<
Argument
*>
(
v
))
{
auto
args
=
cur_func
->
get_args
();
...
...
@@ -149,12 +168,13 @@ CodeGen::value2reg(Value *v, int id, bool is_float) {
for
(
auto
iter
=
args
.
begin
();
id
<=
args
.
size
();
++
iter
,
++
id
)
if
(
*
iter
==
v
)
break
;
output
.
push_back
(
"ld"
+
suffix
(
typeLen
(
v
->
get_type
()))
+
" "
+
reg_name
+
", $fp, "
+
to_string
(
func_arg_off
[
cur_func
][
id
]));
string
instr_ir
=
is_float
?
"fld"
:
"ld"
;
output
.
push_back
(
instr_ir
+
suffix
(
v
->
get_type
())
+
" "
+
reg_name
+
", $fp, "
+
to_string
(
func_arg_off
[
cur_func
][
id
]));
}
else
{
output
.
push_back
(
"ld"
+
suffix
(
typeLen
(
v
->
get_type
()))
+
" "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
v
]));
string
instr_ir
=
is_float
?
"fld"
:
"ld"
;
output
.
push_back
(
instr_ir
+
suffix
(
v
->
get_type
())
+
" "
+
reg_name
+
", $fp, -"
+
to_string
(
off
[
v
]));
}
}
...
...
@@ -215,55 +235,98 @@ CodeGen::stackMemAlloc() {
output
.
push_back
(
"addi.d $fp, $sp, "
+
to_string
(
stackN
));
output
.
push_back
(
"st.d $ra, $fp, -8"
);
}
void
CodeGen
::
IR2assem
(
FpToSiInst
*
instr
)
{
assert
(
instr
->
get_operand
(
0
)
->
get_type
()
==
m
->
get_float_type
());
assert
(
instr
->
get_dest_type
()
==
m
->
get_int32_type
());
value2reg
(
instr
->
get_operand
(
0
));
output
.
push_back
(
"ftint.w.s $fa0, $fa0"
);
output
.
push_back
(
"movfr2gr.s $a0, $fa0"
);
}
void
CodeGen
::
IR2assem
(
SiToFpInst
*
instr
)
{
assert
(
instr
->
get_operand
(
0
)
->
get_type
()
==
m
->
get_int32_type
());
assert
(
instr
->
get_dest_type
()
==
m
->
get_float_type
());
output
.
push_back
(
"movgr2fr.w $fa0, $a0"
);
output
.
push_back
(
"ffint.s.w $fa0, $fa0"
);
}
string
CodeGen
::
bool2branch
(
Instruction
*
instr
)
{
assert
(
instr
->
get_type
()
==
instr
->
get_module
()
->
get_int1_type
());
auto
cmp_instr
=
dynamic_cast
<
CmpInst
*>
(
instr
);
assert
(
cmp_instr
);
assert
(
instr
->
get_type
()
==
m
->
get_int1_type
());
auto
icmp_instr
=
dynamic_cast
<
CmpInst
*>
(
instr
);
auto
fcmp_instr
=
dynamic_cast
<
FCmpInst
*>
(
instr
);
assert
(
icmp_instr
or
fcmp_instr
);
string
instr_ir
;
bool
reverse
=
false
;
switch
(
cmp_instr
->
get_cmp_op
())
{
case
CmpInst
::
EQ
:
instr_ir
=
"beq"
;
break
;
case
CmpInst
::
NE
:
{
instr_ir
=
"bne"
;
if
(
instr
->
get_operand
(
1
)
==
ConstantInt
::
get
(
0
,
instr
->
get_module
())
and
dynamic_cast
<
Instruction
*>
(
instr
->
get_operand
(
0
))
->
is_zext
())
{
// something like:
// %op0 = icmp slt i32 1, 2 # deepest
// %op1 = zext i1 %op0 to i32
// %op2 = icmp ne i32 %op1, 0
// br i1 %op2, label %label3, label %label5
auto
deepest
=
static_cast
<
Instruction
*>
(
static_cast
<
Instruction
*>
(
instr
->
get_operand
(
0
))
->
get_operand
(
0
));
return
bool2branch
(
deepest
);
}
if
(
icmp_instr
)
{
switch
(
icmp_instr
->
get_cmp_op
())
{
case
CmpInst
::
EQ
:
instr_ir
=
"beq"
;
break
;
case
CmpInst
::
NE
:
{
instr_ir
=
"bne"
;
if
(
instr
->
get_operand
(
1
)
==
ConstantInt
::
get
(
0
,
m
)
and
dynamic_cast
<
Instruction
*>
(
instr
->
get_operand
(
0
))
->
is_zext
())
{
// something like:
// %op0 = icmp slt i32 1, 2 # deepest
// %op1 = zext i1 %op0 to i32
// %op2 = icmp ne i32 %op1, 0
// br i1 %op2, label %label3, label %label5
auto
deepest
=
static_cast
<
Instruction
*>
(
static_cast
<
Instruction
*>
(
instr
->
get_operand
(
0
))
->
get_operand
(
0
));
return
bool2branch
(
deepest
);
}
}
break
;
case
CmpInst
::
GT
:
instr_ir
=
"blt"
;
reverse
=
true
;
break
;
case
CmpInst
::
GE
:
instr_ir
=
"bge"
;
break
;
case
CmpInst
::
LT
:
instr_ir
=
"blt"
;
break
;
case
CmpInst
::
LE
:
instr_ir
=
"bge"
;
reverse
=
true
;
break
;
}
break
;
case
CmpInst
::
GT
:
instr_ir
=
"blt"
;
reverse
=
true
;
break
;
case
CmpInst
::
GE
:
instr_ir
=
"bge"
;
break
;
case
CmpInst
::
LT
:
instr_ir
=
"blt"
;
break
;
case
CmpInst
::
LE
:
instr_ir
=
"bge"
;
reverse
=
true
;
break
;
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
return
instr_ir
+
(
reverse
?
" $a1, $a0,"
:
" $a0, $a1,"
);
}
else
{
switch
(
fcmp_instr
->
get_cmp_op
())
{
case
FCmpInst
::
EQ
:
instr_ir
=
"fcmp.ceq.s $fcc0"
;
break
;
case
FCmpInst
::
NE
:
instr_ir
=
"fcmp.cun.s $fcc0"
;
break
;
case
FCmpInst
::
GT
:
instr_ir
=
"fcmp.cle.s $fcc0"
;
reverse
=
true
;
break
;
case
FCmpInst
::
GE
:
instr_ir
=
"fcmp.clt.s $fcc0"
;
reverse
=
true
;
break
;
case
FCmpInst
::
LT
:
instr_ir
=
"fcmp.clt.s $fcc0"
;
break
;
case
FCmpInst
::
LE
:
instr_ir
=
"fcmp.cle.s $fcc0"
;
break
;
}
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
output
.
push_back
(
instr_ir
+
", "
+
"$fa0, $fa1"
);
return
(
reverse
?
"bceqz $fcc0,"
:
"bcnez $fcc0,"
);
}
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
return
instr_ir
+
(
reverse
?
" $a1, $a0 "
:
" $a0, $a1 "
);
}
void
...
...
@@ -287,85 +350,33 @@ CodeGen::IR2assem(CallInst *instr) {
auto
func
=
static_cast
<
Function
*>
(
instr
->
get_operand
(
0
));
// stack space allocation
output
.
push_back
(
"addi.d $sp, $sp, -"
+
to_string
(
func_arg_N
[
func
]));
string
instr_ir
,
suff
,
reg
;
// place the arguments
for
(
int
i
=
1
;
i
<
instr
->
get_num_operand
();
i
++
)
{
auto
arg
=
instr
->
get_operand
(
i
);
auto
tplen
=
typeLen
(
arg
->
get_type
());
string
suff
=
suffix
(
tplen
);
// auto tplen = typeLen(arg->get_type());
instr_ir
=
(
arg
->
get_type
()
->
is_float_type
()
?
"fst"
:
"st"
);
suff
=
suffix
(
arg
->
get_type
());
reg
=
(
arg
->
get_type
()
->
is_float_type
()
?
"$fa0"
:
"$a0"
);
value2reg
(
arg
);
output
.
push_back
(
"st"
+
suff
+
" $a0
, $sp, "
+
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
"
, $sp, "
+
to_string
(
func_arg_off
[
func
][
i
]));
}
output
.
push_back
(
"bl "
+
func
->
get_name
());
output
.
push_back
(
"addi.d $sp, $sp, "
+
to_string
(
func_arg_N
[
func
]));
output
.
push_back
(
"addi.d $fp, $sp, "
+
to_string
(
stackN
));
if
(
not
instr
->
is_void
())
back2stack
(
instr
);
}
/* void
* CodeGen::IR2assem(CmpInst *instr) {
* value2reg(instr->get_operand(0), 0);
* value2reg(instr->get_operand(1), 1);
* string instr_ir;
* switch (instr->get_cmp_op()) {
* case CmpInst::EQ:
* break;
* case CmpInst::NE:
* // output.push_back("xor $a0, $a0, $a1");
* break;
* case CmpInst::GT:
* output.push_back("slt $a0, $a1, $a0");
* break;
* case CmpInst::GE:
* break;
* case CmpInst::LT:
* output.push_back("slt $a0, $a0, $a1");
* break;
* case CmpInst::LE:
* break;
* }
* output.push_back(instr_ir + " $a0, $a0, $a1");
* back2stack(instr);
* } */
void
CodeGen
::
IR2assem
(
BinaryInst
*
instr
)
{
auto
is_float
=
instr
->
get_type
()
->
is_float_type
();
value2reg
(
instr
->
get_operand
(
0
),
0
);
value2reg
(
instr
->
get_operand
(
1
),
1
);
string
suff
=
suffix
(
typeLen
(
instr
->
get_type
()));
string
instr_ir
;
switch
(
instr
->
get_instr_type
())
{
case
Instruction
::
add
:
instr_ir
=
"add"
;
break
;
case
Instruction
::
sub
:
instr_ir
=
"sub"
;
break
;
case
Instruction
::
mul
:
instr_ir
=
"mulw.d.w"
;
suff
=
""
;
break
;
case
Instruction
::
sdiv
:
instr_ir
=
"div"
;
break
;
/* case Instruction::fadd:
* instr_ir = "fadd";
* break;
* case Instruction::fsub:
* instr_ir = "fsub";
* break;
* case Instruction::fmul:
* instr_ir = "fmul";
* break;
* case Instruction::fdiv:
* instr_ir = "fdiv";
* break; */
default:
assert
(
false
&&
"instruction type"
);
}
output
.
push_back
(
instr_ir
+
suff
+
" $a0, $a0, $a1"
);
back2stack
(
instr
);
string
instr_ir
=
instr
->
get_instr_op_name
();
string
suff
=
suffix
(
instr
->
get_type
());
output
.
push_back
(
instr_ir
+
suff
+
(
is_float
?
" $fa0, $fa0, $fa1"
:
" $a0, $a0, $a1"
));
}
void
...
...
@@ -383,10 +394,10 @@ CodeGen::IR2assem(GetElementPtrInst *instr) {
}
else
assert
(
false
&&
"GEP translation error"
);
value2reg
(
instr
->
get_operand
(
i
),
1
);
output
.
push_back
(
"mul.w $a1, $a1, "
+
to_string
(
size
));
value2reg
(
ConstantInt
::
get
(
size
,
m
),
2
);
output
.
push_back
(
"mul.w $a1, $a1, $a2"
);
output
.
push_back
(
"add.d $a0, $a0, $a1"
);
}
back2stack
(
instr
);
}
void
...
...
@@ -395,18 +406,17 @@ CodeGen::IR2assem(LoadInst *instr) {
ptrContent2reg
(
instr
->
get_lval
());
assert
(
instr
->
get_type
()
==
instr
->
get_load_type
());
back2stack
(
instr
);
/* string suff = suffix(typeLen(instr->get_load_type()));
* string addr = "$fp, -" + to_string(off[instr]);
* output.push_back("st" + suff + " $a0, " + addr); */
}
void
CodeGen
::
IR2assem
(
StoreInst
*
instr
)
{
value2reg
(
instr
->
get_rval
());
value2reg
(
instr
->
get_rval
()
,
0
);
value2reg
(
instr
->
get_lval
(),
1
);
string
suff
=
suffix
(
typeLen
(
instr
->
get_rval
()
->
get_type
()));
output
.
push_back
(
"st"
+
suff
+
" $a0, $a1, 0"
);
bool
is_float
=
instr
->
get_rval
()
->
get_type
()
->
is_float_type
();
string
instr_ir
=
(
is_float
?
"fst"
:
"st"
);
string
suff
=
suffix
(
instr
->
get_rval
()
->
get_type
());
string
reg
=
(
is_float
?
"$fa0"
:
"$a0"
);
output
.
push_back
(
instr_ir
+
suff
+
" "
+
reg
+
", $a1, 0"
);
}
void
...
...
@@ -424,59 +434,60 @@ CodeGen::IR2assem(Instruction &instr) {
switch
(
instr
.
get_instr_type
())
{
case
Instruction
::
ret
:
IR2assem
(
static_cast
<
ReturnInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
br
:
IR2assem
(
static_cast
<
BranchInst
*>
(
&
instr
));
return
;
break
;
// Standard binary operators
case
Instruction
::
add
:
case
Instruction
::
sub
:
case
Instruction
::
mul
:
case
Instruction
::
sdiv
:
IR2assem
(
static_cast
<
BinaryInst
*>
(
&
instr
));
return
;
// float binary operators
case
Instruction
::
fadd
:
break
;
case
Instruction
::
fsub
:
break
;
case
Instruction
::
fmul
:
break
;
case
Instruction
::
fdiv
:
IR2assem
(
static_cast
<
BinaryInst
*>
(
&
instr
));
break
;
// Memory operators
case
Instruction
::
alloca
:
IR2assem
(
static_cast
<
AllocaInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
load
:
IR2assem
(
static_cast
<
LoadInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
store
:
IR2assem
(
static_cast
<
StoreInst
*>
(
&
instr
));
return
;
break
;
// Other operators
case
Instruction
::
cmp
:
IR2assem
(
static_cast
<
CmpInst
*>
(
&
instr
));
break
;
case
Instruction
::
fcmp
:
IR2assem
(
static_cast
<
FCmpInst
*>
(
&
instr
));
break
;
case
Instruction
::
phi
:
IR2assem
(
static_cast
<
PhiInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
call
:
IR2assem
(
static_cast
<
CallInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
getelementptr
:
IR2assem
(
static_cast
<
GetElementPtrInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
zext
:
IR2assem
(
static_cast
<
ZextInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
fptosi
:
IR2assem
(
static_cast
<
FpToSiInst
*>
(
&
instr
));
return
;
break
;
case
Instruction
::
sitofp
:
IR2assem
(
static_cast
<
SiToFpInst
*>
(
&
instr
));
return
;
break
;
}
// assert(false && "This ")
if
(
not
instr
.
is_void
()
and
not
no_stack_alloca
(
&
instr
)
and
not
instr
.
is_alloca
())
back2stack
(
&
instr
);
}
tests/5-bonus/test_time.py
View file @
83f09476
...
...
@@ -6,7 +6,7 @@ import argparse
import
subprocess
test_dir
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
# 当前文件夹路径 tests/5-bonus
cminus
=
os
.
path
.
join
(
test_dir
,
'../../build/cminus'
)
# ===可修改===
cminus
=
os
.
path
.
join
(
test_dir
,
'../../build/cminus
fc
'
)
# ===可修改===
testfile_dir
=
os
.
path
.
join
(
test_dir
,
'./testcases'
)
output_file_name
=
os
.
path
.
join
(
test_dir
,
'./test_result'
)
io
=
os
.
path
.
join
(
test_dir
,
'../../src/io/io.c'
)
...
...
@@ -56,7 +56,8 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
# 超时,跳过
if
start_time
-
total_start
>
30
*
60
or
start_time
-
single_begin
>
30
*
60
:
output_file
.
write
(
f"[
{
count
+
1
}
/
{
test_count
}
] "
+
file_name
+
': skipped due to exceeded total time limit
\n
'
)
output_file
.
write
(
f"[
{
count
+
1
}
/
{
test_count
}
] "
+
file_name
+
': skipped due to exceeded total time limit
\n
'
)
continue
# 未超时
output_file
.
write
(
f"[
{
count
+
1
}
/
{
test_count
}
] "
+
file_name
+
': '
)
...
...
@@ -75,8 +76,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file
.
write
(
'compile-1 timeout
\n
'
)
failed_count
+=
1
continue
except
Exception
:
except
Exception
as
e
:
output_file
.
write
(
"compile-1 failed with an unexcept error
\n
"
)
output_file
.
write
(
str
(
e
))
failed_count
+=
1
continue
...
...
@@ -107,8 +109,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file
.
write
(
'compile timeout
\n
'
)
failed_count
+=
1
continue
except
Exception
:
except
Exception
as
e
:
output_file
.
write
(
"compile failed with an unexcept error
\n
"
)
output_file
.
write
(
e
)
failed_count
+=
1
continue
...
...
@@ -135,8 +138,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file
.
write
(
"executable time limit exceeded
\n
"
)
failed_count
+=
1
continue
except
Exception
as
_
:
except
Exception
as
e
:
output_file
.
write
(
'executable runtime error
\n
'
)
output_file
.
write
(
str
(
e
))
failed_count
+=
1
continue
...
...
@@ -159,8 +163,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
succ_count
+=
1
testtime
[
count
]
=
time
else
:
output_file
.
write
(
'output is different from standard answer, this may be caused by wrong return code
\n
'
)
# 因为退出码也会作为输出的一部分,因此输出和答案不同可能是程序崩溃造成的
# 因为退出码也会作为输出的一部分,因此输出和答案不同可能是程序崩溃造成的
output_file
.
write
(
'output is different from standard answer, this may be caused by wrong return code
\n
'
)
output_file
.
write
(
f"
\t
{
ref
=
}
"
)
output_file
.
write
(
f"
\t
{
actual
=
}
"
)
failed_count
+=
1
output_file
.
write
(
f"
{
failed_count
}
tests failed
\n
"
)
...
...
@@ -172,9 +179,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file
.
write
(
'
\t\t\t
your_cminus'
)
for
count
,
file_name
in
enumerate
(
testfiles
):
output_file
.
write
(
'{:<20}'
.
format
(
file_name
))
output_file
.
write
(
'
\t\t
%.6f'
%
testtime
[
count
]
if
testtime
[
count
]
!=
-
1
else
'
\t\t
None '
)
output_file
.
write
(
'
\t\t
%.6f'
%
testtime
[
count
]
if
testtime
[
count
]
!=
-
1
else
'
\t\t
None '
)
output_file
.
write
(
"===================================================================
\n
"
)
output_file
.
write
(
"===================================================================
\n
"
)
if
__name__
==
"__main__"
:
...
...
@@ -182,8 +191,10 @@ if __name__ == "__main__":
parser
=
argparse
.
ArgumentParser
(
description
=
"functional test"
)
parser
.
add_argument
(
"--console"
,
action
=
"store_true"
,
help
=
"specify whether to output the result to console"
)
parser
.
add_argument
(
"--clang"
,
action
=
"store_true"
,
help
=
"estimate runtime when compile with clang"
)
parser
.
add_argument
(
"--console"
,
action
=
"store_true"
,
help
=
"specify whether to output the result to console"
)
parser
.
add_argument
(
"--clang"
,
action
=
"store_true"
,
help
=
"estimate runtime when compile with clang"
)
args
=
parser
.
parse_args
()
eval
(
args
.
console
,
testfile_dir
,
use_clang
=
args
.
clang
)
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