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
97e188ad
Commit
97e188ad
authored
Nov 14, 2016
by
qinsoon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement SELECT
parent
01145b46
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
325 additions
and
8 deletions
+325
-8
.gitignore
.gitignore
+1
-0
src/ast/src/inst.rs
src/ast/src/inst.rs
+8
-0
src/ast/src/ir_semantics.rs
src/ast/src/ir_semantics.rs
+2
-0
src/ast/src/op.rs
src/ast/src/op.rs
+2
-0
src/compiler/backend/arch/x86_64/asm_backend.rs
src/compiler/backend/arch/x86_64/asm_backend.rs
+42
-0
src/compiler/backend/arch/x86_64/codegen.rs
src/compiler/backend/arch/x86_64/codegen.rs
+42
-0
src/compiler/backend/arch/x86_64/inst_sel.rs
src/compiler/backend/arch/x86_64/inst_sel.rs
+78
-1
tests/ir_macros.rs
tests/ir_macros.rs
+24
-0
tests/test_compiler/test_controlflow.rs
tests/test_compiler/test_controlflow.rs
+126
-7
No files found.
.gitignore
View file @
97e188ad
...
...
@@ -8,3 +8,4 @@ Cargo.lock
*.DS_Store
*.swp
.idea
*.pyc
src/ast/src/inst.rs
View file @
97e188ad
...
...
@@ -221,6 +221,11 @@ pub enum Instruction_ {
false_dest
:
Destination
,
true_prob
:
f32
},
Select
{
cond
:
OpIndex
,
true_val
:
OpIndex
,
false_val
:
OpIndex
},
Watchpoint
{
// Watchpoint NONE ResumptionData
// serves as an unconditional trap. Trap to client, and resume with ResumptionData
// Watchpoint (WPID dest) ResumptionData
...
...
@@ -333,6 +338,9 @@ impl Instruction_ {
&
Instruction_
::
Branch2
{
cond
,
ref
true_dest
,
ref
false_dest
,
..
}
=>
{
format!
(
"BRANCH2 {} {} {}"
,
ops
[
cond
],
true_dest
.debug_str
(
ops
),
false_dest
.debug_str
(
ops
))
},
&
Instruction_
::
Select
{
cond
,
true_val
,
false_val
}
=>
{
format!
(
"SELECT if {} then {} else {}"
,
ops
[
cond
],
ops
[
true_val
],
ops
[
false_val
])
}
&
Instruction_
::
Watchpoint
{
id
,
ref
disable_dest
,
ref
resume
}
=>
{
match
id
{
Some
(
id
)
=>
{
...
...
src/ast/src/ir_semantics.rs
View file @
97e188ad
...
...
@@ -25,6 +25,7 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
|
&
GetElementIRef
{
..
}
|
&
ShiftIRef
{
..
}
|
&
GetVarPartIRef
{
..
}
|
&
Select
{
..
}
|
&
Fence
(
_
)
=>
false
,
&
Return
(
_
)
|
&
ThreadExit
...
...
@@ -78,6 +79,7 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
&
TailCall
(
_
)
=>
true
,
&
Branch1
(
_
)
=>
true
,
&
Branch2
{
..
}
=>
true
,
&
Select
{
..
}
=>
false
,
&
Watchpoint
{
..
}
=>
true
,
&
WPBranch
{
..
}
=>
true
,
&
Call
{
..
}
=>
true
,
...
...
src/ast/src/op.rs
View file @
97e188ad
...
...
@@ -24,6 +24,7 @@ pub enum OpCode {
TailCall
,
Branch1
,
Branch2
,
Select
,
Watchpoint
,
WPBranch
,
Call
,
...
...
@@ -272,6 +273,7 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
Instruction_
::
TailCall
(
_
)
=>
OpCode
::
TailCall
,
Instruction_
::
Branch1
(
_
)
=>
OpCode
::
Branch1
,
Instruction_
::
Branch2
{
..
}
=>
OpCode
::
Branch2
,
Instruction_
::
Select
{
..
}
=>
OpCode
::
Select
,
Instruction_
::
Watchpoint
{
..
}
=>
OpCode
::
Watchpoint
,
Instruction_
::
WPBranch
{
..
}
=>
OpCode
::
WPBranch
,
Instruction_
::
Call
{
..
}
=>
OpCode
::
Call
,
...
...
src/compiler/backend/arch/x86_64/asm_backend.rs
View file @
97e188ad
...
...
@@ -1657,6 +1657,48 @@ impl CodeGenerator for ASMCodeGen {
mov_mem_imm!
(
emit_mov_mem16_imm16
,
"mov"
,
16
,
i16
);
mov_mem_imm!
(
emit_mov_mem8_imm8
,
"mov"
,
8
,
i8
);
// cmov
mov_r_r!
(
emit_cmova_r64_r64
,
"cmova"
,
64
);
mov_r_imm!
(
emit_cmova_r64_imm32
,
"cmova"
,
64
,
i32
);
mov_r_mem!
(
emit_cmova_r64_mem64
,
"cmova"
,
64
);
mov_r_r!
(
emit_cmovae_r64_r64
,
"cmovae"
,
64
);
mov_r_imm!
(
emit_cmovae_r64_imm32
,
"cmovae"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovae_r64_mem64
,
"cmovae"
,
64
);
mov_r_r!
(
emit_cmovb_r64_r64
,
"cmovb"
,
64
);
mov_r_imm!
(
emit_cmovb_r64_imm32
,
"cmovb"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovb_r64_mem64
,
"cmovb"
,
64
);
mov_r_r!
(
emit_cmovbe_r64_r64
,
"cmovbe"
,
64
);
mov_r_imm!
(
emit_cmovbe_r64_imm32
,
"cmovbe"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovbe_r64_mem64
,
"cmovbe"
,
64
);
mov_r_r!
(
emit_cmove_r64_r64
,
"cmove"
,
64
);
mov_r_imm!
(
emit_cmove_r64_imm32
,
"cmove"
,
64
,
i32
);
mov_r_mem!
(
emit_cmove_r64_mem64
,
"cmove"
,
64
);
mov_r_r!
(
emit_cmovne_r64_r64
,
"cmovne"
,
64
);
mov_r_imm!
(
emit_cmovne_r64_imm32
,
"cmovne"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovne_r64_mem64
,
"cmovne"
,
64
);
mov_r_r!
(
emit_cmovg_r64_r64
,
"cmovg"
,
64
);
mov_r_imm!
(
emit_cmovg_r64_imm32
,
"cmovg"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovg_r64_mem64
,
"cmovg"
,
64
);
mov_r_r!
(
emit_cmovge_r64_r64
,
"cmovge"
,
64
);
mov_r_imm!
(
emit_cmovge_r64_imm32
,
"cmovge"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovge_r64_mem64
,
"cmovge"
,
64
);
mov_r_r!
(
emit_cmovl_r64_r64
,
"cmovl"
,
64
);
mov_r_imm!
(
emit_cmovl_r64_imm32
,
"cmovl"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovl_r64_mem64
,
"cmovl"
,
64
);
mov_r_r!
(
emit_cmovle_r64_r64
,
"cmovle"
,
64
);
mov_r_imm!
(
emit_cmovle_r64_imm32
,
"cmovle"
,
64
,
i32
);
mov_r_mem!
(
emit_cmovle_r64_mem64
,
"cmovle"
,
64
);
// lea
mov_r_mem!
(
emit_lea_r64
,
"lea"
,
64
);
...
...
src/compiler/backend/arch/x86_64/codegen.rs
View file @
97e188ad
...
...
@@ -73,6 +73,48 @@ pub trait CodeGenerator {
fn
emit_mov_mem8_r8
(
&
mut
self
,
dest
:
Mem
,
src
:
Reg
);
// store
fn
emit_mov_mem8_imm8
(
&
mut
self
,
dest
:
Mem
,
src
:
i8
);
// gpr conditional move
fn
emit_cmova_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmova_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmova_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovae_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovae_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovae_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovb_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovb_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovb_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovbe_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovbe_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovbe_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmove_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmove_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmove_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovg_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovg_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovg_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovge_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovge_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovge_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovl_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovl_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovl_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovle_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovle_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovle_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
fn
emit_cmovne_r64_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Reg
);
fn
emit_cmovne_r64_imm32
(
&
mut
self
,
dest
:
Reg
,
src
:
i32
);
fn
emit_cmovne_r64_mem64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
// load
// lea
fn
emit_lea_r64
(
&
mut
self
,
dest
:
Reg
,
src
:
Mem
);
...
...
src/compiler/backend/arch/x86_64/inst_sel.rs
View file @
97e188ad
...
...
@@ -180,7 +180,84 @@ impl <'a> InstructionSelection {
unimplemented!
();
}
},
Instruction_
::
Select
{
cond
,
true_val
,
false_val
}
=>
{
let
ops
=
inst
.ops
.read
()
.unwrap
();
let
ref
cond
=
ops
[
cond
];
let
ref
true_val
=
ops
[
true_val
];
let
ref
false_val
=
ops
[
false_val
];
if
self
.match_ireg
(
true_val
)
{
// moving integers/pointers
let
tmp_res
=
self
.get_result_value
(
node
);
let
tmp_true
=
self
.emit_ireg
(
true_val
,
f_content
,
f_context
,
vm
);
let
tmp_false
=
self
.emit_ireg
(
false_val
,
f_content
,
f_context
,
vm
);
if
self
.match_cmp_res
(
cond
)
{
match
self
.emit_cmp_res
(
cond
,
f_content
,
f_context
,
vm
)
{
op
::
CmpOp
::
EQ
=>
{
self
.backend
.emit_cmove_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovne_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
NE
=>
{
self
.backend
.emit_cmovne_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmove_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
SGE
=>
{
self
.backend
.emit_cmovge_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovl_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
SGT
=>
{
self
.backend
.emit_cmovg_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovle_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
SLE
=>
{
self
.backend
.emit_cmovle_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovg_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
SLT
=>
{
self
.backend
.emit_cmovl_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovge_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
UGE
=>
{
self
.backend
.emit_cmovae_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovb_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
UGT
=>
{
self
.backend
.emit_cmova_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovbe_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
ULE
=>
{
self
.backend
.emit_cmovbe_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmova_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
op
::
CmpOp
::
ULT
=>
{
self
.backend
.emit_cmovb_r64_r64
(
&
tmp_res
,
&
tmp_true
);
self
.backend
.emit_cmovae_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
_
=>
panic!
(
"expecting CmpOp for integers"
)
}
}
else
if
self
.match_ireg
(
cond
)
{
let
tmp_cond
=
self
.emit_ireg
(
cond
,
f_content
,
f_context
,
vm
);
// emit: cmp cond_reg 1
self
.backend
.emit_cmp_imm32_r64
(
1
,
&
tmp_cond
);
// emit: cmove tmp_true -> tmp_res
self
.backend
.emit_cmove_r64_r64
(
&
tmp_res
,
&
tmp_true
);
// emit: cmovne tmp_false -> tmp_res
self
.backend
.emit_cmovne_r64_r64
(
&
tmp_res
,
&
tmp_false
);
}
else
{
unimplemented!
()
}
}
else
{
// moving vectors, floatingpoints
unimplemented!
()
}
},
Instruction_
::
Branch1
(
ref
dest
)
=>
{
let
ops
=
inst
.ops
.read
()
.unwrap
();
...
...
tests/ir_macros.rs
View file @
97e188ad
...
...
@@ -165,6 +165,30 @@ macro_rules! inst {
});
};
// CMPOP
((
$vm
:
expr
,
$fv
:
ident
)
$name
:
ident
:
$value
:
ident
=
CMPOP
(
$op
:
expr
)
$op1
:
ident
$op2
:
ident
)
=>
{
let
$name
=
$fv
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
$vm
.next_id
()),
value
:
Some
(
vec!
[
$value
.clone_value
()]),
ops
:
RwLock
::
new
(
vec!
[
$op1
.clone
(),
$op2
.clone
()]),
v
:
Instruction_
::
CmpOp
(
$op
,
0
,
1
)
});
};
// SELECT
((
$vm
:
expr
,
$fv
:
ident
)
$name
:
ident
:
$value
:
ident
=
SELECT
$cond
:
ident
$op_true
:
ident
$op_false:ident
)
=>
{
let
$name
=
$fv
.new_inst
(
Instruction
{
hdr
:
MuEntityHeader
::
unnamed
(
$vm
.next_id
()),
value
:
Some
(
vec!
[
$value
.clone_value
()]),
ops
:
RwLock
::
new
(
vec!
[
$cond
.clone
(),
$op_true
.clone
(),
$op_false
.clone
()]),
v
:
Instruction_
::
Select
{
cond
:
0
,
true_val
:
1
,
false_val
:
2
}
});
};
// BRANCH
((
$vm
:
expr
,
$fv
:
ident
)
$name
:
ident
:
BRANCH
$dest
:
ident
(
$
(
$arg
:
ident
),
*
))
=>
{
let
$name
=
$fv
.new_inst
(
Instruction
{
...
...
tests/test_compiler/test_controlflow.rs
View file @
97e188ad
extern
crate
mu
;
extern
crate
log
;
extern
crate
libloading
;
use
self
::
mu
::
ast
::
types
::
*
;
use
self
::
mu
::
ast
::
ir
::
*
;
use
self
::
mu
::
ast
::
inst
::
*
;
use
self
::
mu
::
vm
::
*
;
use
self
::
mu
::
testutil
;
use
mu
::
ast
::
types
::
*
;
use
mu
::
ast
::
ir
::
*
;
use
mu
::
ast
::
inst
::
*
;
use
mu
::
ast
::
op
::
*
;
use
mu
::
vm
::
*
;
use
mu
::
testutil
;
use
std
::
sync
::
RwLock
;
...
...
@@ -203,5 +202,125 @@ fn switch() -> VM {
vm
.define_func_version
(
func_ver
);
vm
}
#[test]
fn
test_select_eq_zero
()
{
let
lib
=
testutil
::
compile_fnc
(
"select_eq_zero"
,
&
select_eq_zero
);
unsafe
{
let
select_eq_zero
:
libloading
::
Symbol
<
unsafe
extern
fn
(
u64
)
->
u64
>
=
lib
.get
(
b
"select_eq_zero"
)
.unwrap
();
let
res
=
select_eq_zero
(
0
);
println!
(
"select_eq_zero(0) = {}"
,
res
);
assert
!
(
res
==
1
);
let
res
=
select_eq_zero
(
1
);
println!
(
"select_eq_zero(1) = {}"
,
res
);
assert
!
(
res
==
0
);
}
}
fn
select_eq_zero
()
->
VM
{
let
vm
=
VM
::
new
();
typedef!
((
vm
)
int64
=
mu_int
(
64
));
typedef!
((
vm
)
int1
=
mu_int
(
1
));
constdef!
((
vm
)
<
int64
>
int64_0
=
Constant
::
Int
(
0
));
constdef!
((
vm
)
<
int64
>
int64_1
=
Constant
::
Int
(
1
));
funcsig!
((
vm
)
sig
=
(
int64
)
->
(
int64
));
funcdecl!
((
vm
)
<
sig
>
select_eq_zero
);
funcdef!
((
vm
)
<
sig
>
select_eq_zero
VERSION
select_v1
);
// blk entry
block!
((
vm
,
select_v1
)
blk_entry
);
ssa!
((
vm
,
select_v1
)
<
int64
>
blk_entry_n
);
ssa!
((
vm
,
select_v1
)
<
int1
>
blk_entry_cond
);
consta!
((
vm
,
select_v1
)
int64_0_local
=
int64_0
);
consta!
((
vm
,
select_v1
)
int64_1_local
=
int64_1
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_cmp
:
blk_entry_cond
=
CMPOP
(
CmpOp
::
EQ
)
blk_entry_n
int64_0_local
);
ssa!
((
vm
,
select_v1
)
<
int64
>
blk_entry_ret
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_select
:
blk_entry_ret
=
SELECT
blk_entry_cond
int64_1_local
int64_0_local
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_ret
:
RET
(
blk_entry_ret
)
);
define_block!
((
vm
,
select_v1
)
blk_entry
(
blk_entry_n
){
blk_entry_inst_cmp
,
blk_entry_inst_select
,
blk_entry_inst_ret
});
define_func_ver!
((
vm
)
select_v1
(
entry
:
blk_entry
)
{
blk_entry
});
vm
}
#[test]
fn
test_select_sge_zero
()
{
let
lib
=
testutil
::
compile_fnc
(
"select_sge_zero"
,
&
select_sge_zero
);
unsafe
{
let
select_sge_zero
:
libloading
::
Symbol
<
unsafe
extern
fn
(
i64
)
->
u64
>
=
lib
.get
(
b
"select_sge_zero"
)
.unwrap
();
let
res
=
select_sge_zero
(
0
);
println!
(
"select_sge_zero(0) = {}"
,
res
);
assert
!
(
res
==
1
);
let
res
=
select_sge_zero
(
1
);
println!
(
"select_sge_zero(1) = {}"
,
res
);
assert
!
(
res
==
1
);
let
res
=
select_sge_zero
(
-
1
);
println!
(
"select_sge_zero(-1) = {}"
,
res
);
assert
!
(
res
==
0
);
}
}
fn
select_sge_zero
()
->
VM
{
let
vm
=
VM
::
new
();
typedef!
((
vm
)
int64
=
mu_int
(
64
));
typedef!
((
vm
)
int1
=
mu_int
(
1
));
constdef!
((
vm
)
<
int64
>
int64_0
=
Constant
::
Int
(
0
));
constdef!
((
vm
)
<
int64
>
int64_1
=
Constant
::
Int
(
1
));
funcsig!
((
vm
)
sig
=
(
int64
)
->
(
int64
));
funcdecl!
((
vm
)
<
sig
>
select_sge_zero
);
funcdef!
((
vm
)
<
sig
>
select_sge_zero
VERSION
select_v1
);
// blk entry
block!
((
vm
,
select_v1
)
blk_entry
);
ssa!
((
vm
,
select_v1
)
<
int64
>
blk_entry_n
);
ssa!
((
vm
,
select_v1
)
<
int1
>
blk_entry_cond
);
consta!
((
vm
,
select_v1
)
int64_0_local
=
int64_0
);
consta!
((
vm
,
select_v1
)
int64_1_local
=
int64_1
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_cmp
:
blk_entry_cond
=
CMPOP
(
CmpOp
::
SGE
)
blk_entry_n
int64_0_local
);
ssa!
((
vm
,
select_v1
)
<
int64
>
blk_entry_ret
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_select
:
blk_entry_ret
=
SELECT
blk_entry_cond
int64_1_local
int64_0_local
);
inst!
((
vm
,
select_v1
)
blk_entry_inst_ret
:
RET
(
blk_entry_ret
)
);
define_block!
((
vm
,
select_v1
)
blk_entry
(
blk_entry_n
){
blk_entry_inst_cmp
,
blk_entry_inst_select
,
blk_entry_inst_ret
});
define_func_ver!
((
vm
)
select_v1
(
entry
:
blk_entry
)
{
blk_entry
});
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