Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mu-impl-fast
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
40
Issues
40
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
mu
mu-impl-fast
Commits
bdea18c4
Commit
bdea18c4
authored
Nov 01, 2016
by
qinsoon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sext, zext, truncate
(throw, new not working)
parent
9262dfcc
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
297 additions
and
21 deletions
+297
-21
.gitignore
.gitignore
+1
-0
run_test.sh
run_test.sh
+2
-0
src/ast/src/types.rs
src/ast/src/types.rs
+2
-0
src/compiler/backend/arch/x86_64/inst_sel.rs
src/compiler/backend/arch/x86_64/inst_sel.rs
+101
-0
tests/test_compiler/test_int.rs
tests/test_compiler/test_int.rs
+191
-21
No files found.
.gitignore
View file @
bdea18c4
**/target/*
**/__pycache__/*
**/.cache/*
emit/*
**/temp/*
Cargo.lock
...
...
run_test.sh
View file @
bdea18c4
...
...
@@ -64,6 +64,8 @@ echo "KERNEL: $KERNEL"
echo
"ARCH:
$MACH
"
echo
"---------"
rm
emit/
*
if
[
"
$OS
"
==
"linux"
]
;
then
RUSTFLAGS
=
-Zincremental
=
target/incr-cache
RUST_BACKTRACE
=
1
RUST_TEST_THREADS
=
1
CC
=
clang-3.8 cargo
test
"
$@
"
elif
[
"
$OS
"
==
"Darwin"
]
;
then
...
...
src/ast/src/types.rs
View file @
bdea18c4
...
...
@@ -35,6 +35,8 @@ lazy_static! {
pub
static
ref
INTERNAL_TYPES
:
Vec
<
P
<
MuType
>>
=
vec!
[
ADDRESS_TYPE
.clone
(),
UINT8_TYPE
.clone
(),
UINT16_TYPE
.clone
(),
UINT32_TYPE
.clone
(),
UINT64_TYPE
.clone
(),
DOUBLE_TYPE
.clone
()
...
...
src/compiler/backend/arch/x86_64/inst_sel.rs
View file @
bdea18c4
...
...
@@ -483,6 +483,107 @@ impl <'a> InstructionSelection {
_
=>
unimplemented!
()
}
}
Instruction_
::
ConvOp
{
operation
,
ref
from_ty
,
ref
to_ty
,
operand
}
=>
{
let
ops
=
inst
.ops
.read
()
.unwrap
();
let
ref
op
=
ops
[
operand
];
let
extract_int_len
=
|
x
:
&
P
<
MuType
>
|
{
match
x
.v
{
MuType_
::
Int
(
len
)
=>
len
,
_
=>
panic!
(
"only expect int types, found: {}"
,
x
)
}
};
match
operation
{
op
::
ConvOp
::
TRUNC
=>
{
// currently only use 64bits register
// so only keep what is needed in the register (set others to 0)
let
from_ty_len
=
extract_int_len
(
from_ty
);
let
to_ty_len
=
extract_int_len
(
to_ty
);
debug_assert!
(
from_ty_len
>
to_ty_len
);
if
self
.match_ireg
(
op
)
{
let
tmp_op
=
self
.emit_ireg
(
op
,
f_content
,
f_context
,
vm
);
let
tmp_res
=
self
.get_result_value
(
node
);
// ignoring from_ty for now (we use 64bits register for everything)
let
mask
=
match
to_ty_len
{
8
=>
0xFFi32
,
16
=>
0xFFFFi32
,
32
=>
0xFFFFFFFFi32
,
_
=>
unimplemented!
()
};
// mov op -> result
self
.backend
.emit_mov_r64_r64
(
&
tmp_res
,
&
tmp_op
);
// and mask, result -> result
self
.backend
.emit_and_r64_imm32
(
&
tmp_res
,
mask
);
}
else
{
panic!
(
"unexpected op (expect ireg): {}"
,
op
);
}
}
op
::
ConvOp
::
ZEXT
=>
{
// currently only use 64bits register
// so set irrelevant bits to 0
let
from_ty_len
=
extract_int_len
(
from_ty
);
let
to_ty_len
=
extract_int_len
(
to_ty
);
debug_assert!
(
from_ty_len
<
to_ty_len
);
if
self
.match_ireg
(
op
)
{
let
tmp_op
=
self
.emit_ireg
(
op
,
f_content
,
f_context
,
vm
);
let
tmp_res
=
self
.get_result_value
(
node
);
let
mask
=
match
from_ty_len
{
8
=>
0xFFi32
,
16
=>
0xFFFFi32
,
32
=>
0xFFFFFFFFi32
,
_
=>
unimplemented!
()
};
// mov op -> result
self
.backend
.emit_mov_r64_r64
(
&
tmp_res
,
&
tmp_op
);
// and mask result -> result
self
.backend
.emit_and_r64_imm32
(
&
tmp_res
,
mask
);
}
else
{
panic!
(
"unexpected op (expect ireg): {}"
,
op
);
}
},
op
::
ConvOp
::
SEXT
=>
{
// currently only use 64bits register
// we left shift the value, then arithmetic right shift back
let
from_ty_len
=
extract_int_len
(
from_ty
);
let
to_ty_len
=
extract_int_len
(
to_ty
);
debug_assert!
(
from_ty_len
<
to_ty_len
);
let
shift
:
i8
=
(
to_ty_len
-
from_ty_len
)
as
i8
;
if
self
.match_ireg
(
op
)
{
let
tmp_op
=
self
.emit_ireg
(
op
,
f_content
,
f_context
,
vm
);
let
tmp_res
=
self
.get_result_value
(
node
);
// mov op -> result
self
.backend
.emit_mov_r64_r64
(
&
tmp_res
,
&
tmp_op
);
// shl result, shift -> result
self
.backend
.emit_shl_r64_imm8
(
&
tmp_res
,
shift
);
// sar result, shift -> result
self
.backend
.emit_sar_r64_imm8
(
&
tmp_res
,
shift
);
}
else
{
panic!
(
"unexpected op (expect ireg): {}"
,
op
)
}
}
_
=>
unimplemented!
()
}
}
// load on x64 generates mov inst (no matter what order is specified)
// https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
...
...
tests/test_compiler/test_int.rs
View file @
bdea18c4
...
...
@@ -12,32 +12,13 @@ use self::mu::compiler::*;
use
std
::
sync
::
RwLock
;
use
std
::
sync
::
Arc
;
use
mu
::
testutil
;
use
mu
::
testutil
::
aot
;
#[test]
fn
test_u8_add
()
{
simple_logger
::
init_with_level
(
log
::
LogLevel
::
Trace
)
.ok
(
);
let
lib
=
testutil
::
compile_fnc
(
"u8_add"
,
&
u8_add
);
let
vm
=
Arc
::
new
(
u8_add
());
let
compiler
=
Compiler
::
new
(
CompilerPolicy
::
default
(),
vm
.clone
());
let
func_id
=
vm
.id_of
(
"u8_add"
);
{
let
funcs
=
vm
.funcs
()
.read
()
.unwrap
();
let
func
=
funcs
.get
(
&
func_id
)
.unwrap
()
.read
()
.unwrap
();
let
func_vers
=
vm
.func_vers
()
.read
()
.unwrap
();
let
mut
func_ver
=
func_vers
.get
(
&
func
.cur_ver
.unwrap
())
.unwrap
()
.write
()
.unwrap
();
compiler
.compile
(
&
mut
func_ver
);
}
backend
::
emit_context
(
&
vm
);
let
dylib
=
aot
::
link_dylib
(
vec!
[
Mu
(
"u8_add"
)],
"libu8_add.dylib"
);
let
lib
=
libloading
::
Library
::
new
(
dylib
.as_os_str
())
.unwrap
();
unsafe
{
let
u8_add
:
libloading
::
Symbol
<
unsafe
extern
fn
(
u8
,
u8
)
->
u8
>
=
lib
.get
(
b
"u8_add"
)
.unwrap
();
...
...
@@ -115,5 +96,194 @@ fn u8_add() -> VM {
vm
.define_func_version
(
func_ver
);
vm
}
#[test]
fn
test_truncate
()
{
let
lib
=
testutil
::
compile_fnc
(
"truncate"
,
&
truncate
);
unsafe
{
let
truncate
:
libloading
::
Symbol
<
unsafe
extern
fn
(
u64
)
->
u64
>
=
lib
.get
(
b
"truncate"
)
.unwrap
();
let
res
=
truncate
(
0xF01u64
);
println!
(
"truncate(0xF01) = {}"
,
res
);
assert
!
(
res
==
1
);
}
}
fn
truncate
()
->
VM
{
let
vm
=
VM
::
new
();
// .typedef @u64 = int<64>
let
type_def_u64
=
vm
.declare_type
(
vm
.next_id
(),
MuType_
::
int
(
64
));
vm
.set_name
(
type_def_u64
.as_entity
(),
Mu
(
"u64"
));
// .typedef @u8 = int<8>
let
type_def_u8
=
vm
.declare_type
(
vm
.next_id
(),
MuType_
::
int
(
8
));
vm
.set_name
(
type_def_u8
.as_entity
(),
Mu
(
"u8"
));
// .funcsig @truncate_sig = (@u64) -> (@u64)
let
truncate_sig
=
vm
.declare_func_sig
(
vm
.next_id
(),
vec!
[
type_def_u64
.clone
()],
vec!
[
type_def_u64
.clone
()]);
vm
.set_name
(
truncate_sig
.as_entity
(),
Mu
(
"truncate_sig"
));
// .funcdecl @truncate <@truncate_sig>
let
func_id
=
vm
.next_id
();
let
func
=
MuFunction
::
new
(
func_id
,
truncate_sig
.clone
());
vm
.set_name
(
func
.as_entity
(),
Mu
(
"truncate"
));
vm
.declare_func
(
func
);
// .funcdef @truncate VERSION @truncate_v1 <@truncate_sig>
let
mut
func_ver
=
MuFunctionVersion
::
new
(
vm
.next_id
(),
func_id
,
truncate_sig
.clone
());
vm
.set_name
(
func_ver
.as_entity
(),
Mu
(
"truncate_v1"
));
// %entry(<@u64> %a):
let
mut
blk_entry
=
Block
::
new
(
vm
.next_id
());
vm
.set_name
(
blk_entry
.as_entity
(),
Mu
(
"entry"
));
let
blk_entry_a
=
func_ver
.new_ssa
(
vm
.next_id
(),
type_def_u8
.clone
());
vm
.set_name
(
blk_entry_a
.as_entity
(),
Mu
(
"blk_entry_a"
));
// %r = TRUNC @u64->@u8 %a
let
blk_entry_r
=
func_ver
.new_ssa
(
vm
.next_id
(),
type_def_u8
.clone
());
vm
.set_name
(
blk_entry_r
.as_entity
(),
Mu
(
"blk_entry_r"
));
let
blk_entry_truncate
=
func_ver
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
vm
.next_id
()),
value
:
Some
(
vec!
[
blk_entry_r
.clone_value
()]),
ops
:
RwLock
::
new
(
vec!
[
blk_entry_a
.clone
()]),
v
:
Instruction_
::
ConvOp
{
operation
:
ConvOp
::
TRUNC
,
from_ty
:
type_def_u64
.clone
(),
to_ty
:
type_def_u8
.clone
(),
operand
:
0
}
});
// %r2 = ZEXT @u8->@u64 %r
let
blk_entry_r2
=
func_ver
.new_ssa
(
vm
.next_id
(),
type_def_u64
.clone
());
vm
.set_name
(
blk_entry_r2
.as_entity
(),
Mu
(
"blk_entry_r2"
));
let
blk_entry_zext
=
func_ver
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
vm
.next_id
()),
value
:
Some
(
vec!
[
blk_entry_r2
.clone_value
()]),
ops
:
RwLock
::
new
(
vec!
[
blk_entry_r
.clone
()]),
v
:
Instruction_
::
ConvOp
{
operation
:
ConvOp
::
ZEXT
,
from_ty
:
type_def_u8
.clone
(),
to_ty
:
type_def_u64
.clone
(),
operand
:
0
}
});
// RET %r2
let
blk_entry_term
=
func_ver
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
vm
.next_id
()),
value
:
None
,
ops
:
RwLock
::
new
(
vec!
[
blk_entry_r2
.clone
()]),
v
:
Instruction_
::
Return
(
vec!
[
0
])
});
blk_entry
.content
=
Some
(
BlockContent
{
args
:
vec!
[
blk_entry_a
.clone_value
()],
exn_arg
:
None
,
body
:
vec!
[
blk_entry_truncate
,
blk_entry_zext
,
blk_entry_term
],
keepalives
:
None
});
func_ver
.define
(
FunctionContent
{
entry
:
blk_entry
.id
(),
blocks
:
hashmap!
{
blk_entry
.id
()
=>
blk_entry
}
});
vm
.define_func_version
(
func_ver
);
vm
}
#[test]
fn
test_sext
()
{
let
lib
=
testutil
::
compile_fnc
(
"sext"
,
&
sext
);
unsafe
{
let
sext
:
libloading
::
Symbol
<
unsafe
extern
fn
(
i8
)
->
i64
>
=
lib
.get
(
b
"sext"
)
.unwrap
();
let
res
=
sext
(
-
1
);
println!
(
"truncate(-1) = {}"
,
res
);
assert
!
(
res
==
-
1
);
}
}
fn
sext
()
->
VM
{
let
vm
=
VM
::
new
();
// .typedef @i8 = int<8>
let
type_def_i8
=
vm
.declare_type
(
vm
.next_id
(),
MuType_
::
int
(
8
));
vm
.set_name
(
type_def_i8
.as_entity
(),
Mu
(
"i8"
));
// .typedef @i64 = int<64>
let
type_def_i64
=
vm
.declare_type
(
vm
.next_id
(),
MuType_
::
int
(
64
));
vm
.set_name
(
type_def_i64
.as_entity
(),
Mu
(
"i64"
));
// .funcsig @sext_sig = (@i8) -> (@i64)
let
sext_sig
=
vm
.declare_func_sig
(
vm
.next_id
(),
vec!
[
type_def_i64
.clone
()],
vec!
[
type_def_i8
.clone
()]);
vm
.set_name
(
sext_sig
.as_entity
(),
Mu
(
"sext_sig"
));
// .funcdecl @sext <@sext_sig>
let
func_id
=
vm
.next_id
();
let
func
=
MuFunction
::
new
(
func_id
,
sext_sig
.clone
());
vm
.set_name
(
func
.as_entity
(),
Mu
(
"sext"
));
vm
.declare_func
(
func
);
// .funcdef @sext VERSION @sext_v1 <@sext_sig>
let
mut
func_ver
=
MuFunctionVersion
::
new
(
vm
.next_id
(),
func_id
,
sext_sig
.clone
());
vm
.set_name
(
func_ver
.as_entity
(),
Mu
(
"sext_v1"
));
// %entry(<@i8> %a):
let
mut
blk_entry
=
Block
::
new
(
vm
.next_id
());
vm
.set_name
(
blk_entry
.as_entity
(),
Mu
(
"entry"
));
let
blk_entry_a
=
func_ver
.new_ssa
(
vm
.next_id
(),
type_def_i8
.clone
());
vm
.set_name
(
blk_entry_a
.as_entity
(),
Mu
(
"blk_entry_a"
));
// %r = SEXT @i8->@i64 %a
let
blk_entry_r
=
func_ver
.new_ssa
(
vm
.next_id
(),
type_def_i64
.clone
());
vm
.set_name
(
blk_entry_r
.as_entity
(),
Mu
(
"blk_entry_r"
));
let
blk_entry_add
=
func_ver
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
vm
.next_id
()),
value
:
Some
(
vec!
[
blk_entry_r
.clone_value
()]),
ops
:
RwLock
::
new
(
vec!
[
blk_entry_a
.clone
()]),
v
:
Instruction_
::
ConvOp
{
operation
:
ConvOp
::
SEXT
,
from_ty
:
type_def_i8
.clone
(),
to_ty
:
type_def_i64
.clone
(),
operand
:
0
}
});
// RET %r
let
blk_entry_term
=
func_ver
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
vm
.next_id
()),
value
:
None
,
ops
:
RwLock
::
new
(
vec!
[
blk_entry_r
.clone
()]),
v
:
Instruction_
::
Return
(
vec!
[
0
])
});
blk_entry
.content
=
Some
(
BlockContent
{
args
:
vec!
[
blk_entry_a
.clone_value
()],
exn_arg
:
None
,
body
:
vec!
[
blk_entry_add
,
blk_entry_term
],
keepalives
:
None
});
func_ver
.define
(
FunctionContent
{
entry
:
blk_entry
.id
(),
blocks
:
hashmap!
{
blk_entry
.id
()
=>
blk_entry
}
});
vm
.define_func_version
(
func_ver
);
vm
}
\ 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