mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Ops for sqrt and round
This commit is contained in:
parent
9f8c48118f
commit
1c98248b91
6 changed files with 221 additions and 163 deletions
|
@ -54,6 +54,7 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
|
||||||
Symbol::LIST_GET => list_get,
|
Symbol::LIST_GET => list_get,
|
||||||
Symbol::LIST_SET => list_set,
|
Symbol::LIST_SET => list_set,
|
||||||
Symbol::LIST_FIRST => list_first,
|
Symbol::LIST_FIRST => list_first,
|
||||||
|
Symbol::LIST_IS_EMPTY => list_is_empty,
|
||||||
Symbol::NUM_ADD => num_add,
|
Symbol::NUM_ADD => num_add,
|
||||||
Symbol::NUM_SUB => num_sub,
|
Symbol::NUM_SUB => num_sub,
|
||||||
Symbol::NUM_MUL => num_mul,
|
Symbol::NUM_MUL => num_mul,
|
||||||
|
@ -68,6 +69,8 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
|
||||||
Symbol::NUM_ABS => num_abs,
|
Symbol::NUM_ABS => num_abs,
|
||||||
Symbol::NUM_NEG => num_neg,
|
Symbol::NUM_NEG => num_neg,
|
||||||
Symbol::NUM_REM => num_rem,
|
Symbol::NUM_REM => num_rem,
|
||||||
|
Symbol::NUM_SQRT => num_sqrt,
|
||||||
|
Symbol::NUM_ROUND => num_round,
|
||||||
Symbol::NUM_IS_ODD => num_is_odd,
|
Symbol::NUM_IS_ODD => num_is_odd,
|
||||||
Symbol::NUM_IS_EVEN => num_is_even,
|
Symbol::NUM_IS_EVEN => num_is_even,
|
||||||
Symbol::NUM_IS_ZERO => num_is_zero,
|
Symbol::NUM_IS_ZERO => num_is_zero,
|
||||||
|
@ -80,11 +83,12 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
|
||||||
fn bool_eq(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn bool_eq(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::BOOL_BINOP_LHS)),
|
(bool_var, Var(Symbol::BOOL_BINOP_LHS)),
|
||||||
(var_store.fresh(), Var(Symbol::BOOL_BINOP_RHS)),
|
(bool_var, Var(Symbol::BOOL_BINOP_RHS)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
};
|
};
|
||||||
|
@ -101,11 +105,12 @@ fn bool_eq(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn bool_neq(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn bool_neq(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::BOOL_BINOP_LHS)),
|
(bool_var, Var(Symbol::BOOL_BINOP_LHS)),
|
||||||
(var_store.fresh(), Var(Symbol::BOOL_BINOP_RHS)),
|
(bool_var, Var(Symbol::BOOL_BINOP_RHS)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
};
|
};
|
||||||
|
@ -254,7 +259,7 @@ fn num_cos(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
/// Num.tan : Float -> Float
|
/// Num.tan : Float -> Float
|
||||||
fn num_tan(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_tan(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::NumDivUnsafe,
|
op: LowLevel::NumDivUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(
|
(
|
||||||
var_store.fresh(),
|
var_store.fresh(),
|
||||||
|
@ -287,11 +292,12 @@ fn num_tan(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
|
||||||
/// Num.isZero : Float -> Bool
|
/// Num.isZero : Float -> Bool
|
||||||
fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(bool_var, Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Num(var_store.fresh(), 0)),
|
(bool_var, Num(var_store.fresh(), 0)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
};
|
};
|
||||||
|
@ -333,13 +339,15 @@ fn num_is_positive(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
|
(bool_var, Int(var_store.fresh(), 1)),
|
||||||
(
|
(
|
||||||
var_store.fresh(),
|
bool_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumRemUnsafe,
|
op: LowLevel::NumRemUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(var_store.fresh(), Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 2)),
|
(var_store.fresh(), Int(var_store.fresh(), 2)),
|
||||||
|
@ -347,7 +355,6 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 1)),
|
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
};
|
};
|
||||||
|
@ -359,13 +366,15 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
|
(bool_var, Int(var_store.fresh(), 0)),
|
||||||
(
|
(
|
||||||
var_store.fresh(),
|
bool_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumRemUnsafe,
|
op: LowLevel::NumRemUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(var_store.fresh(), Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 2)),
|
(var_store.fresh(), Int(var_store.fresh(), 2)),
|
||||||
|
@ -373,7 +382,54 @@ fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 0)),
|
],
|
||||||
|
ret_var: var_store.fresh(),
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(symbol, vec![Symbol::ARG_1], var_store, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.sqrt : Float -> Result Float [ SqrtOfNegative ]*
|
||||||
|
fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let body = RunLowLevel {
|
||||||
|
op: LowLevel::NumSqrt,
|
||||||
|
args: vec![(var_store.fresh(), Var(Symbol::ARG_1))],
|
||||||
|
ret_var: var_store.fresh(),
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(symbol, vec![Symbol::ARG_1], var_store, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.round : Float -> Int
|
||||||
|
fn num_round(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let body = RunLowLevel {
|
||||||
|
op: LowLevel::NumRound,
|
||||||
|
args: vec![(var_store.fresh(), Var(Symbol::ARG_1))],
|
||||||
|
ret_var: var_store.fresh(),
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(symbol, vec![Symbol::ARG_1], var_store, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List.isEmpty : List * -> Bool
|
||||||
|
fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
|
let body = RunLowLevel {
|
||||||
|
op: LowLevel::Eq,
|
||||||
|
args: vec![
|
||||||
|
(bool_var, Num(var_store.fresh(), 0)),
|
||||||
|
(
|
||||||
|
bool_var,
|
||||||
|
RunLowLevel {
|
||||||
|
op: LowLevel::ListLen,
|
||||||
|
args: vec![(var_store.fresh(), Var(Symbol::ARG_1))],
|
||||||
|
ret_var: var_store.fresh(),
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
};
|
};
|
||||||
|
@ -383,29 +439,22 @@ fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
|
||||||
/// List.len : List * -> Int
|
/// List.len : List * -> Int
|
||||||
fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_len(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
let body = RunLowLevel {
|
||||||
|
op: LowLevel::ListLen,
|
||||||
|
args: vec![(var_store.fresh(), Var(Symbol::ARG_1))],
|
||||||
|
ret_var: var_store.fresh(),
|
||||||
|
};
|
||||||
|
|
||||||
// Polymorphic wrapper around LowLevel::ListLen
|
defn(symbol, vec![Symbol::ARG_1], var_store, body)
|
||||||
let arg = Symbol::LIST_LEN_ARG;
|
|
||||||
let arg_var = var_store.fresh();
|
|
||||||
let ret_var = var_store.fresh();
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![arg],
|
|
||||||
var_store,
|
|
||||||
RunLowLevel {
|
|
||||||
op: LowLevel::ListLen,
|
|
||||||
args: vec![(arg_var, Var(arg))],
|
|
||||||
ret_var,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.get : List elem, Int -> Result elem [ OutOfBounds ]*
|
/// List.get : List elem, Int -> Result elem [ OutOfBounds ]*
|
||||||
fn list_get(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_get(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let arg_list = Symbol::ARG_1;
|
||||||
|
let arg_index = Symbol::ARG_2;
|
||||||
|
|
||||||
// Perform a bounds check. If it passes, run LowLevel::ListGetUnsafe
|
// Perform a bounds check. If it passes, run LowLevel::ListGetUnsafe
|
||||||
let body = If {
|
let body = If {
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
|
@ -417,12 +466,12 @@ fn list_get(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumLt,
|
op: LowLevel::NumLt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::LIST_GET_ARG_INDEX)),
|
(var_store.fresh(), Var(arg_index)),
|
||||||
(
|
(
|
||||||
var_store.fresh(),
|
var_store.fresh(),
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListLen,
|
op: LowLevel::ListLen,
|
||||||
args: vec![(var_store.fresh(), Var(Symbol::LIST_GET_ARG_LIST))],
|
args: vec![(var_store.fresh(), Var(arg_list))],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -440,8 +489,8 @@ fn list_get(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListGetUnsafe,
|
op: LowLevel::ListGetUnsafe,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::LIST_GET_ARG_LIST)),
|
(var_store.fresh(), Var(arg_list)),
|
||||||
(var_store.fresh(), Var(Symbol::LIST_GET_ARG_INDEX)),
|
(var_store.fresh(), Var(arg_index)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
|
@ -463,19 +512,18 @@ fn list_get(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
defn(
|
defn(symbol, vec![Symbol::ARG_1, Symbol::ARG_2], var_store, body)
|
||||||
symbol,
|
|
||||||
vec![Symbol::LIST_GET_ARG_LIST, Symbol::LIST_GET_ARG_INDEX],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.set : List elem, Int, elem -> List elem
|
/// List.set : List elem, Int, elem -> List elem
|
||||||
fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
// Perform a bounds check. If it passes, run LowLevel::ListSetUnsafe.
|
let arg_list = Symbol::ARG_1;
|
||||||
|
let arg_index = Symbol::ARG_2;
|
||||||
|
let arg_elem = Symbol::ARG_3;
|
||||||
|
|
||||||
|
// Perform a bounds check. If it passes, run LowLevel::ListSet.
|
||||||
// Otherwise, return the list unmodified.
|
// Otherwise, return the list unmodified.
|
||||||
let body = If {
|
let body = If {
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
|
@ -487,12 +535,12 @@ fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumLt,
|
op: LowLevel::NumLt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::LIST_GET_ARG_INDEX)),
|
(var_store.fresh(), Var(arg_index)),
|
||||||
(
|
(
|
||||||
var_store.fresh(),
|
var_store.fresh(),
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListLen,
|
op: LowLevel::ListLen,
|
||||||
args: vec![(var_store.fresh(), Var(Symbol::LIST_GET_ARG_LIST))],
|
args: vec![(var_store.fresh(), Var(arg_list))],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -504,11 +552,11 @@ fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
no_region(
|
no_region(
|
||||||
// List.setUnsafe list index
|
// List.setUnsafe list index
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListSetUnsafe,
|
op: LowLevel::ListSet,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::LIST_SET_ARG_LIST)),
|
(var_store.fresh(), Var(arg_list)),
|
||||||
(var_store.fresh(), Var(Symbol::LIST_SET_ARG_INDEX)),
|
(var_store.fresh(), Var(arg_index)),
|
||||||
(var_store.fresh(), Var(Symbol::LIST_SET_ARG_ELEM)),
|
(var_store.fresh(), Var(arg_elem)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
|
@ -516,13 +564,13 @@ fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)],
|
)],
|
||||||
final_else: Box::new(
|
final_else: Box::new(
|
||||||
// else-branch
|
// else-branch
|
||||||
no_region(Var(Symbol::LIST_SET_ARG_LIST)),
|
no_region(Var(arg_list)),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
defn(
|
defn(
|
||||||
symbol,
|
symbol,
|
||||||
vec![Symbol::LIST_GET_ARG_LIST, Symbol::LIST_GET_ARG_INDEX],
|
vec![Symbol::ARG_1, Symbol::ARG_2, Symbol::ARG_3],
|
||||||
var_store,
|
var_store,
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
@ -532,6 +580,7 @@ fn list_set(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = If {
|
let body = If {
|
||||||
branch_var: var_store.fresh(),
|
branch_var: var_store.fresh(),
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
|
@ -542,8 +591,8 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_2)),
|
(bool_var, Var(Symbol::ARG_2)),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 0)),
|
(bool_var, Int(var_store.fresh(), 0)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
|
@ -556,7 +605,7 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
vec![
|
vec![
|
||||||
// Num.#remUnsafe arg0 arg1
|
// Num.#remUnsafe arg0 arg1
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumRemUnsafe,
|
op: LowLevel::NumRemUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(var_store.fresh(), Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Var(Symbol::ARG_2)),
|
(var_store.fresh(), Var(Symbol::ARG_2)),
|
||||||
|
@ -632,6 +681,7 @@ fn num_abs(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
let body = If {
|
let body = If {
|
||||||
branch_var: var_store.fresh(),
|
branch_var: var_store.fresh(),
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
|
@ -642,8 +692,8 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(bool_var, Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 0)),
|
(bool_var, Int(var_store.fresh(), 0)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
|
@ -656,7 +706,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
vec![
|
vec![
|
||||||
// Num.#divUnsafe numerator denominator
|
// Num.#divUnsafe numerator denominator
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumDivUnsafe,
|
op: LowLevel::NumDivUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::ARG_1)),
|
(var_store.fresh(), Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Var(Symbol::ARG_2)),
|
(var_store.fresh(), Var(Symbol::ARG_2)),
|
||||||
|
@ -697,7 +747,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
// List.isEmpty list
|
// List.isEmpty list
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListIsEmpty,
|
op: LowLevel::ListIsEmpty,
|
||||||
args: vec![(var_store.fresh(), Var(Symbol::LIST_FIRST_ARG))],
|
args: vec![(var_store.fresh(), Var(Symbol::ARG_1))],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -722,7 +772,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::ListGetUnsafe,
|
op: LowLevel::ListGetUnsafe,
|
||||||
args: vec![
|
args: vec![
|
||||||
(var_store.fresh(), Var(Symbol::LIST_GET_ARG_LIST)),
|
(var_store.fresh(), Var(Symbol::ARG_1)),
|
||||||
(var_store.fresh(), Int(var_store.fresh(), 0)),
|
(var_store.fresh(), Int(var_store.fresh(), 0)),
|
||||||
],
|
],
|
||||||
ret_var: var_store.fresh(),
|
ret_var: var_store.fresh(),
|
||||||
|
@ -734,7 +784,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
defn(symbol, vec![Symbol::LIST_FIRST_ARG], var_store, body)
|
defn(symbol, vec![Symbol::ARG_1], var_store, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -1017,21 +1017,10 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
parent: FunctionValue<'ctx>,
|
_parent: FunctionValue<'ctx>,
|
||||||
args: &[(BasicValueEnum<'ctx>, &'a Layout<'a>)],
|
args: &[(BasicValueEnum<'ctx>, &'a Layout<'a>)],
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
match symbol {
|
match symbol {
|
||||||
Symbol::NUM_MUL => {
|
|
||||||
debug_assert!(args.len() == 2);
|
|
||||||
|
|
||||||
let int_val = env.builder.build_int_mul(
|
|
||||||
args[0].0.into_int_value(),
|
|
||||||
args[1].0.into_int_value(),
|
|
||||||
"mul_i64",
|
|
||||||
);
|
|
||||||
|
|
||||||
BasicValueEnum::IntValue(int_val)
|
|
||||||
}
|
|
||||||
Symbol::NUM_TO_FLOAT => {
|
Symbol::NUM_TO_FLOAT => {
|
||||||
// TODO specialize this to be not just for i64!
|
// TODO specialize this to be not just for i64!
|
||||||
let builtin_fn_name = "i64_to_f64_";
|
let builtin_fn_name = "i64_to_f64_";
|
||||||
|
@ -1057,10 +1046,6 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||||
.left()
|
.left()
|
||||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call for builtin {:?}", symbol))
|
.unwrap_or_else(|| panic!("LLVM error: Invalid call for builtin {:?}", symbol))
|
||||||
}
|
}
|
||||||
Symbol::NUM_SQRT => call_intrinsic(LLVM_SQRT_F64, env, args),
|
|
||||||
Symbol::NUM_ROUND => call_intrinsic(LLVM_LROUND_I64_F64, env, args),
|
|
||||||
Symbol::LIST_SET => list_set(parent, args, env, InPlace::Clone),
|
|
||||||
Symbol::LIST_SET_IN_PLACE => list_set(parent, args, env, InPlace::InPlace),
|
|
||||||
Symbol::LIST_SINGLE => {
|
Symbol::LIST_SINGLE => {
|
||||||
// List.single : a -> List a
|
// List.single : a -> List a
|
||||||
debug_assert!(args.len() == 1);
|
debug_assert!(args.len() == 1);
|
||||||
|
@ -1311,7 +1296,7 @@ fn list_set<'a, 'ctx, 'env>(
|
||||||
// List.set : List elem, Int, elem -> List elem
|
// List.set : List elem, Int, elem -> List elem
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
debug_assert!(args.len() == 3);
|
debug_assert_eq!(args.len(), 3);
|
||||||
|
|
||||||
let original_wrapper = args[0].0.into_struct_value();
|
let original_wrapper = args[0].0.into_struct_value();
|
||||||
let elem_index = args[1].0.into_int_value();
|
let elem_index = args[1].0.into_int_value();
|
||||||
|
@ -1414,7 +1399,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
BasicValueEnum::IntValue(answer)
|
BasicValueEnum::IntValue(answer)
|
||||||
}
|
}
|
||||||
NumAbs | NumNeg => {
|
NumAbs | NumNeg | NumRound | NumSqrt => {
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
let arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
|
let arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
|
||||||
|
@ -1445,7 +1430,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumSin | NumCos
|
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumSin | NumCos
|
||||||
| NumRemUnsafe | NumDivUnsafe => {
|
| NumRemUnchecked | NumDivUnchecked => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let lhs_arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
|
let lhs_arg = build_expr(env, layout_ids, scope, parent, &args[0].0);
|
||||||
|
@ -1576,9 +1561,44 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListSetUnsafe => {
|
ListSet => list_set(
|
||||||
todo!("re-implement List#setUnsafe");
|
parent,
|
||||||
}
|
&[
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[0].0),
|
||||||
|
&args[0].1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[1].0),
|
||||||
|
&args[1].1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[2].0),
|
||||||
|
&args[2].1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
env,
|
||||||
|
InPlace::Clone,
|
||||||
|
),
|
||||||
|
ListSetInPlace => list_set(
|
||||||
|
parent,
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[0].0),
|
||||||
|
&args[0].1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[1].0),
|
||||||
|
&args[1].1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
build_expr(env, layout_ids, scope, parent, &args[2].0),
|
||||||
|
&args[2].1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
env,
|
||||||
|
InPlace::InPlace,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1603,8 +1623,8 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
||||||
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
|
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
|
||||||
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
||||||
NumRemUnsafe => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
|
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
|
||||||
NumDivUnsafe => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Unrecognized int binary operation: {:?}", op);
|
unreachable!("Unrecognized int binary operation: {:?}", op);
|
||||||
}
|
}
|
||||||
|
@ -1632,8 +1652,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
||||||
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
||||||
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
||||||
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
|
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
|
||||||
NumRemUnsafe => bd.build_float_rem(lhs, rhs, "rem_float").into(),
|
NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(),
|
||||||
NumDivUnsafe => bd.build_float_div(lhs, rhs, "div_float").into(),
|
NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(),
|
||||||
|
|
||||||
// Float-specific ops
|
// Float-specific ops
|
||||||
NumSin => call_intrinsic(
|
NumSin => call_intrinsic(
|
||||||
|
@ -1686,6 +1706,8 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
||||||
match op {
|
match op {
|
||||||
NumAdd => bd.build_float_neg(arg, "negate_float").into(),
|
NumAdd => bd.build_float_neg(arg, "negate_float").into(),
|
||||||
NumAbs => call_intrinsic(LLVM_FABS_F64, env, &[(arg.into(), arg_layout)]),
|
NumAbs => call_intrinsic(LLVM_FABS_F64, env, &[(arg.into(), arg_layout)]),
|
||||||
|
NumSqrt => call_intrinsic(LLVM_SQRT_F64, env, &[(arg.into(), arg_layout)]),
|
||||||
|
NumRound => call_intrinsic(LLVM_LROUND_I64_F64, env, &[(arg.into(), arg_layout)]),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Unrecognized int unary operation: {:?}", op);
|
unreachable!("Unrecognized int unary operation: {:?}", op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
pub enum LowLevel {
|
pub enum LowLevel {
|
||||||
ListLen,
|
ListLen,
|
||||||
ListGetUnsafe,
|
ListGetUnsafe,
|
||||||
ListSetUnsafe,
|
ListSet,
|
||||||
|
ListSetInPlace,
|
||||||
ListIsEmpty,
|
ListIsEmpty,
|
||||||
NumAdd,
|
NumAdd,
|
||||||
NumSub,
|
NumSub,
|
||||||
|
@ -14,12 +15,14 @@ pub enum LowLevel {
|
||||||
NumGte,
|
NumGte,
|
||||||
NumLt,
|
NumLt,
|
||||||
NumLte,
|
NumLte,
|
||||||
NumDivUnsafe,
|
NumDivUnchecked,
|
||||||
NumRemUnsafe,
|
NumRemUnchecked,
|
||||||
NumAbs,
|
NumAbs,
|
||||||
NumNeg,
|
NumNeg,
|
||||||
NumSin,
|
NumSin,
|
||||||
NumCos,
|
NumCos,
|
||||||
|
NumSqrt,
|
||||||
|
NumRound,
|
||||||
Eq,
|
Eq,
|
||||||
NotEq,
|
NotEq,
|
||||||
And,
|
And,
|
||||||
|
|
|
@ -644,23 +644,15 @@ define_builtins! {
|
||||||
1 LIST_AT_LIST: "@List" // the List.@List private tag
|
1 LIST_AT_LIST: "@List" // the List.@List private tag
|
||||||
2 LIST_IS_EMPTY: "isEmpty"
|
2 LIST_IS_EMPTY: "isEmpty"
|
||||||
3 LIST_GET: "get"
|
3 LIST_GET: "get"
|
||||||
4 LIST_GET_ARG_LIST: "get#list"
|
4 LIST_SET: "set"
|
||||||
5 LIST_GET_ARG_INDEX: "get#index"
|
5 LIST_PUSH: "push"
|
||||||
6 LIST_SET: "set"
|
6 LIST_MAP: "map"
|
||||||
7 LIST_SET_IN_PLACE: "#setInPlace"
|
7 LIST_LEN: "len"
|
||||||
8 LIST_PUSH: "push"
|
8 LIST_FOLDL: "foldl"
|
||||||
9 LIST_MAP: "map"
|
9 LIST_FOLDR: "foldr"
|
||||||
10 LIST_LEN: "len"
|
10 LIST_CONCAT: "concat"
|
||||||
11 LIST_LEN_ARG: "len#list"
|
11 LIST_FIRST: "first"
|
||||||
12 LIST_FOLDL: "foldl"
|
12 LIST_SINGLE: "single"
|
||||||
13 LIST_FOLDR: "foldr"
|
|
||||||
14 LIST_CONCAT: "concat"
|
|
||||||
15 LIST_FIRST: "first"
|
|
||||||
16 LIST_FIRST_ARG: "first#list"
|
|
||||||
17 LIST_SINGLE: "single"
|
|
||||||
18 LIST_SET_ARG_LIST: "set#list"
|
|
||||||
19 LIST_SET_ARG_INDEX: "set#index"
|
|
||||||
20 LIST_SET_ARG_ELEM: "set#elem"
|
|
||||||
}
|
}
|
||||||
5 RESULT: "Result" => {
|
5 RESULT: "Result" => {
|
||||||
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
||||||
|
|
|
@ -514,6 +514,7 @@ fn from_can<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
RunLowLevel { op, args, .. } => {
|
RunLowLevel { op, args, .. } => {
|
||||||
|
let op = optimize_low_level(env.subs, op, &args);
|
||||||
let mut mono_args = Vec::with_capacity_in(args.len(), env.arena);
|
let mut mono_args = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
for (arg_var, arg_expr) in args {
|
for (arg_var, arg_expr) in args {
|
||||||
|
@ -535,64 +536,15 @@ fn from_can<'a>(
|
||||||
Expr::Load(proc_name) => {
|
Expr::Load(proc_name) => {
|
||||||
// Some functions can potentially mutate in-place.
|
// Some functions can potentially mutate in-place.
|
||||||
// If we have one of those, switch to the in-place version if appropriate.
|
// If we have one of those, switch to the in-place version if appropriate.
|
||||||
match proc_name {
|
call_by_name(
|
||||||
Symbol::LIST_SET => {
|
env,
|
||||||
let subs = &env.subs;
|
procs,
|
||||||
// The first arg is the one with the List in it.
|
fn_var,
|
||||||
// List.set : List elem, Int, elem -> List elem
|
ret_var,
|
||||||
let (list_arg_var, _) = loc_args.get(0).unwrap();
|
proc_name,
|
||||||
|
loc_args,
|
||||||
let content = subs.get_without_compacting(*list_arg_var).content;
|
layout_cache,
|
||||||
|
)
|
||||||
match content {
|
|
||||||
Content::Structure(FlatType::Apply(
|
|
||||||
Symbol::ATTR_ATTR,
|
|
||||||
attr_args,
|
|
||||||
)) => {
|
|
||||||
debug_assert!(attr_args.len() == 2);
|
|
||||||
|
|
||||||
// If the first argument (the List) is unique,
|
|
||||||
// then we can safely upgrade to List.set_in_place
|
|
||||||
let attr_arg_content =
|
|
||||||
subs.get_without_compacting(attr_args[0]).content;
|
|
||||||
|
|
||||||
let new_name = if attr_arg_content.is_unique(subs) {
|
|
||||||
Symbol::LIST_SET_IN_PLACE
|
|
||||||
} else {
|
|
||||||
Symbol::LIST_SET
|
|
||||||
};
|
|
||||||
|
|
||||||
call_by_name(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
fn_var,
|
|
||||||
ret_var,
|
|
||||||
new_name,
|
|
||||||
loc_args,
|
|
||||||
layout_cache,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => call_by_name(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
fn_var,
|
|
||||||
ret_var,
|
|
||||||
proc_name,
|
|
||||||
loc_args,
|
|
||||||
layout_cache,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
specialized_proc_symbol => call_by_name(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
fn_var,
|
|
||||||
ret_var,
|
|
||||||
specialized_proc_symbol,
|
|
||||||
loc_args,
|
|
||||||
layout_cache,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ptr => {
|
ptr => {
|
||||||
// Call by pointer - the closure was anonymous, e.g.
|
// Call by pointer - the closure was anonymous, e.g.
|
||||||
|
@ -1783,3 +1735,41 @@ fn from_can_record_destruct<'a>(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Potentially translate LowLevel operations into more efficient ones based on
|
||||||
|
/// uniqueness type info.
|
||||||
|
///
|
||||||
|
/// For example, turning LowLevel::ListSet to LowLevel::ListSetInPlace if the
|
||||||
|
/// list is Unique.
|
||||||
|
fn optimize_low_level(
|
||||||
|
subs: &Subs,
|
||||||
|
op: LowLevel,
|
||||||
|
args: &[(Variable, roc_can::expr::Expr)],
|
||||||
|
) -> LowLevel {
|
||||||
|
match op {
|
||||||
|
LowLevel::ListSet => {
|
||||||
|
// The first arg is the one with the List in it.
|
||||||
|
// List.set : List elem, Int, elem -> List elem
|
||||||
|
let list_arg_var = args[0].0;
|
||||||
|
let content = subs.get_without_compacting(list_arg_var).content;
|
||||||
|
|
||||||
|
match content {
|
||||||
|
Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => {
|
||||||
|
debug_assert_eq!(attr_args.len(), 2);
|
||||||
|
|
||||||
|
// If the first argument (the List) is unique,
|
||||||
|
// then we can safely upgrade to List.set_in_place
|
||||||
|
let attr_arg_content = subs.get_without_compacting(attr_args[0]).content;
|
||||||
|
|
||||||
|
if attr_arg_content.is_unique(subs) {
|
||||||
|
LowLevel::ListSetInPlace
|
||||||
|
} else {
|
||||||
|
LowLevel::ListSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => op,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => op,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -733,7 +733,7 @@ fn annotate_low_level_usage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListSetUnsafe => {
|
ListSet | ListSetInPlace => {
|
||||||
match &args[0].1 {
|
match &args[0].1 {
|
||||||
Var(list_var) => {
|
Var(list_var) => {
|
||||||
usage.register_with(
|
usage.register_with(
|
||||||
|
@ -756,7 +756,8 @@ fn annotate_low_level_usage(
|
||||||
}
|
}
|
||||||
|
|
||||||
NumAdd | NumSub | NumMul | NumGt | NumGte | NumLt | NumLte | NumAbs | NumNeg
|
NumAdd | NumSub | NumMul | NumGt | NumGte | NumLt | NumLte | NumAbs | NumNeg
|
||||||
| NumDivUnsafe | NumRemUnsafe | NumSin | NumCos | Eq | NotEq | And | Or | Not => {
|
| NumDivUnchecked | NumRemUnchecked | NumSqrt | NumRound | NumSin | NumCos | Eq | NotEq
|
||||||
|
| And | Or | Not => {
|
||||||
for (_, arg) in args {
|
for (_, arg) in args {
|
||||||
annotate_usage(&arg, usage);
|
annotate_usage(&arg, usage);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue