Commit c3ba71ac authored by John Zhang's avatar John Zhang

Merge branch 'master' into ci-script

parents 00c57362 a241c754
**/target/*
**/__pycache__/*
**/.cache/*
emit/*
**/temp/*
Cargo.lock
......
......@@ -35,21 +35,21 @@ test:cargo:api:
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 CC=clang cargo test test_api
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_api
test:cargo:ir:
stage: test
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 CC=clang cargo test test_ir
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_ir
test:cargo:compiler:
stage: test
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 CC=clang cargo test test_compiler
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_compiler
test:cargo:runtime:
stage: test
......@@ -63,18 +63,27 @@ testjit:milestones:
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo build 2>/dev/null
- RUST_BACKTRACE=1 pytest tests/test_jit/test_milestones.py
testjit:binops:
stage: test
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_binops.py
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo build 2>/dev/null
- RUST_BACKTRACE=1 pytest tests/test_jit/test_binops.py
testjit:cmpops:
stage: test
dependencies:
- build_test
script:
- RUST_BACKTRACE=1 pytest tests/test_jit/test_cmpops.py
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo build 2>/dev/null
- RUST_BACKTRACE=1 pytest tests/test_jit/test_cmpops.py
testjit:cmpops:
stage: test
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo build 2>/dev/null
- RUST_BACKTRACE=1 pytest tests/test_jit/test_convops.py
\ No newline at end of file
......@@ -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
......
......@@ -91,6 +91,12 @@ pub enum Instruction_ {
BinOp(BinOp, OpIndex, OpIndex),
CmpOp(CmpOp, OpIndex, OpIndex),
ConvOp{
operation: ConvOp,
from_ty: P<MuType>,
to_ty: P<MuType>,
operand: OpIndex
},
// yields a tuple of results from the call
ExprCall{
......@@ -254,6 +260,9 @@ impl Instruction_ {
match self {
&Instruction_::BinOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
&Instruction_::CmpOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
&Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand])
}
&Instruction_::ExprCall{ref data, is_abort} => {
let abort = select_value!(is_abort, "ABORT_ON_EXN", "RETHROW");
format!("CALL {} {}", data.debug_str(ops), abort)
......
......@@ -4,6 +4,7 @@ use inst::*;
use op::*;
use utils::vec_utils;
use utils::Address;
use std::collections::HashMap;
use std::fmt;
......@@ -735,6 +736,8 @@ pub enum Constant {
FuncRef(MuID),
UFuncRef(MuID),
Vector(Vec<Constant>),
//Pointer(Address),
NullRef,
}
impl fmt::Display for Constant {
......@@ -756,6 +759,7 @@ impl fmt::Display for Constant {
}
write!(f, "]")
}
&Constant::NullRef => write!(f, "NullRef"),
}
}
}
......
......@@ -5,6 +5,7 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _)
| &CmpOp(_, _, _)
| &ConvOp{..}
| &ExprCall{..}
| &Load{..}
| &Store{..}
......@@ -49,6 +50,7 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _) => false,
&CmpOp(_, _, _) => false,
&ConvOp{..} => false,
&ExprCall{..} => true,
&Load{..} => true,
&Store{..} => true,
......
......@@ -35,6 +35,7 @@ pub enum OpCode {
// expression
Binary(BinOp),
Comparison(CmpOp),
Conversion(ConvOp),
AtomicRMW(AtomicRMWOp),
ExprCall,
......@@ -172,6 +173,22 @@ pub enum CmpOp {
FUNO
}
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ConvOp {
TRUNC,
ZEXT,
SEXT,
FPTRUNC,
FPEXT,
FPTOUI,
FPTOSI,
UITOFP,
SITOFP,
BITCAST,
REFCAST,
PTRCAST
}
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum AtomicRMWOp {
XCHG,
......@@ -207,6 +224,7 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
match inst.v {
Instruction_::BinOp(op, _, _) => OpCode::Binary(op),
Instruction_::CmpOp(op, _, _) => OpCode::Comparison(op),
Instruction_::ConvOp{operation, ..} => OpCode::Conversion(operation),
Instruction_::AtomicRMW{op, ..} => OpCode::AtomicRMW(op),
Instruction_::ExprCall{..} => OpCode::ExprCall,
Instruction_::Load{..} => OpCode::Load,
......
......@@ -12,6 +12,14 @@ lazy_static! {
pub static ref ADDRESS_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8))
);
pub static ref UINT8_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(8))
);
pub static ref UINT16_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(16))
);
pub static ref UINT32_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(32))
......@@ -27,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()
......
This diff is collapsed.
......@@ -62,14 +62,14 @@ lazy_static! {
pub static ref R13 : P<Value> = GPR!(13,"r13");
pub static ref R14 : P<Value> = GPR!(14,"r14");
pub static ref R15 : P<Value> = GPR!(15,"r15");
pub static ref RIP : P<Value> = GPR!(32,"rip");
pub static ref RETURN_GPRs : [P<Value>; 2] = [
RAX.clone(),
RDX.clone(),
];
pub static ref ARGUMENT_GPRs : [P<Value>; 6] = [
RDI.clone(),
RSI.clone(),
......@@ -78,7 +78,7 @@ lazy_static! {
R8.clone(),
R9.clone()
];
pub static ref CALLEE_SAVED_GPRs : [P<Value>; 6] = [
RBX.clone(),
RBP.clone(),
......@@ -99,7 +99,7 @@ lazy_static! {
R10.clone(),
R11.clone()
];
pub static ref ALL_GPRs : [P<Value>; 15] = [
RAX.clone(),
RCX.clone(),
......@@ -136,13 +136,13 @@ lazy_static!{
pub static ref XMM12 : P<Value> = FPR!(28,"xmm12");
pub static ref XMM13 : P<Value> = FPR!(29,"xmm13");
pub static ref XMM14 : P<Value> = FPR!(30,"xmm14");
pub static ref XMM15 : P<Value> = FPR!(31,"xmm15");
pub static ref XMM15 : P<Value> = FPR!(31,"xmm15");
pub static ref RETURN_FPRs : [P<Value>; 2] = [
XMM0.clone(),
XMM1.clone()
];
pub static ref ARGUMENT_FPRs : [P<Value>; 8] = [
XMM0.clone(),
XMM1.clone(),
......@@ -153,7 +153,7 @@ lazy_static!{
XMM6.clone(),
XMM7.clone()
];
pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = [];
pub static ref CALLER_SAVED_FPRs : [P<Value>; 16] = [
......@@ -174,7 +174,7 @@ lazy_static!{
XMM14.clone(),
XMM15.clone(),
];
pub static ref ALL_FPRs : [P<Value>; 16] = [
XMM0.clone(),
XMM1.clone(),
......@@ -234,10 +234,10 @@ lazy_static! {
map.insert(XMM14.id(), XMM14.clone());
map.insert(XMM15.id(), XMM15.clone());
map.insert(RIP.id(), RIP.clone());
map
};
// put caller saved regs first (they imposes no overhead if there is no call instruction)
pub static ref ALL_USABLE_MACHINE_REGs : Vec<P<Value>> = vec![
RAX.clone(),
......@@ -279,7 +279,7 @@ pub fn init_machine_regs_for_func (func_context: &mut FunctionContext) {
for reg in ALL_MACHINE_REGs.values() {
let reg_id = reg.extract_ssa_id().unwrap();
let entry = SSAVarEntry::new(reg.clone());
func_context.values.insert(reg_id, entry);
}
}
......@@ -320,8 +320,8 @@ pub fn is_callee_saved(reg_id: MuID) -> bool {
return true;
}
}
false
false
}
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
......@@ -332,4 +332,4 @@ pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
},
_ => false
}
}
}
\ No newline at end of file
......@@ -171,3 +171,30 @@ pub struct BackendTypeInfo {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum RegGroup {GPR, FPR}
impl RegGroup {
pub fn get(ty: &P<MuType>) -> RegGroup {
match ty.v {
// for now, only use 64bits registers
MuType_::Int(len) if len == 8 => RegGroup::GPR,
MuType_::Int(len) if len == 16 => RegGroup::GPR,
MuType_::Int(len) if len == 32 => RegGroup::GPR,
MuType_::Int(len) if len == 64 => RegGroup::GPR,
MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_)
| MuType_::UPtr(_)
| MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64
| MuType_::FuncRef(_)
| MuType_::UFuncPtr(_) => RegGroup::GPR,
MuType_::Float => RegGroup::FPR,
MuType_::Double => RegGroup::FPR,
_ => unimplemented!()
}
}
}
\ No newline at end of file
......@@ -54,18 +54,7 @@ impl InterferenceGraph {
self.nodes.insert(reg_id, node.clone());
// add node property
let group = {
let ref ty = entry.ty();
if types::is_scalar(ty) {
if types::is_fp(ty) {
backend::RegGroup::FPR
} else {
backend::RegGroup::GPR
}
} else {
unimplemented!()
}
};
let group = backend::RegGroup::get(entry.ty());
let property = NodeProperty {
color: None,
group: group,
......
......@@ -138,5 +138,28 @@ pub fn link_dylib (funcs: Vec<MuName>, out: &str) -> PathBuf {
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
pub fn link_dylib_with_extra_srcs(funcs: Vec<MuName>, srcs: Vec<String>, out: &str) -> PathBuf{
let files = {
let mut ret = vec![];
for func in funcs {
ret.push(get_path_for_mu_func(func));
}
for src in srcs {
ret.push(PathBuf::from(src));
}
ret.push(get_path_for_mu_context());
ret
};
let mut out_path = PathBuf::from(backend::AOT_EMIT_DIR);
out_path.push(out);
link_dylib_internal(files, out_path)
}
\ No newline at end of file
......@@ -24,13 +24,18 @@ pub fn get_test_clang_path() -> String {
pub fn exec (mut cmd: Command) -> Output {
println!("executing: {:?}", cmd);
let output = cmd.output().expect("failed to execute");
let output = match cmd.output() {
Ok(res) => res,
Err(e) => panic!("failed to execute: {}", e)
};
println!("---out---");
println!("{}", String::from_utf8_lossy(&output.stdout));
println!("---err---");
println!("{}", String::from_utf8_lossy(&output.stderr));
assert!(output.status.success());
output
}
......
......@@ -243,11 +243,13 @@ extern fn _forwarder__MuVM__set_trap_handler(mvm: *mut CMuVM, trap_handler: CMuT
};
}
extern fn _forwarder__MuVM__compile_to_sharedlib(mvm: *mut CMuVM, lib_name: CMuCString) {
extern fn _forwarder__MuVM__compile_to_sharedlib(mvm: *mut CMuVM, lib_name: CMuCString,
extra_srcs: *const CMuCString, n: usize) {
let mut _arg_mvm = from_MuVM_ptr(mvm);
let mut _arg_lib_name = from_MuCString(lib_name);
let _arg_extra_srcs = from_MuCString_array(extra_srcs, n);
unsafe {
(*_arg_mvm).compile_to_sharedlib(&_arg_lib_name)
(*_arg_mvm).compile_to_sharedlib(&_arg_lib_name, _arg_extra_srcs)
};
}
......
......@@ -110,7 +110,7 @@ pub struct CMuVM {
pub name_of: extern fn(*mut CMuVM, CMuID) -> CMuName,
pub set_trap_handler: extern fn(*mut CMuVM, CMuTrapHandler, CMuCPtr),
// this function is only used in testing jit
pub compile_to_sharedlib: extern fn(*mut CMuVM, CMuCString),
pub compile_to_sharedlib: extern fn(*mut CMuVM, CMuCString, *const CMuCString, CMuArraySize),
}
#[repr(C)]
......
......@@ -42,7 +42,10 @@ pub enum NodeType {
TypeStruct { id: MuID, fieldtys: Vec<MuTypeNode> },
TypeHybrid { id: MuID, fixedtys: Vec<MuTypeNode>, varty: MuTypeNode },
TypeArray { id: MuID, elemty: MuTypeNode, len: usize },
TypeVector { id: MuID, elemty: MuTypeNode, lem: usize },
TypeVector { id: MuID, elemty: MuTypeNode, len: usize },
TypeVoid { id: MuID },
TypeTagRef64 { id: MuID },
TypeRef { id: MuID, ty: MuTypeNode },
TypeIRef { id: MuID, ty: MuTypeNode },
......
This diff is collapsed.
......@@ -70,7 +70,7 @@ impl MuVM {
panic!("Not implemented")
}
pub fn compile_to_sharedlib(&self, lib_name: &str) {
pub fn compile_to_sharedlib(&self, lib_name: &str, extra_srcs: Vec<String>) {
extern crate libloading as ll;
use compiler::*;
......@@ -88,7 +88,7 @@ impl MuVM {
func_names.push(func.name().unwrap());
}
backend::emit_context(&self.vm);
aot::link_dylib(func_names, lib_name);
aot::link_dylib_with_extra_srcs(func_names, extra_srcs, lib_name);
}
}
......
......@@ -271,7 +271,7 @@ struct MuVM {
// Set handlers
void (*set_trap_handler)(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
void (*compile_to_sharedlib)(MuVM *mvm, MuCString lib_name);
void (*compile_to_sharedlib)(MuVM *mvm, MuCString lib_name, MuCString *extra_srcs, MuArraySize n_extra_srcs); /// MUAPIPARSER extra_srcs:array:n_extra_srcs
};
// A local context. It can only be used by one thread at a time. It holds many
......
......@@ -478,6 +478,15 @@ impl <'a> VM {
funcs.insert(func.id(), RwLock::new(func));
}
/// The IR builder needs to look-up the function signature from the existing function ID.
pub fn get_func_sig_for_func(&self, id: MuID) -> P<MuFuncSig> {
let funcs_lock = self.funcs.read().unwrap();
match funcs_lock.get(&id) {
Some(func) => func.read().unwrap().sig.clone(),
None => panic!("cannot find Mu function #{}", id)
}
}
pub fn define_func_version (&self, func_ver: MuFunctionVersion) {
info!("define function version {}", func_ver);
// record this version
......@@ -501,6 +510,72 @@ impl <'a> VM {
// redefinition happens here
// do stuff
}
/// Add a new bundle into VM.
///
/// This function will drain the contents of all arguments.
///
/// Ideally, this function should happen atomically. e.g. The client should not see a new type
/// added without also seeing a new function added.
pub fn declare_many(&self,
new_id_name_map: &mut HashMap<MuID, MuName>,
new_types: &mut HashMap<MuID, P<MuType>>,
new_func_sigs: &mut HashMap<MuID, P<MuFuncSig>>,
new_constants: &mut HashMap<MuID, P<Value>>,
new_globals: &mut HashMap<MuID, P<Value>>,
new_funcs: &mut HashMap<MuID, Box<MuFunction>>,
new_func_vers: &mut HashMap<MuID, Box<MuFunctionVersion>>
) {
// Make sure other components, if ever acquiring multiple locks at the same time, acquire
// them in this order, to prevent deadlock.
let mut id_name_map = self.id_name_map.write().unwrap();
let mut name_id_map = self.name_id_map.write().unwrap();
let mut types = self.types.write().unwrap();
let mut constants = self.constants.write().unwrap();
let mut globals = self.globals.write().unwrap();
let mut func_sigs = self.func_sigs.write().unwrap();
let mut funcs = self.funcs.write().unwrap();
let mut func_vers = self.func_vers.write().unwrap();
for (id, name) in new_id_name_map.drain() {
id_name_map.insert(id, name.clone());
name_id_map.insert(name, id);
}
for (id, obj) in new_types.drain() {
types.insert(id, obj);
}
for (id, obj) in new_constants.drain() {
constants.insert(id, obj);
}
for (id, obj) in new_globals.drain() {
globals.insert(id, obj);
}
for (id, obj) in new_func_sigs.drain() {
func_sigs.insert(id, obj);
}
for (id, obj) in new_funcs.drain() {
funcs.insert(id, RwLock::new(*obj));
}
for (id, obj) in new_func_vers.drain() {
let func_id = obj.func_id;
func_vers.insert(id, RwLock::new(*obj));
{
trace!("Adding funcver {} as a version of {}...", id, func_id);
let func = funcs.get_mut(&func_id).unwrap();
func.write().unwrap().new_version(id);
trace!("Added funcver {} as a version of {} {:?}.", id, func_id, func);
}
}
// Locks released here
}
pub fn add_compiled_func (&self, func: CompiledFunction) {
debug_assert!(self.funcs.read().unwrap().contains_key(&func.func_id));
......
......@@ -173,5 +173,175 @@ fn sdiv() -> VM {
vm.define_func_version(func_ver);
vm
}
#[test]
fn test_shl() {
let lib = testutil::compile_fnc("shl", &shl);
unsafe {
let shl : libloading::Symbol<unsafe extern fn(u64, u8) -> u64> = lib.get(b"shl").unwrap();
let shl_1_2 = shl(1, 2);
println!("shl(1, 2) = {}", shl_1_2);
assert!(shl_1_2 == 4);
let shl_2_2 = shl(2, 2);
println!("shl(2, 2) = {}", shl_2_2);
assert!(shl_2_2 == 8);
}
}
fn shl() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
let type_def_int64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_int64.as_entity(), Mu("int64"));
// .typedef @int8 = int<8>
let type_def_int8 = vm.declare_type(vm.next_id(), MuType_::int(8));
vm.set_name(type_def_int8.as_entity(), Mu("int8"));
// .funcsig @shl_sig = (@int64 @int8) -> (@int64)
let shl_sig = vm.declare_func_sig(vm.next_id(), vec![type_def_int64.clone()], vec![type_def_int64.clone(), type_def_int8.clone()]);
vm.set_name(shl_sig.as_entity(), Mu("shl_sig"));
// .funcdecl @shl <@shl_sig>
let func_id = vm.next_id();
let func = MuFunction::new(func_id, shl_sig.clone());
vm.set_name(func.as_entity(), Mu("shl"));
vm.declare_func(func);
// .funcdef @shl VERSION @shl_v1 <@shl_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, shl_sig.clone());
vm.set_name(func_ver.as_entity(), Mu("shl_v1"));
// %entry(<@int64> %a, <@int8> %b):
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_int64.clone());
vm.set_name(blk_entry_a.as_entity(), Mu("blk_entry_a"));
let blk_entry_b = func_ver.new_ssa(vm.next_id(), type_def_int8.clone());
vm.set_name(blk_entry_b.as_entity(), Mu("blk_entry_b"));
// %r = SHL %a %b
let blk_entry_r = func_ver.new_ssa(vm.next_id(), type_def_int64.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(), blk_entry_b.clone()]),
v: Instruction_::BinOp(BinOp::Shl, 0, 1)
});
// 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(), blk_entry_b.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
}
#[test]
fn test_lshr() {
let lib = testutil::compile_fnc("lshr", &lshr);
unsafe {
let lshr : libloading::Symbol<unsafe extern fn(u64, u8) -> u64> = lib.get(b"lshr").unwrap();
let lshr_8_3 = lshr(8, 3);
println!("lshr(8, 3) = {}", lshr_8_3);
assert!(lshr_8_3 == 1);
}
}
fn lshr() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
let type_def_int64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_int64.as_entity(), Mu("int64"));
// .typedef @int8 = int<8>
let type_def_int8 = vm.declare_type(vm.next_id(), MuType_::int(8));
vm.set_name(type_def_int8.as_entity(), Mu("int8"));
// .funcsig @lshr_sig = (@int64 @int8) -> (@int64)
let lshr_sig = vm.declare_func_sig(vm.next_id(), vec![type_def_int64.clone()], vec![type_def_int64.clone(), type_def_int8.clone()]);
vm.set_name(lshr_sig.as_entity(), Mu("lshr_sig"));
// .funcdecl @lshr <@lshr_sig>
let func_id = vm.next_id();
let func = MuFunction::new(func_id, lshr_sig.clone());
vm.set_name(func.as_entity(), Mu("lshr"));
vm.declare_func(func);