adding optional values
This commit is contained in:
parent
9ed3c7ab9e
commit
3f9f99ff65
|
@ -135,9 +135,6 @@ fib := fn(n: uint): uint {
|
||||||
#### pointers
|
#### pointers
|
||||||
```hb
|
```hb
|
||||||
main := fn(): uint {
|
main := fn(): uint {
|
||||||
n := @as(^uint, null)
|
|
||||||
if n != null return 9001
|
|
||||||
|
|
||||||
a := 1
|
a := 1
|
||||||
b := &a
|
b := &a
|
||||||
|
|
||||||
|
@ -176,7 +173,12 @@ main := fn(): int {
|
||||||
|
|
||||||
if c != null return 42
|
if c != null return 42
|
||||||
|
|
||||||
return 0
|
d := @as(?u16, null)
|
||||||
|
if decide() d = 0
|
||||||
|
|
||||||
|
if d == null return 69
|
||||||
|
|
||||||
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
decide := fn(): bool return true
|
decide := fn(): bool return true
|
||||||
|
|
|
@ -454,6 +454,7 @@ mod ty {
|
||||||
_ if oa == Self::from(NEVER) => ob,
|
_ if oa == Self::from(NEVER) => ob,
|
||||||
_ if ob == Self::from(NEVER) => oa,
|
_ if ob == Self::from(NEVER) => oa,
|
||||||
_ if oa == ob => oa,
|
_ if oa == ob => oa,
|
||||||
|
_ if ob.is_optional() => ob,
|
||||||
_ if oa.is_pointer() && ob.is_pointer() => return None,
|
_ if oa.is_pointer() && ob.is_pointer() => return None,
|
||||||
_ if a.is_signed() && b.is_signed() || a.is_unsigned() && b.is_unsigned() => ob,
|
_ if a.is_signed() && b.is_signed() || a.is_unsigned() && b.is_unsigned() => ob,
|
||||||
_ if a.is_unsigned() && b.is_signed() && a.repr() - U8 < b.repr() - I8 => ob,
|
_ if a.is_unsigned() && b.is_signed() && a.repr() - U8 < b.repr() - I8 => ob,
|
||||||
|
@ -646,12 +647,12 @@ mod ty {
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Builtin,
|
Builtin,
|
||||||
Struct,
|
Struct,
|
||||||
Opt,
|
|
||||||
Ptr,
|
Ptr,
|
||||||
|
Slice,
|
||||||
|
Opt,
|
||||||
Func,
|
Func,
|
||||||
Global,
|
Global,
|
||||||
Module,
|
Module,
|
||||||
Slice,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1295,6 +1296,14 @@ impl Types {
|
||||||
self.ins.structs[stru as usize].size.set(oiter.offset);
|
self.ins.structs[stru as usize].size.set(oiter.offset);
|
||||||
oiter.offset
|
oiter.offset
|
||||||
}
|
}
|
||||||
|
ty::Kind::Opt(opt) => {
|
||||||
|
let base = self.ins.opts[opt as usize].base;
|
||||||
|
if self.nieche_of(base).is_some() {
|
||||||
|
self.size_of(base)
|
||||||
|
} else {
|
||||||
|
self.size_of(base) + self.align_of(base)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ if let Some(size) = ty.simple_size() => size,
|
_ if let Some(size) = ty.simple_size() => size,
|
||||||
ty => unimplemented!("size_of: {:?}", ty),
|
ty => unimplemented!("size_of: {:?}", ty),
|
||||||
}
|
}
|
||||||
|
@ -1344,10 +1353,27 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opt_flag_field(&self, ty: ty::Id) -> (Offset, ty::Id) {
|
fn opt_layout(&self, inner_ty: ty::Id) -> OptLayout {
|
||||||
|
match self.nieche_of(inner_ty) {
|
||||||
|
Some((_, flag_offset, flag_ty)) => {
|
||||||
|
OptLayout { flag_ty, flag_offset, payload_offset: 0 }
|
||||||
|
}
|
||||||
|
None => OptLayout {
|
||||||
|
flag_ty: ty::Id::BOOL,
|
||||||
|
flag_offset: 0,
|
||||||
|
payload_offset: self.align_of(inner_ty),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nieche_of(&self, ty: ty::Id) -> Option<(bool, Offset, ty::Id)> {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Ptr(_) => (0, ty::Id::UINT),
|
ty::Kind::Ptr(_) => Some((false, 0, ty::Id::UINT)),
|
||||||
_ => todo!("{ty:?}"),
|
// TODO: cache this
|
||||||
|
ty::Kind::Struct(s) => OffsetIter::new(s, self).into_iter(self).find_map(|(f, off)| {
|
||||||
|
self.nieche_of(f.ty).map(|(uninit, o, ty)| (uninit, o + off, ty))
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,6 +1405,12 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct OptLayout {
|
||||||
|
flag_ty: ty::Id,
|
||||||
|
flag_offset: Offset,
|
||||||
|
payload_offset: Offset,
|
||||||
|
}
|
||||||
|
|
||||||
struct OffsetIter {
|
struct OffsetIter {
|
||||||
strct: ty::Struct,
|
strct: ty::Struct,
|
||||||
offset: Offset,
|
offset: Offset,
|
||||||
|
|
225
lang/src/son.rs
225
lang/src/son.rs
|
@ -12,8 +12,8 @@ use {
|
||||||
task,
|
task,
|
||||||
ty::{self, Arg, ArrayLen, Loc, Tuple},
|
ty::{self, Arg, ArrayLen, Loc, Tuple},
|
||||||
utils::{BitSet, Vc},
|
utils::{BitSet, Vc},
|
||||||
FTask, Func, Global, Ident, Offset, OffsetIter, Reloc, Sig, StringRef, SymKey, TypeParser,
|
FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Reloc, Sig, StringRef, SymKey,
|
||||||
TypedReloc, Types,
|
TypeParser, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
|
@ -2320,9 +2320,9 @@ impl<'a> Codegen<'a> {
|
||||||
match oty.loc(self.tys) {
|
match oty.loc(self.tys) {
|
||||||
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
|
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
|
||||||
Loc::Stack => {
|
Loc::Stack => {
|
||||||
let (off, flag_ty) = self.tys.opt_flag_field(ty);
|
let OptLayout { flag_ty, flag_offset, .. } = self.tys.opt_layout(ty);
|
||||||
let stack = self.new_stack(oty);
|
let stack = self.new_stack(oty);
|
||||||
let offset = self.offset(stack, off);
|
let offset = self.offset(stack, flag_offset);
|
||||||
let value = self.ci.nodes.new_const(flag_ty, 0);
|
let value = self.ci.nodes.new_const(flag_ty, 0);
|
||||||
self.store_mem(offset, flag_ty, value);
|
self.store_mem(offset, flag_ty, value);
|
||||||
Some(Value::ptr(stack).ty(oty))
|
Some(Value::ptr(stack).ty(oty))
|
||||||
|
@ -2347,14 +2347,24 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Bool { value, .. } => Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, value)),
|
Expr::Bool { value, .. } => Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, value)),
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_const_lit(
|
Expr::Number { value, .. } => Some(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
self.ci.nodes.new_const_lit(
|
||||||
value,
|
ctx.ty
|
||||||
)),
|
.map(|ty| self.tys.inner_of(ty).unwrap_or(ty))
|
||||||
Expr::Float { value, .. } => Some(self.ci.nodes.new_const_lit(
|
.filter(|ty| ty.is_integer())
|
||||||
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
|
.unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
value as i64,
|
value,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
Expr::Float { value, .. } => Some(
|
||||||
|
self.ci.nodes.new_const_lit(
|
||||||
|
ctx.ty
|
||||||
|
.map(|ty| self.tys.inner_of(ty).unwrap_or(ty))
|
||||||
|
.filter(|ty| ty.is_float())
|
||||||
|
.unwrap_or(ty::Id::F32),
|
||||||
|
value as i64,
|
||||||
|
),
|
||||||
|
),
|
||||||
Expr::Ident { id, .. }
|
Expr::Ident { id, .. }
|
||||||
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
||||||
{
|
{
|
||||||
|
@ -2534,6 +2544,8 @@ impl<'a> Codegen<'a> {
|
||||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||||
let mut val = self.expr_ctx(val, ctx)?;
|
let mut val = self.expr_ctx(val, ctx)?;
|
||||||
|
|
||||||
|
self.unwrap_opt(pos, &mut val);
|
||||||
|
|
||||||
let Some(base) = self.tys.base_of(val.ty) else {
|
let Some(base) = self.tys.base_of(val.ty) else {
|
||||||
self.report(
|
self.report(
|
||||||
pos,
|
pos,
|
||||||
|
@ -2596,6 +2608,25 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
|
Expr::BinOp { left: &Expr::Null { pos }, .. } => {
|
||||||
|
self.report(pos, "'null' must always be no the right side of an expression");
|
||||||
|
Value::NEVER
|
||||||
|
}
|
||||||
|
Expr::BinOp {
|
||||||
|
left,
|
||||||
|
op: op @ (TokenKind::Eq | TokenKind::Ne),
|
||||||
|
right: Expr::Null { .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut cmped = self.raw_expr(left)?;
|
||||||
|
self.strip_var(&mut cmped);
|
||||||
|
|
||||||
|
let Some(ty) = self.tys.inner_of(cmped.ty) else {
|
||||||
|
return Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::BOOL))
|
||||||
|
}
|
||||||
Expr::BinOp { left, pos, op, right }
|
Expr::BinOp { left, pos, op, right }
|
||||||
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
||||||
{
|
{
|
||||||
|
@ -2685,17 +2716,27 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
||||||
let ty = self.ty(ty);
|
let ty = self.ty(ty);
|
||||||
Some(self.ci.nodes.new_const_lit(
|
Some(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
self.ci.nodes.new_const_lit(
|
||||||
self.tys.size_of(ty),
|
ctx.ty
|
||||||
))
|
.map(|ty| self.tys.inner_of(ty).unwrap_or(ty))
|
||||||
|
.filter(|ty| ty.is_integer())
|
||||||
|
.unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
|
self.tys.size_of(ty),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
||||||
let ty = self.ty(ty);
|
let ty = self.ty(ty);
|
||||||
Some(self.ci.nodes.new_const_lit(
|
Some(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
self.ci.nodes.new_const_lit(
|
||||||
self.tys.align_of(ty),
|
ctx.ty
|
||||||
))
|
.map(|ty| self.tys.inner_of(ty).unwrap_or(ty))
|
||||||
|
.filter(|ty| ty.is_integer())
|
||||||
|
.unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
|
self.tys.align_of(ty),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
||||||
let mut val = self.raw_expr(val)?;
|
let mut val = self.raw_expr(val)?;
|
||||||
|
@ -3929,6 +3970,103 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap_in_opt(&mut self, val: &mut Value) {
|
||||||
|
debug_assert!(!val.var);
|
||||||
|
|
||||||
|
let oty = self.tys.make_opt(val.ty);
|
||||||
|
|
||||||
|
if let Some((uninit, ..)) = self.tys.nieche_of(val.ty) {
|
||||||
|
self.strip_ptr(val);
|
||||||
|
val.ty = oty;
|
||||||
|
assert!(!uninit, "TODO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let OptLayout { flag_ty, flag_offset, payload_offset } = self.tys.opt_layout(val.ty);
|
||||||
|
|
||||||
|
match oty.loc(self.tys) {
|
||||||
|
Loc::Reg => {
|
||||||
|
self.strip_ptr(val);
|
||||||
|
// registers have inverted offsets so that accessing the inner type is a noop
|
||||||
|
let flag_offset = self.tys.size_of(oty) - flag_offset - 1;
|
||||||
|
let fill = self.ci.nodes.new_const(oty, 1i64 << (flag_offset * 8 - 1));
|
||||||
|
val.id = self
|
||||||
|
.ci
|
||||||
|
.nodes
|
||||||
|
.new_node(oty, Kind::BinOp { op: TokenKind::Bor }, [VOID, val.id, fill]);
|
||||||
|
val.ty = oty;
|
||||||
|
}
|
||||||
|
Loc::Stack if val.ty.loc(self.tys) == Loc::Reg => {
|
||||||
|
self.strip_ptr(val);
|
||||||
|
let stack = self.new_stack(oty);
|
||||||
|
let fill = self.ci.nodes.new_const(flag_ty, 1);
|
||||||
|
self.store_mem(stack, flag_ty, fill);
|
||||||
|
let off = self.offset(stack, payload_offset);
|
||||||
|
self.store_mem(off, val.ty, val.id);
|
||||||
|
val.id = stack;
|
||||||
|
val.ptr = true;
|
||||||
|
val.ty = oty;
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_opt(&mut self, pos: Pos, opt: &mut Value) {
|
||||||
|
let Some(ty) = self.tys.inner_of(opt.ty) else { return };
|
||||||
|
let null_check = self.gen_null_check(*opt, ty, TokenKind::Eq);
|
||||||
|
|
||||||
|
// TODO: extract the if check int a fucntion
|
||||||
|
let ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::If, [self.ci.ctrl.get(), null_check]);
|
||||||
|
let ctrl_ty = self.ci.nodes[ctrl].ty;
|
||||||
|
self.ci.nodes.remove(ctrl);
|
||||||
|
let oty = mem::replace(&mut opt.ty, ty);
|
||||||
|
match ctrl_ty {
|
||||||
|
ty::Id::LEFT_UNREACHABLE => {
|
||||||
|
if self.tys.nieche_of(ty).is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let OptLayout { payload_offset, .. } = self.tys.opt_layout(ty);
|
||||||
|
|
||||||
|
match oty.loc(self.tys) {
|
||||||
|
Loc::Reg => {}
|
||||||
|
Loc::Stack => {
|
||||||
|
opt.id = self.offset(opt.id, payload_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Id::RIGHT_UNREACHABLE => {
|
||||||
|
self.report(pos, "the value is always null, some checks might need to be inverted");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
"can't prove the value is not 'null', \
|
||||||
|
there is not nice syntax for bypassing this, sorry",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_null_check(&mut self, mut cmped: Value, ty: ty::Id, op: TokenKind) -> Nid {
|
||||||
|
let OptLayout { flag_ty, flag_offset, .. } = self.tys.opt_layout(ty);
|
||||||
|
|
||||||
|
match cmped.ty.loc(self.tys) {
|
||||||
|
Loc::Reg => {
|
||||||
|
self.strip_ptr(&mut cmped);
|
||||||
|
let inps = [VOID, cmped.id, self.ci.nodes.new_const(cmped.ty, 0)];
|
||||||
|
self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps)
|
||||||
|
}
|
||||||
|
Loc::Stack => {
|
||||||
|
cmped.id = self.offset(cmped.id, flag_offset);
|
||||||
|
cmped.ty = flag_ty;
|
||||||
|
self.strip_ptr(&mut cmped);
|
||||||
|
let inps = [VOID, cmped.id, self.ci.nodes.new_const(ty, 0)];
|
||||||
|
self.ci.nodes.new_node(ty::Id::BOOL, Kind::BinOp { op }, inps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_ty(
|
fn assert_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -3940,24 +4078,43 @@ impl<'a> Codegen<'a> {
|
||||||
if let Some(upcasted) = src.ty.try_upcast(expected)
|
if let Some(upcasted) = src.ty.try_upcast(expected)
|
||||||
&& upcasted == expected
|
&& upcasted == expected
|
||||||
{
|
{
|
||||||
|
if src.ty.is_never() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if src.ty != upcasted {
|
if src.ty != upcasted {
|
||||||
debug_assert!(
|
if let Some(inner) = self.tys.inner_of(upcasted) {
|
||||||
src.ty.is_integer() || src.ty == ty::Id::NEVER,
|
if inner != src.ty {
|
||||||
"{} {}",
|
self.assert_ty(pos, src, inner, hint);
|
||||||
self.ty_display(src.ty),
|
}
|
||||||
self.ty_display(upcasted)
|
self.wrap_in_opt(src);
|
||||||
);
|
} else {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
upcasted.is_integer() || src.ty == ty::Id::NEVER,
|
src.ty.is_integer() || src.ty == ty::Id::NEVER,
|
||||||
"{} {}",
|
"{} {}",
|
||||||
self.ty_display(src.ty),
|
self.ty_display(src.ty),
|
||||||
self.ty_display(upcasted)
|
self.ty_display(upcasted)
|
||||||
);
|
);
|
||||||
self.extend(src, upcasted);
|
debug_assert!(
|
||||||
|
upcasted.is_integer() || src.ty == ty::Id::NEVER,
|
||||||
|
"{} {}",
|
||||||
|
self.ty_display(src.ty),
|
||||||
|
self.ty_display(upcasted)
|
||||||
|
);
|
||||||
|
self.extend(src, upcasted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
if let Some(inner) = self.tys.inner_of(src.ty)
|
||||||
|
&& inner.try_upcast(expected) == Some(expected)
|
||||||
|
{
|
||||||
|
self.unwrap_opt(pos, src);
|
||||||
|
return self.assert_ty(pos, src, expected, hint);
|
||||||
|
}
|
||||||
|
|
||||||
let ty = self.ty_display(src.ty);
|
let ty = self.ty_display(src.ty);
|
||||||
|
|
||||||
let expected = self.ty_display(expected);
|
let expected = self.ty_display(expected);
|
||||||
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
|
self.report(pos, fa!("expected {hint} to be of type {expected}, got {ty}"));
|
||||||
false
|
false
|
||||||
|
@ -3966,10 +4123,10 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
fn extend(&mut self, value: &mut Value, to: ty::Id) {
|
fn extend(&mut self, value: &mut Value, to: ty::Id) {
|
||||||
self.strip_ptr(value);
|
self.strip_ptr(value);
|
||||||
value.ty = to;
|
|
||||||
let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1);
|
let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1);
|
||||||
let inps = [VOID, value.id, mask];
|
let inps = [VOID, value.id, mask];
|
||||||
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps);
|
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps);
|
||||||
|
value.ty = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
|
|
@ -226,17 +226,20 @@ impl ItemCtx {
|
||||||
let node = &fuc.nodes[nid];
|
let node = &fuc.nodes[nid];
|
||||||
|
|
||||||
let mut extend = |base: ty::Id, dest: ty::Id, from: usize, to: usize| {
|
let mut extend = |base: ty::Id, dest: ty::Id, from: usize, to: usize| {
|
||||||
if base.simple_size() == dest.simple_size() {
|
let (bsize, dsize) = (tys.size_of(base), tys.size_of(dest));
|
||||||
|
debug_assert!(bsize <= 8);
|
||||||
|
debug_assert!(dsize <= 8);
|
||||||
|
if bsize == dsize {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
}
|
}
|
||||||
match (base.is_signed(), dest.is_signed()) {
|
match (base.is_signed(), dest.is_signed()) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32]
|
let op = [instrs::sxt8, instrs::sxt16, instrs::sxt32]
|
||||||
[base.simple_size().unwrap().ilog2() as usize];
|
[bsize.ilog2() as usize];
|
||||||
op(atr(allocs[to]), atr(allocs[from]))
|
op(atr(allocs[to]), atr(allocs[from]))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mask = (1u64 << (base.simple_size().unwrap() * 8)) - 1;
|
let mask = (1u64 << (bsize * 8)) - 1;
|
||||||
instrs::andi(atr(allocs[to]), atr(allocs[from]), mask)
|
instrs::andi(atr(allocs[to]), atr(allocs[from]), mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
decide:
|
||||||
|
LI8 r1, 1b
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
main:
|
||||||
|
ADDI64 r254, r254, -40d
|
||||||
|
ST r31, r254, 24a, 16h
|
||||||
|
JAL r31, r0, :decide
|
||||||
|
LI64 r3, 0d
|
||||||
|
ANDI r1, r1, 255d
|
||||||
|
JNE r1, r0, :0
|
||||||
|
CP r32, r3
|
||||||
|
JMP :1
|
||||||
|
0: ADDI64 r32, r254, 16d
|
||||||
|
1: JNE r32, r3, :2
|
||||||
|
LI64 r1, 9001d
|
||||||
|
JMP :3
|
||||||
|
2: JAL r31, r0, :decide
|
||||||
|
ANDI r1, r1, 255d
|
||||||
|
JNE r1, r0, :4
|
||||||
|
LI8 r6, 1b
|
||||||
|
ST r6, r254, 0a, 1h
|
||||||
|
LD r7, r32, 0a, 8h
|
||||||
|
ST r7, r254, 8a, 8h
|
||||||
|
JMP :5
|
||||||
|
4: LI8 r1, 0b
|
||||||
|
ST r1, r254, 0a, 1h
|
||||||
|
5: LI64 r6, 0d
|
||||||
|
LD r7, r254, 0a, 1h
|
||||||
|
ANDI r7, r7, 255d
|
||||||
|
JEQ r7, r6, :6
|
||||||
|
LI64 r1, 42d
|
||||||
|
JMP :3
|
||||||
|
6: JAL r31, r0, :decide
|
||||||
|
LI32 r2, 0w
|
||||||
|
ANDI r1, r1, 255d
|
||||||
|
JNE r1, r0, :7
|
||||||
|
CP r8, r2
|
||||||
|
JMP :8
|
||||||
|
7: LI32 r8, 8388608w
|
||||||
|
8: ANDI r8, r8, 4294967295d
|
||||||
|
ANDI r2, r2, 4294967295d
|
||||||
|
JNE r8, r2, :9
|
||||||
|
LI64 r1, 69d
|
||||||
|
JMP :3
|
||||||
|
9: ANDI r1, r8, 65535d
|
||||||
|
3: LD r31, r254, 24a, 16h
|
||||||
|
ADDI64 r254, r254, 40d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 389
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue