This commit is contained in:
Jakub Doka 2024-10-30 20:20:03 +01:00
parent acacd10ee9
commit 9ed3c7ab9e
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 150 additions and 114 deletions

View file

@ -161,6 +161,27 @@ drop := fn(a: uint): void {
} }
``` ```
#### nullable_types
```hb
main := fn(): int {
a := &1
b := @as(?^uint, null)
if decide() b = a
if b == null return 9001
c := @as(?uint, *b)
if decide() c = null
if c != null return 42
return 0
}
decide := fn(): bool return true
```
#### structs #### structs
```hb ```hb
Ty := struct { Ty := struct {
@ -1196,3 +1217,4 @@ main := fn(): int {
opaque := fn(): Foo { opaque := fn(): Foo {
return .(3, 2) return .(3, 2)
} }
```

View file

@ -290,6 +290,7 @@ mod ty {
pub type Builtin = u32; pub type Builtin = u32;
pub type Struct = u32; pub type Struct = u32;
pub type Opt = u32;
pub type Ptr = u32; pub type Ptr = u32;
pub type Func = u32; pub type Func = u32;
pub type Global = u32; pub type Global = u32;
@ -373,6 +374,7 @@ mod ty {
crate::SymKey::Struct(st.file, st.pos, st.captures) crate::SymKey::Struct(st.file, st.pos, st.captures)
} }
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]), Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]),
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p as usize]),
Kind::Func(f) => { Kind::Func(f) => {
let fc = &ctx.funcs[f as usize]; let fc = &ctx.funcs[f as usize];
if let Some(base) = fc.base { if let Some(base) = fc.base {
@ -441,6 +443,10 @@ mod ty {
matches!(self.expand(), Kind::Ptr(_)) || self.is_never() matches!(self.expand(), Kind::Ptr(_)) || self.is_never()
} }
pub fn is_optional(self) -> bool {
matches!(self.expand(), Kind::Opt(_)) || self.is_never()
}
pub fn try_upcast(self, ob: Self) -> Option<Self> { pub fn try_upcast(self, ob: Self) -> Option<Self> {
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0))); let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
let (a, b) = (oa.strip_pointer(), ob.strip_pointer()); let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
@ -490,9 +496,16 @@ mod ty {
pub(crate) fn loc(&self, tys: &Types) -> Loc { pub(crate) fn loc(&self, tys: &Types) -> Loc {
match self.expand() { match self.expand() {
Kind::Opt(o)
if let ty = tys.ins.opts[o as usize].base
&& ty.loc(tys) == Loc::Reg
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
{
Loc::Reg
}
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg, Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg, Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
Kind::Struct(_) | Kind::Slice(_) => Loc::Stack, Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(), Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
} }
} }
@ -633,6 +646,7 @@ mod ty {
pub enum Kind { pub enum Kind {
Builtin, Builtin,
Struct, Struct,
Opt,
Ptr, Ptr,
Func, Func,
Global, Global,
@ -675,6 +689,10 @@ mod ty {
f.write_str("]") f.write_str("]")
} }
TK::Builtin(ty) => f.write_str(to_str(ty)), TK::Builtin(ty) => f.write_str(to_str(ty)),
TK::Opt(ty) => {
f.write_str("?")?;
self.rety(self.tys.ins.opts[ty as usize].base).fmt(f)
}
TK::Ptr(ty) => { TK::Ptr(ty) => {
f.write_str("^")?; f.write_str("^")?;
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f) self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f)
@ -730,6 +748,7 @@ type Size = u32;
#[derive(PartialEq, Eq, Hash, Clone, Copy)] #[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub enum SymKey<'a> { pub enum SymKey<'a> {
Pointer(&'a Ptr), Pointer(&'a Ptr),
Optional(&'a Opt),
Struct(FileId, Pos, ty::Tuple), Struct(FileId, Pos, ty::Tuple),
FuncInst(ty::Func, ty::Tuple), FuncInst(ty::Func, ty::Tuple),
Decl(FileId, Ident), Decl(FileId, Ident),
@ -840,7 +859,12 @@ struct Struct {
field_start: u32, field_start: u32,
} }
#[derive(PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct Opt {
base: ty::Id,
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct Ptr { pub struct Ptr {
base: ty::Id, base: ty::Id,
} }
@ -935,6 +959,7 @@ pub struct TypeIns {
structs: Vec<Struct>, structs: Vec<Struct>,
fields: Vec<Field>, fields: Vec<Field>,
ptrs: Vec<Ptr>, ptrs: Vec<Ptr>,
opts: Vec<Opt>,
slices: Vec<Array>, slices: Vec<Array>,
} }
@ -1065,6 +1090,10 @@ trait TypeParser {
let base = self.parse_ty(file, val, None, files); let base = self.parse_ty(file, val, None, files);
self.tys().make_ptr(base) self.tys().make_ptr(base)
} }
Expr::UnOp { op: TokenKind::Que, val, .. } => {
let base = self.parse_ty(file, val, None, files);
self.tys().make_opt(base)
}
Expr::Ident { id, .. } if id.is_null() => id.len().into(), Expr::Ident { id, .. } if id.is_null() => id.len().into(),
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files), Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
Expr::Field { target, pos, name } Expr::Field { target, pos, name }
@ -1206,64 +1235,44 @@ impl Types {
(ret, iter) (ret, iter)
} }
fn make_ptr(&mut self, base: ty::Id) -> ty::Id { fn make_opt(&mut self, base: ty::Id) -> ty::Id {
ty::Kind::Ptr(self.make_ptr_low(base)).compress() self.make_generic_ty(
} Opt { base },
|ins| &mut ins.opts,
fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr { |e| SymKey::Optional(e),
let ptr = Ptr { base }; ty::Kind::Opt,
let (entry, hash) = self.syms.entry(SymKey::Pointer(&ptr), &self.ins);
match entry {
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
hash_map::RawEntryMut::Vacant(v) => {
self.ins.ptrs.push(ptr);
v.insert(
ctx_map::Key {
value: ty::Kind::Ptr(self.ins.ptrs.len() as u32 - 1).compress(),
hash,
},
(),
) )
.0
.value
}
}
.expand()
.inner()
} }
fn make_array(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Id { fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
ty::Kind::Slice(self.make_array_low(ty, len)).compress() self.make_generic_ty(
Ptr { base },
|ins| &mut ins.ptrs,
|e| SymKey::Pointer(e),
ty::Kind::Ptr,
)
} }
fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice { fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
self.syms self.make_generic_ty(
.get_or_insert(SymKey::Array(&Array { elem: ty, len }), &mut self.ins, |ins| { Array { elem, len },
ins.slices.push(Array { elem: ty, len }); |ins| &mut ins.slices,
ty::Kind::Slice(ins.slices.len() as u32 - 1).compress() |e| SymKey::Array(e),
ty::Kind::Slice,
)
}
fn make_generic_ty<T: Copy>(
&mut self,
ty: T,
get_col: fn(&mut TypeIns) -> &mut Vec<T>,
key: fn(&T) -> SymKey,
kind: fn(u32) -> ty::Kind,
) -> ty::Id {
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| {
get_col(ins).push(ty);
kind(get_col(ins).len() as u32 - 1).compress()
}) })
.expand()
.inner()
//let array = Array { ty, len };
//let (entry, hash) = self.syms.entry(SymKey::Array(&array), &self.ins);
//match entry {
// hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
// hash_map::RawEntryMut::Vacant(v) => {
// self.ins.arrays.push(array);
// v.insert(
// ctx_map::Key {
// value: ty::Kind::Slice(self.ins.ptrs.len() as u32 - 1).compress(),
// hash,
// },
// (),
// )
// .0
// .value
// }
//}
//.expand()
//.inner()
} }
fn size_of(&self, ty: ty::Id) -> Size { fn size_of(&self, ty: ty::Id) -> Size {
@ -1328,6 +1337,20 @@ impl Types {
} }
} }
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
match ty.expand() {
ty::Kind::Opt(o) => Some(self.ins.opts[o as usize].base),
_ => None,
}
}
fn opt_flag_field(&self, ty: ty::Id) -> (Offset, ty::Id) {
match ty.expand() {
ty::Kind::Ptr(_) => (0, ty::Id::UINT),
_ => todo!("{ty:?}"),
}
}
fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> { fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> {
let name = self.names.project(name)?; let name = self.names.project(name)?;
self.struct_fields(s).iter().position(|f| f.name == name) self.struct_fields(s).iter().position(|f| f.name == name)

View file

@ -443,7 +443,7 @@ impl<'a, 'b> Parser<'a, 'b> {
pos pos
}, },
}, },
T::Band | T::Mul | T::Xor | T::Sub => E::UnOp { T::Band | T::Mul | T::Xor | T::Sub | T::Que => E::UnOp {
pos, pos,
op: token.kind, op: token.kind,
val: { val: {

View file

@ -654,6 +654,14 @@ impl Nodes {
} }
} }
fn new_const(&mut self, ty: ty::Id, value: impl Into<i64>) -> Nid {
self.new_node_nop(ty, Kind::CInt { value: value.into() }, [VOID])
}
fn new_const_lit(&mut self, ty: ty::Id, value: impl Into<i64>) -> Value {
self.new_node_lit(ty, Kind::CInt { value: value.into() }, [VOID])
}
fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value { fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value {
Value::new(self.new_node(ty, kind, inps)).ty(ty) Value::new(self.new_node(ty, kind, inps)).ty(ty)
} }
@ -772,18 +780,14 @@ impl Nodes {
if let (&K::CInt { value: a }, &K::CInt { value: b }) = if let (&K::CInt { value: a }, &K::CInt { value: b }) =
(&self[lhs].kind, &self[rhs].kind) (&self[lhs].kind, &self[rhs].kind)
{ {
return Some(self.new_node( return Some(self.new_const(ty, op.apply_binop(a, b, is_float)));
ty,
K::CInt { value: op.apply_binop(a, b, is_float) },
[ctrl],
));
} }
if lhs == rhs { if lhs == rhs {
match op { match op {
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])), T::Sub => return Some(self.new_const(ty, 0)),
T::Add => { T::Add => {
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]); let rhs = self.new_const(ty, 2);
return Some( return Some(
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]), self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]),
); );
@ -813,11 +817,7 @@ impl Nodes {
&& let K::CInt { value: bv } = self[rhs].kind && let K::CInt { value: bv } = self[rhs].kind
{ {
// (a op #b) op #c => a op (#b op #c) // (a op #b) op #c => a op (#b op #c)
let new_rhs = self.new_node_nop( let new_rhs = self.new_const(ty, op.apply_binop(av, bv, is_float));
ty,
K::CInt { value: op.apply_binop(av, bv, is_float) },
[ctrl],
);
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
} }
@ -834,7 +834,7 @@ impl Nodes {
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind && let K::CInt { value } = self[self[lhs].inputs[2]].kind
{ {
// a * #n + a => a * (#n + 1) // a * #n + a => a * (#n + 1)
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]); let new_rhs = self.new_const(ty, value + 1);
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs])); return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
} }
@ -843,7 +843,7 @@ impl Nodes {
&& let K::CInt { value: a } = self[rhs].kind && let K::CInt { value: a } = self[rhs].kind
&& let K::CInt { value: b } = self[self[lhs].inputs[2]].kind && let K::CInt { value: b } = self[self[lhs].inputs[2]].kind
{ {
let new_rhs = self.new_node_nop(ty, K::CInt { value: b - a }, [ctrl]); let new_rhs = self.new_const(ty, b - a);
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [ return Some(self.new_node(ty, K::BinOp { op: T::Add }, [
ctrl, ctrl,
self[lhs].inputs[1], self[lhs].inputs[1],
@ -864,17 +864,13 @@ impl Nodes {
} }
} }
K::UnOp { op } => { K::UnOp { op } => {
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() }; let &[_, oper] = self[target].inputs.as_slice() else { unreachable!() };
let ty = self[target].ty; let ty = self[target].ty;
let is_float = self[oper].ty.is_float(); let is_float = self[oper].ty.is_float();
if let K::CInt { value } = self[oper].kind { if let K::CInt { value } = self[oper].kind {
return Some(self.new_node( return Some(self.new_const(ty, op.apply_unop(value, is_float)));
ty,
K::CInt { value: op.apply_unop(value, is_float) },
[ctrl],
));
} }
} }
K::If => { K::If => {
@ -2307,21 +2303,31 @@ impl<'a> Codegen<'a> {
// ordered by complexity of the expression // ordered by complexity of the expression
match *expr { match *expr {
Expr::Null { pos } => { Expr::Null { pos } => {
inference!(ty, ctx, self, pos, "null pointer", "@as(^<ty>, null)"); inference!(oty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
if !ty.is_pointer() { let Some(ty) = self.tys.inner_of(oty) else {
self.report( self.report(
pos, pos,
fa!( fa!(
"'null' expression was inferred to be '{}', "'null' expression was inferred to be '{}',
which is not a pointer (and that is not supported yet)", which is not optional",
self.ty_display(ty) self.ty_display(oty)
), ),
); );
return Value::NEVER; return Value::NEVER;
} };
Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID])) match oty.loc(self.tys) {
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
Loc::Stack => {
let (off, flag_ty) = self.tys.opt_flag_field(ty);
let stack = self.new_stack(oty);
let offset = self.offset(stack, off);
let value = self.ci.nodes.new_const(flag_ty, 0);
self.store_mem(offset, flag_ty, value);
Some(Value::ptr(stack).ty(oty))
}
}
} }
Expr::Idk { pos } => { Expr::Idk { pos } => {
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)"); inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
@ -2340,20 +2346,14 @@ impl<'a> Codegen<'a> {
Value::NEVER Value::NEVER
} }
} }
Expr::Bool { value, .. } => Some(self.ci.nodes.new_node_lit( Expr::Bool { value, .. } => Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, value)),
ty::Id::BOOL, Expr::Number { value, .. } => Some(self.ci.nodes.new_const_lit(
Kind::CInt { value: value as i64 },
[VOID],
)),
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT), ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
Kind::CInt { value }, value,
[VOID],
)), )),
Expr::Float { value, .. } => Some(self.ci.nodes.new_node_lit( Expr::Float { value, .. } => Some(self.ci.nodes.new_const_lit(
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32), ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
Kind::CInt { value: value as _ }, value as i64,
[VOID],
)), )),
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) =>
@ -2551,11 +2551,7 @@ impl<'a> Codegen<'a> {
if val.ty.is_integer() { if val.ty.is_integer() {
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id])) Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
} else if val.ty.is_float() { } else if val.ty.is_float() {
let value = self.ci.nodes.new_node_nop( let value = self.ci.nodes.new_const(val.ty, (-1f64).to_bits() as i64);
val.ty,
Kind::CInt { value: (-1f64).to_bits() as _ },
[VOID],
);
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [ Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [
VOID, val.id, value, VOID, val.id, value,
])) ]))
@ -2669,8 +2665,7 @@ impl<'a> Codegen<'a> {
let elem = self.tys.ins.slices[s as usize].elem; let elem = self.tys.ins.slices[s as usize].elem;
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?; let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript"); self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
let value = self.tys.size_of(elem) as i64; let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
let size = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
let inps = [VOID, idx.id, size]; let inps = [VOID, idx.id, size];
let offset = let offset =
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps); self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
@ -2690,18 +2685,16 @@ 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_node_lit( Some(self.ci.nodes.new_const_lit(
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT), ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
Kind::CInt { value: self.tys.size_of(ty) as _ }, self.tys.size_of(ty),
[VOID],
)) ))
} }
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_node_lit( Some(self.ci.nodes.new_const_lit(
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT), ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
Kind::CInt { value: self.tys.align_of(ty) as _ }, self.tys.align_of(ty),
[VOID],
)) ))
} }
Expr::Directive { name: "bitcast", args: [val], pos } => { Expr::Directive { name: "bitcast", args: [val], pos } => {
@ -3166,8 +3159,8 @@ impl<'a> Codegen<'a> {
} }
} }
Expr::Struct { .. } => { Expr::Struct { .. } => {
let value = self.ty(expr).repr() as i64; let value = self.ty(expr).repr();
Some(self.ci.nodes.new_node_lit(ty::Id::TYPE, Kind::CInt { value }, [VOID])) Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, value))
} }
Expr::Ctor { pos, ty, fields, .. } => { Expr::Ctor { pos, ty, fields, .. } => {
ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty); ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty);
@ -3729,7 +3722,7 @@ impl<'a> Codegen<'a> {
return val; return val;
} }
let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]); let off = self.ci.nodes.new_const(ty::Id::INT, off);
let (aclass, mem) = self.ci.nodes.aclass_index(val); let (aclass, mem) = self.ci.nodes.aclass_index(val);
let inps = [VOID, val, off]; let inps = [VOID, val, off];
let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps); let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
@ -3914,9 +3907,7 @@ impl<'a> Codegen<'a> {
if matches!(op, TokenKind::Add | TokenKind::Sub) if matches!(op, TokenKind::Add | TokenKind::Sub)
&& let Some(elem) = self.tys.base_of(upcasted) && let Some(elem) = self.tys.base_of(upcasted)
{ {
let value = self.tys.size_of(elem) as i64; let cnst = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
let cnst =
self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
oper.id = oper.id =
self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [ self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [
VOID, oper.id, cnst, VOID, oper.id, cnst,
@ -3975,9 +3966,8 @@ 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);
let val = (1i64 << (self.tys.size_of(value.ty) * 8)) - 1;
value.ty = to; value.ty = to;
let mask = self.ci.nodes.new_node_nop(to, Kind::CInt { value: val }, [VOID]); 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);
} }
@ -4137,6 +4127,7 @@ mod tests {
variables; variables;
loops; loops;
pointers; pointers;
nullable_types;
structs; structs;
hex_octal_binary_literals; hex_octal_binary_literals;
struct_operators; struct_operators;

View file