supporting translation of all nodes
TODO: handle ABI argument passing Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
ee67ebb017
commit
68186ec0ce
|
@ -1,19 +1,21 @@
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(slice_take)]
|
#![feature(slice_take)]
|
||||||
use {
|
use {
|
||||||
|
core::panic,
|
||||||
cranelift_codegen::{
|
cranelift_codegen::{
|
||||||
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||||
ir::{InstBuilder, UserExternalName},
|
ir::{InstBuilder, MemFlags, UserExternalName},
|
||||||
isa::LookupError,
|
isa::{LookupError, TargetIsa},
|
||||||
settings::Configurable,
|
settings::Configurable,
|
||||||
},
|
},
|
||||||
cranelift_frontend::FunctionBuilder,
|
cranelift_frontend::FunctionBuilder,
|
||||||
cranelift_module::{Module, ModuleError},
|
cranelift_module::{Module, ModuleError},
|
||||||
hblang::{
|
hblang::{
|
||||||
|
lexer::TokenKind,
|
||||||
nodes::Kind,
|
nodes::Kind,
|
||||||
utils::{Ent, EntVec},
|
utils::{Ent, EntVec},
|
||||||
},
|
},
|
||||||
std::{fmt::Display, ops::Range},
|
std::{fmt::Display, ops::Range, usize},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
|
@ -85,6 +87,9 @@ impl hblang::backend::Backend for Backend {
|
||||||
match itm.expand() {
|
match itm.expand() {
|
||||||
hblang::ty::Kind::Func(func) => {
|
hblang::ty::Kind::Func(func) => {
|
||||||
let fuc = &mut self.funcs.headers[func];
|
let fuc = &mut self.funcs.headers[func];
|
||||||
|
if fuc.module_id.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.asm.funcs.push(func);
|
self.asm.funcs.push(func);
|
||||||
self.asm.frontier.extend(
|
self.asm.frontier.extend(
|
||||||
fuc.external_names.clone().map(|r| {
|
fuc.external_names.clone().map(|r| {
|
||||||
|
@ -96,7 +101,7 @@ impl hblang::backend::Backend for Backend {
|
||||||
self.asm.name.push_str("main");
|
self.asm.name.push_str("main");
|
||||||
} else {
|
} else {
|
||||||
let file = &files[types.ins.funcs[func].file];
|
let file = &files[types.ins.funcs[func].file];
|
||||||
self.asm.name.push_str(&file.path);
|
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
||||||
self.asm.name.push('.');
|
self.asm.name.push('.');
|
||||||
self.asm.name.push_str(file.ident_str(types.ins.funcs[func].name));
|
self.asm.name.push_str(file.ident_str(types.ins.funcs[func].name));
|
||||||
}
|
}
|
||||||
|
@ -119,10 +124,13 @@ impl hblang::backend::Backend for Backend {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hblang::ty::Kind::Global(glob) => {
|
hblang::ty::Kind::Global(glob) => {
|
||||||
|
if self.globals[glob].module_id.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
self.asm.globals.push(glob);
|
self.asm.globals.push(glob);
|
||||||
self.asm.name.clear();
|
self.asm.name.clear();
|
||||||
let file = &files[types.ins.globals[glob].file];
|
let file = &files[types.ins.globals[glob].file];
|
||||||
self.asm.name.push_str(&file.path);
|
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
||||||
self.asm.name.push('.');
|
self.asm.name.push('.');
|
||||||
self.asm.name.push_str(file.ident_str(types.ins.globals[glob].name));
|
self.asm.name.push_str(file.ident_str(types.ins.globals[glob].name));
|
||||||
self.globals[glob].module_id = Some(
|
self.globals[glob].module_id = Some(
|
||||||
|
@ -146,7 +154,10 @@ impl hblang::backend::Backend for Backend {
|
||||||
let names = &mut self.funcs.external_names
|
let names = &mut self.funcs.external_names
|
||||||
[fuc.external_names.start as usize..fuc.external_names.end as usize];
|
[fuc.external_names.start as usize..fuc.external_names.end as usize];
|
||||||
names.iter_mut().for_each(|nm| {
|
names.iter_mut().for_each(|nm| {
|
||||||
nm.index = fuc.module_id.unwrap().as_u32();
|
nm.index = self.funcs.headers[hblang::ty::Func::new(nm.index as _)]
|
||||||
|
.module_id
|
||||||
|
.unwrap()
|
||||||
|
.as_u32();
|
||||||
self.ctx.func.params.ensure_user_func_name(nm.clone());
|
self.ctx.func.params.ensure_user_func_name(nm.clone());
|
||||||
});
|
});
|
||||||
module
|
module
|
||||||
|
@ -191,10 +202,11 @@ impl hblang::backend::Backend for Backend {
|
||||||
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||||
) {
|
) {
|
||||||
self.ctx.clear();
|
self.ctx.clear();
|
||||||
|
let isa = self.module.as_ref().unwrap().isa();
|
||||||
|
|
||||||
let mut lens = vec![];
|
let mut lens = vec![];
|
||||||
let stack_ret = build_signature(
|
let stack_ret = build_signature(
|
||||||
self.module.as_ref().unwrap().isa().default_call_conv(),
|
isa.default_call_conv(),
|
||||||
tys.ins.funcs[id].sig,
|
tys.ins.funcs[id].sig,
|
||||||
tys,
|
tys,
|
||||||
&mut self.ctx.func.signature,
|
&mut self.ctx.func.signature,
|
||||||
|
@ -203,6 +215,7 @@ impl hblang::backend::Backend for Backend {
|
||||||
|
|
||||||
FuncBuilder {
|
FuncBuilder {
|
||||||
bl: FunctionBuilder::new(&mut self.ctx.func, &mut self.fb_ctx),
|
bl: FunctionBuilder::new(&mut self.ctx.func, &mut self.fb_ctx),
|
||||||
|
isa,
|
||||||
nodes,
|
nodes,
|
||||||
tys,
|
tys,
|
||||||
files,
|
files,
|
||||||
|
@ -210,7 +223,15 @@ impl hblang::backend::Backend for Backend {
|
||||||
}
|
}
|
||||||
.build(tys.ins.funcs[id].sig, &lens, stack_ret);
|
.build(tys.ins.funcs[id].sig, &lens, stack_ret);
|
||||||
|
|
||||||
self.ctx.compile(self.module.as_ref().unwrap().isa(), &mut self.ctrl_plane).unwrap();
|
self.ctx.func.name =
|
||||||
|
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
||||||
|
namespace: 0,
|
||||||
|
index: id.index() as _,
|
||||||
|
});
|
||||||
|
|
||||||
|
std::eprintln!("{}", self.ctx.func.display());
|
||||||
|
|
||||||
|
self.ctx.compile(isa, &mut self.ctrl_plane).unwrap();
|
||||||
let code = self.ctx.compiled_code().unwrap();
|
let code = self.ctx.compiled_code().unwrap();
|
||||||
self.funcs.push(id, &self.ctx.func, &code.buffer);
|
self.funcs.push(id, &self.ctx.func, &code.buffer);
|
||||||
}
|
}
|
||||||
|
@ -234,9 +255,9 @@ fn build_signature(
|
||||||
|
|
||||||
struct FuncBuilder<'a, 'b> {
|
struct FuncBuilder<'a, 'b> {
|
||||||
bl: cranelift_frontend::FunctionBuilder<'b>,
|
bl: cranelift_frontend::FunctionBuilder<'b>,
|
||||||
|
isa: &'a dyn TargetIsa,
|
||||||
nodes: &'a hblang::nodes::Nodes,
|
nodes: &'a hblang::nodes::Nodes,
|
||||||
tys: &'a hblang::ty::Types,
|
tys: &'a hblang::ty::Types,
|
||||||
#[expect(unused)]
|
|
||||||
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||||
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
||||||
}
|
}
|
||||||
|
@ -265,7 +286,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
if ty.is_aggregate(tys) {
|
if ty.is_aggregate(tys) {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
debug_assert_eq!(loc.len(), 0);
|
debug_assert_eq!(loc.len(), 1);
|
||||||
self.values[arg as usize] = Some(Ok(loc[0]));
|
self.values[arg as usize] = Some(Ok(loc[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,7 +299,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value_of(&self, nid: hblang::nodes::Nid) -> cranelift_codegen::ir::Value {
|
fn value_of(&self, nid: hblang::nodes::Nid) -> cranelift_codegen::ir::Value {
|
||||||
self.values[nid as usize].unwrap().unwrap()
|
self.values[nid as usize].unwrap_or_else(|| panic!("{:?}", self.nodes[nid])).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_of(&self, nid: hblang::nodes::Nid) -> cranelift_codegen::ir::Block {
|
fn block_of(&self, nid: hblang::nodes::Nid) -> cranelift_codegen::ir::Block {
|
||||||
|
@ -286,7 +307,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_block(&mut self, nid: hblang::nodes::Nid) {
|
fn close_block(&mut self, nid: hblang::nodes::Nid) {
|
||||||
if matches!(self.nodes[nid].kind, Kind::Loop | Kind::Region) {
|
if matches!(self.nodes[nid].kind, Kind::Loop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.bl.seal_block(self.block_of(nid));
|
self.bl.seal_block(self.block_of(nid));
|
||||||
|
@ -300,13 +321,14 @@ impl FuncBuilder<'_, '_> {
|
||||||
let side = 1 + self.values[nid as usize].is_some() as usize;
|
let side = 1 + self.values[nid as usize].is_some() as usize;
|
||||||
for &o in self.nodes[nid].outputs.iter() {
|
for &o in self.nodes[nid].outputs.iter() {
|
||||||
if self.nodes[o].is_data_phi() {
|
if self.nodes[o].is_data_phi() {
|
||||||
args.push(self.value_of(self.nodes[0].inputs[side]));
|
args.push(self.value_of(self.nodes[o].inputs[side]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match (self.nodes[nid].kind, self.values[nid as usize]) {
|
match (self.nodes[nid].kind, self.values[nid as usize]) {
|
||||||
(Kind::Loop, Some(blck)) => {
|
(Kind::Loop, Some(blck)) => {
|
||||||
self.bl.ins().jump(blck.unwrap_err(), &args);
|
self.bl.ins().jump(blck.unwrap_err(), &args);
|
||||||
self.bl.seal_block(blck.unwrap_err());
|
self.bl.seal_block(blck.unwrap_err());
|
||||||
|
self.close_block(block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(Kind::Region, None) => {
|
(Kind::Region, None) => {
|
||||||
|
@ -320,7 +342,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.bl.ins().jump(next, &args);
|
self.bl.ins().jump(next, &args);
|
||||||
self.bl.seal_block(next);
|
self.close_block(block);
|
||||||
self.values[nid as usize] = Some(Err(next));
|
self.values[nid as usize] = Some(Err(next));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -353,19 +375,16 @@ impl FuncBuilder<'_, '_> {
|
||||||
self.emit_node(else_, else_);
|
self.emit_node(else_, else_);
|
||||||
Err(self.block_of(block))
|
Err(self.block_of(block))
|
||||||
}
|
}
|
||||||
Kind::Region | Kind::Loop => {
|
Kind::Loop => {
|
||||||
if node.kind == Kind::Loop {
|
let next = self.bl.create_block();
|
||||||
let next = self.bl.create_block();
|
for &o in self.nodes[nid].outputs.iter() {
|
||||||
for &o in self.nodes[nid].outputs.iter() {
|
if self.nodes[o].is_data_phi() {
|
||||||
if self.nodes[o].is_data_phi() {
|
self.values[o as usize] = Some(Ok(self
|
||||||
self.values[o as usize] = Some(Ok(self.bl.append_block_param(
|
.bl
|
||||||
next,
|
.append_block_param(next, ty_to_clif_ty(self.nodes[o].ty, self.tys))));
|
||||||
ty_to_clif_ty(self.nodes[o].ty, self.tys),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.values[nid as usize] = Some(Err(next));
|
|
||||||
}
|
}
|
||||||
|
self.values[nid as usize] = Some(Err(next));
|
||||||
self.bl.ins().jump(self.values[nid as usize].unwrap().unwrap_err(), &args);
|
self.bl.ins().jump(self.values[nid as usize].unwrap().unwrap_err(), &args);
|
||||||
self.close_block(block);
|
self.close_block(block);
|
||||||
self.bl.switch_to_block(self.values[nid as usize].unwrap().unwrap_err());
|
self.bl.switch_to_block(self.values[nid as usize].unwrap().unwrap_err());
|
||||||
|
@ -374,6 +393,15 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
Err(self.block_of(block))
|
Err(self.block_of(block))
|
||||||
}
|
}
|
||||||
|
Kind::Region => {
|
||||||
|
self.bl.ins().jump(self.values[nid as usize].unwrap().unwrap_err(), &args);
|
||||||
|
self.close_block(block);
|
||||||
|
self.bl.switch_to_block(self.values[nid as usize].unwrap().unwrap_err());
|
||||||
|
for &o in node.outputs.iter().rev() {
|
||||||
|
self.emit_node(o, nid);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
Kind::Return { .. } | Kind::Die => {
|
Kind::Return { .. } | Kind::Die => {
|
||||||
let ret = self.value_of(node.inputs[1]);
|
let ret = self.value_of(node.inputs[1]);
|
||||||
self.bl.ins().return_(&[ret]);
|
self.bl.ins().return_(&[ret]);
|
||||||
|
@ -393,19 +421,64 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
Err(self.block_of(block))
|
Err(self.block_of(block))
|
||||||
}
|
}
|
||||||
Kind::Call { func: _, unreachable, .. } => {
|
Kind::Call { func, unreachable, args } => {
|
||||||
if unreachable {
|
if unreachable {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
let mut arg_lens = vec![];
|
||||||
//for &o in node.outputs.iter().rev() {
|
let mut signature =
|
||||||
// if self.nodes[o].inputs[0] == nid
|
cranelift_codegen::ir::Signature::new(self.isa.default_call_conv());
|
||||||
// || (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
|
let stack_ret = build_signature(
|
||||||
// && self.nodes[o].inputs[1] == nid)
|
self.isa.default_call_conv(),
|
||||||
// {
|
self.tys.ins.funcs[func].sig,
|
||||||
// self.emit_node(o, block);
|
self.tys,
|
||||||
// }
|
&mut signature,
|
||||||
//}
|
&mut arg_lens,
|
||||||
|
);
|
||||||
|
assert!(!stack_ret, "TODO");
|
||||||
|
let func_ref = 'b: {
|
||||||
|
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||||
|
cranelift_codegen::ir::UserExternalName {
|
||||||
|
namespace: 0,
|
||||||
|
index: func.index() as _,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(id) = self.bl.func.dfg.ext_funcs.keys().find(|&k| {
|
||||||
|
self.bl.func.dfg.ext_funcs[k].name
|
||||||
|
== cranelift_codegen::ir::ExternalName::user(user_name_ref)
|
||||||
|
}) {
|
||||||
|
break 'b id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let signature = self.bl.func.import_signature(signature);
|
||||||
|
|
||||||
|
self.bl.func.import_function(cranelift_codegen::ir::ExtFuncData {
|
||||||
|
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
||||||
|
signature,
|
||||||
|
colocated: true,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let args = node.inputs[1..][..args.len()]
|
||||||
|
.iter()
|
||||||
|
.map(|&n| self.value_of(n))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let inst = self.bl.ins().call(func_ref, &args);
|
||||||
|
match *self.bl.inst_results(inst) {
|
||||||
|
[] => {}
|
||||||
|
[scala] => self.values[nid as usize] = Some(Ok(scala)),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
for &o in node.outputs.iter().rev() {
|
||||||
|
if self.nodes[o].inputs[0] == nid
|
||||||
|
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
|
||||||
|
&& self.nodes[o].inputs[1] == nid)
|
||||||
|
{
|
||||||
|
self.emit_node(o, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::CInt { value } if self.nodes[nid].ty.is_integer() => Ok(self.bl.ins().iconst(
|
Kind::CInt { value } if self.nodes[nid].ty.is_integer() => Ok(self.bl.ins().iconst(
|
||||||
|
@ -418,13 +491,192 @@ impl FuncBuilder<'_, '_> {
|
||||||
8 => self.bl.ins().f64const(f64::from_bits(value as _)),
|
8 => self.bl.ins().f64const(f64::from_bits(value as _)),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}),
|
}),
|
||||||
Kind::BinOp { .. }
|
Kind::BinOp { op } => {
|
||||||
| Kind::UnOp { .. }
|
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
| Kind::Global { .. }
|
let [lhs, rhs] = [self.value_of(lhs), self.value_of(rhs)];
|
||||||
| Kind::Load { .. }
|
assert!(
|
||||||
| Kind::Stre
|
node.ty.is_integer() || node.ty == hblang::ty::Id::BOOL,
|
||||||
| Kind::RetVal
|
"TODO: unsupported binary type {}",
|
||||||
| Kind::Stck => todo!(),
|
hblang::ty::Display::new(self.tys, self.files, node.ty)
|
||||||
|
);
|
||||||
|
|
||||||
|
use cranelift_codegen::ir::condcodes::IntCC as ICC;
|
||||||
|
fn icc_of(op: TokenKind, signed: bool) -> ICC {
|
||||||
|
match op {
|
||||||
|
TokenKind::Lt if signed => ICC::SignedLessThan,
|
||||||
|
TokenKind::Gt if signed => ICC::SignedGreaterThan,
|
||||||
|
TokenKind::Le if signed => ICC::SignedLessThanOrEqual,
|
||||||
|
TokenKind::Ge if signed => ICC::SignedGreaterThanOrEqual,
|
||||||
|
|
||||||
|
TokenKind::Lt => ICC::UnsignedLessThan,
|
||||||
|
TokenKind::Gt => ICC::UnsignedGreaterThan,
|
||||||
|
TokenKind::Le => ICC::UnsignedLessThanOrEqual,
|
||||||
|
TokenKind::Ge => ICC::UnsignedGreaterThanOrEqual,
|
||||||
|
|
||||||
|
TokenKind::Eq => ICC::Equal,
|
||||||
|
TokenKind::Ne => ICC::NotEqual,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use cranelift_codegen::ir::condcodes::FloatCC as FCC;
|
||||||
|
fn fcc_of(op: TokenKind) -> FCC {
|
||||||
|
match op {
|
||||||
|
TokenKind::Lt => FCC::LessThan,
|
||||||
|
TokenKind::Gt => FCC::GreaterThan,
|
||||||
|
TokenKind::Le => FCC::LessThanOrEqual,
|
||||||
|
TokenKind::Ge => FCC::GreaterThanOrEqual,
|
||||||
|
TokenKind::Eq => FCC::Equal,
|
||||||
|
TokenKind::Ne => FCC::NotEqual,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(if node.ty.is_integer() {
|
||||||
|
let signed = node.ty.is_signed();
|
||||||
|
match op {
|
||||||
|
TokenKind::Add => self.bl.ins().iadd(lhs, rhs),
|
||||||
|
TokenKind::Sub => self.bl.ins().isub(lhs, rhs),
|
||||||
|
TokenKind::Mul => self.bl.ins().imul(lhs, rhs),
|
||||||
|
TokenKind::Shl => self.bl.ins().ishl(lhs, rhs),
|
||||||
|
TokenKind::Xor => self.bl.ins().bxor(lhs, rhs),
|
||||||
|
TokenKind::Band => self.bl.ins().band(lhs, rhs),
|
||||||
|
TokenKind::Bor => self.bl.ins().bor(lhs, rhs),
|
||||||
|
|
||||||
|
TokenKind::Div if signed => self.bl.ins().sdiv(lhs, rhs),
|
||||||
|
TokenKind::Mod if signed => self.bl.ins().srem(lhs, rhs),
|
||||||
|
TokenKind::Shr if signed => self.bl.ins().sshr(lhs, rhs),
|
||||||
|
|
||||||
|
TokenKind::Div => self.bl.ins().udiv(lhs, rhs),
|
||||||
|
TokenKind::Mod => self.bl.ins().urem(lhs, rhs),
|
||||||
|
TokenKind::Shr => self.bl.ins().ushr(lhs, rhs),
|
||||||
|
|
||||||
|
TokenKind::Lt
|
||||||
|
| TokenKind::Gt
|
||||||
|
| TokenKind::Le
|
||||||
|
| TokenKind::Ge
|
||||||
|
| TokenKind::Eq
|
||||||
|
| TokenKind::Ne => self.bl.ins().icmp(icc_of(op, signed), lhs, rhs),
|
||||||
|
op => todo!("{op}"),
|
||||||
|
}
|
||||||
|
} else if node.ty.is_float() {
|
||||||
|
match op {
|
||||||
|
TokenKind::Add => self.bl.ins().fadd(lhs, rhs),
|
||||||
|
TokenKind::Sub => self.bl.ins().fsub(lhs, rhs),
|
||||||
|
TokenKind::Mul => self.bl.ins().fmul(lhs, rhs),
|
||||||
|
TokenKind::Div => self.bl.ins().fdiv(lhs, rhs),
|
||||||
|
|
||||||
|
TokenKind::Lt
|
||||||
|
| TokenKind::Gt
|
||||||
|
| TokenKind::Le
|
||||||
|
| TokenKind::Ge
|
||||||
|
| TokenKind::Eq
|
||||||
|
| TokenKind::Ne => self.bl.ins().fcmp(fcc_of(op), lhs, rhs),
|
||||||
|
op => todo!("{op}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Kind::RetVal => Ok(self.value_of(node.inputs[0])),
|
||||||
|
Kind::UnOp { op } => {
|
||||||
|
let oper = self.value_of(node.inputs[1]);
|
||||||
|
let dst = node.ty;
|
||||||
|
let src = self
|
||||||
|
.tys
|
||||||
|
.inner_of(self.nodes[node.inputs[1]].ty)
|
||||||
|
.unwrap_or(self.nodes[node.inputs[1]].ty);
|
||||||
|
|
||||||
|
let dty = ty_to_clif_ty(dst, self.tys);
|
||||||
|
Ok(match op {
|
||||||
|
TokenKind::Sub => self.bl.ins().ineg(oper),
|
||||||
|
TokenKind::Not => self.bl.ins().bnot(oper),
|
||||||
|
TokenKind::Float if dst.is_float() && src.is_unsigned() => {
|
||||||
|
self.bl.ins().fcvt_from_uint(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Float if dst.is_float() && src.is_signed() => {
|
||||||
|
self.bl.ins().fcvt_from_sint(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Number if src.is_float() && dst.is_unsigned() => {
|
||||||
|
self.bl.ins().fcvt_to_uint(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Number
|
||||||
|
if src.is_signed() && (dst.is_integer() || dst.is_pointer()) =>
|
||||||
|
{
|
||||||
|
self.bl.ins().sextend(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Number
|
||||||
|
if (src.is_unsigned() || src == hblang::ty::Id::BOOL)
|
||||||
|
&& (dst.is_integer() || dst.is_pointer()) =>
|
||||||
|
{
|
||||||
|
self.bl.ins().uextend(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Float if dst == hblang::ty::Id::F64 && src.is_float() => {
|
||||||
|
self.bl.ins().fpromote(dty, oper)
|
||||||
|
}
|
||||||
|
TokenKind::Float if dst == hblang::ty::Id::F32 && src.is_float() => {
|
||||||
|
self.bl.ins().fdemote(dty, oper)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Kind::Stck => {
|
||||||
|
let slot = self.bl.create_sized_stack_slot(cranelift_codegen::ir::StackSlotData {
|
||||||
|
kind: cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
|
||||||
|
size: self.tys.size_of(node.ty),
|
||||||
|
align_shift: self.tys.align_of(node.ty).ilog2() as _,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(self.bl.ins().stack_addr(cranelift_codegen::ir::types::I64, slot, 0))
|
||||||
|
}
|
||||||
|
Kind::Global { global } => {
|
||||||
|
let glob_ref = {
|
||||||
|
// already deduplicated by the SoN
|
||||||
|
let colocated = true;
|
||||||
|
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||||
|
cranelift_codegen::ir::UserExternalName {
|
||||||
|
namespace: 1,
|
||||||
|
index: global.index() as u32,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.bl.func.create_global_value(
|
||||||
|
cranelift_codegen::ir::GlobalValueData::Symbol {
|
||||||
|
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
||||||
|
offset: cranelift_codegen::ir::immediates::Imm64::new(0),
|
||||||
|
colocated,
|
||||||
|
tls: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(self.bl.ins().global_value(cranelift_codegen::ir::types::I64, glob_ref))
|
||||||
|
}
|
||||||
|
Kind::Load if node.ty.is_aggregate(self.tys) => return,
|
||||||
|
Kind::Load => {
|
||||||
|
let ptr = self.value_of(node.inputs[1]);
|
||||||
|
Ok(self.bl.ins().load(ty_to_clif_ty(node.ty, self.tys), MemFlags::new(), ptr, 0))
|
||||||
|
}
|
||||||
|
Kind::Stre if node.ty.is_aggregate(self.tys) => {
|
||||||
|
let src = self.value_of(self.nodes[node.inputs[1]].inputs[1]);
|
||||||
|
let dest = self.value_of(node.inputs[2]);
|
||||||
|
self.bl.emit_small_memory_copy(
|
||||||
|
self.isa.frontend_config(),
|
||||||
|
dest,
|
||||||
|
src,
|
||||||
|
self.tys.size_of(node.ty) as _,
|
||||||
|
self.tys.align_of(node.ty) as _,
|
||||||
|
self.tys.align_of(node.ty) as _,
|
||||||
|
false,
|
||||||
|
MemFlags::new(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Kind::Stre => {
|
||||||
|
let value = self.value_of(node.inputs[1]);
|
||||||
|
let ptr = self.value_of(node.inputs[2]);
|
||||||
|
self.bl.ins().store(MemFlags::new(), value, ptr, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Kind::End | Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops | Kind::Join => return,
|
Kind::End | Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops | Kind::Join => return,
|
||||||
Kind::Assert { .. } => unreachable!(),
|
Kind::Assert { .. } => unreachable!(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -532,10 +532,21 @@ fn test_parse_files(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
static CWD: std::sync::LazyLock<std::path::PathBuf> =
|
||||||
|
std::sync::LazyLock::new(|| std::env::current_dir().unwrap_or_default());
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn strip_cwd(path: &str) -> &str {
|
||||||
|
std::path::Path::new(path)
|
||||||
|
.strip_prefix(&*CWD)
|
||||||
|
.unwrap_or(std::path::Path::new(path))
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn display_rel_path(path: &(impl AsRef<std::ffi::OsStr> + ?Sized)) -> std::path::Display {
|
pub fn display_rel_path(path: &(impl AsRef<std::ffi::OsStr> + ?Sized)) -> std::path::Display {
|
||||||
static CWD: std::sync::LazyLock<std::path::PathBuf> =
|
|
||||||
std::sync::LazyLock::new(|| std::env::current_dir().unwrap_or_default());
|
|
||||||
std::path::Path::new(path).strip_prefix(&*CWD).unwrap_or(std::path::Path::new(path)).display()
|
std::path::Path::new(path).strip_prefix(&*CWD).unwrap_or(std::path::Path::new(path)).display()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue