polishing the compiler cli (cheating with clap)
also adding the raylib example Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
d25540dd52
commit
58479deca1
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,6 +4,7 @@ rustc-ice-*
|
|||
|
||||
a.out
|
||||
out.o
|
||||
/examples/raylib/main
|
||||
|
||||
# sqlite
|
||||
db.sqlite
|
||||
|
|
137
Cargo.lock
generated
137
Cargo.lock
generated
|
@ -44,6 +44,55 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.95"
|
||||
|
@ -323,6 +372,46 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.51"
|
||||
|
@ -332,6 +421,12 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "const_format"
|
||||
version = "0.2.33"
|
||||
|
@ -572,7 +667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -769,6 +864,7 @@ version = "0.1.0"
|
|||
name = "hbc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"cranelift-backend",
|
||||
"hblang",
|
||||
"log",
|
||||
|
@ -818,7 +914,7 @@ version = "0.5.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -945,6 +1041,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
|
@ -1086,7 +1188,7 @@ dependencies = [
|
|||
"hermit-abi",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1288,7 +1390,7 @@ dependencies = [
|
|||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1333,7 +1435,7 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1477,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1492,6 +1594,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
@ -1559,7 +1667,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1690,6 +1798,12 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
@ -1805,6 +1919,15 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.23", features = ["derive", "env"] }
|
||||
cranelift-backend = { version = "0.1.0", path = "../cranelift-backend" }
|
||||
hblang = { workspace = true, features = ["std"] }
|
||||
log = "0.4.22"
|
||||
|
|
|
@ -1,31 +1,78 @@
|
|||
use std::io;
|
||||
use {
|
||||
clap::Parser,
|
||||
std::{io, str::FromStr},
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
/// format depends on the backend used
|
||||
/// - cranelift-backend expects `<key>=<value>,...` pass `help=me` to see options
|
||||
#[clap(long, env, default_value = "")]
|
||||
backend_flags: String,
|
||||
#[clap(long, short, env, default_value_t = target_lexicon::HOST)]
|
||||
target: target_lexicon::Triple,
|
||||
#[clap(long, env, value_parser = ["ableos"])]
|
||||
path_resolver: Option<String>,
|
||||
/// format the source code reachable form the root file
|
||||
#[clap(long, env, default_value_t = false, conflicts_with_all = &["fmt_stdout", "dump_asm"])]
|
||||
fmt: bool,
|
||||
/// format the root file only and output the formatted file into stdout
|
||||
#[clap(long, env, default_value_t = false, conflicts_with_all = &["fmt", "dump_asm"])]
|
||||
fmt_stdout: bool,
|
||||
#[clap(long, env, default_value_t = false, conflicts_with_all = &["fmt", "fmt_stdout"])]
|
||||
dump_asm: bool,
|
||||
/// extra threads to be used during compilation (currently only parser is parallelized)
|
||||
#[clap(long, env, default_value_t = 0)]
|
||||
extra_threads: usize,
|
||||
/// path to the root file
|
||||
file: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use std::io::Write;
|
||||
|
||||
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
|
||||
let args = std::env::args().collect::<Vec<_>>();
|
||||
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let Args {
|
||||
backend_flags,
|
||||
target,
|
||||
path_resolver,
|
||||
fmt,
|
||||
fmt_stdout,
|
||||
dump_asm,
|
||||
extra_threads,
|
||||
file,
|
||||
} = Args::parse();
|
||||
|
||||
let resolvers = &[("ableos", hblang::ABLEOS_PATH_RESOLVER)];
|
||||
|
||||
let mut native = None;
|
||||
let backend = match args.iter().position(|&v| v == "--target").map(|i| args[i + 1]) {
|
||||
Some(hblang::backend::hbvm::TARGET_TRIPLE) => None,
|
||||
Some(target) => Some(
|
||||
let backend = if target
|
||||
== target_lexicon::Triple::from_str(hblang::backend::hbvm::TARGET_TRIPLE).unwrap()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
native.insert(
|
||||
cranelift_backend::Backend::new(target.parse().map_err(io::Error::other)?)
|
||||
cranelift_backend::Backend::new(target, &backend_flags)
|
||||
.map_err(io::Error::other)?,
|
||||
) as &mut dyn hblang::backend::Backend,
|
||||
),
|
||||
None => Some(native.insert(
|
||||
cranelift_backend::Backend::new(target_lexicon::HOST).map_err(io::Error::other)?,
|
||||
) as &mut dyn hblang::backend::Backend),
|
||||
)
|
||||
};
|
||||
|
||||
let opts = hblang::Options::from_args(&args, out, resolvers, backend)?;
|
||||
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
|
||||
let opts = hblang::Options {
|
||||
fmt,
|
||||
fmt_stdout,
|
||||
dump_asm,
|
||||
extra_threads,
|
||||
resolver: resolvers
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|&(name, _)| Some(name) == path_resolver.as_deref())
|
||||
.map(|(_, v)| v),
|
||||
backend,
|
||||
};
|
||||
|
||||
hblang::run_compiler(file, opts, out, warnings)
|
||||
hblang::run_compiler(&file, opts, out, warnings)
|
||||
}
|
||||
|
||||
log::set_logger(&hblang::fs::Logger).unwrap();
|
||||
|
@ -38,9 +85,10 @@ fn main() {
|
|||
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
||||
std::io::stdout().write_all(&out).unwrap()
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
||||
std::io::stderr().write_all(&out).unwrap();
|
||||
std::eprint!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,51 +3,59 @@
|
|||
use {
|
||||
core::panic,
|
||||
cranelift_codegen::{
|
||||
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||
ir::{InstBuilder, MemFlags, TrapCode, UserExternalName},
|
||||
self as cc, CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||
ir::{self as cir, InstBuilder, MemFlags, TrapCode, UserExternalName, condcodes},
|
||||
isa::{LookupError, TargetIsa},
|
||||
settings::Configurable,
|
||||
settings::{Configurable, SetError},
|
||||
},
|
||||
cranelift_frontend::FunctionBuilder,
|
||||
cranelift_module::{Module, ModuleError},
|
||||
cranelift_frontend::{self as cf, FunctionBuilder},
|
||||
cranelift_module::{self as cm, Module, ModuleError},
|
||||
hblang::{
|
||||
lexer::TokenKind,
|
||||
nodes::Kind,
|
||||
utils::{Ent, EntVec},
|
||||
nodes::{self as hbnodes},
|
||||
ty as hbty,
|
||||
utils::{self as hbutils, Ent, EntVec},
|
||||
},
|
||||
std::{
|
||||
fmt::{Display, Write},
|
||||
ops::Range,
|
||||
},
|
||||
std::{fmt::Display, ops::Range},
|
||||
};
|
||||
|
||||
mod x86_64;
|
||||
|
||||
pub struct Backend {
|
||||
ctx: cranelift_codegen::Context,
|
||||
dt_ctx: cranelift_module::DataDescription,
|
||||
fb_ctx: cranelift_frontend::FunctionBuilderContext,
|
||||
ctx: cc::Context,
|
||||
dt_ctx: cm::DataDescription,
|
||||
fb_ctx: cf::FunctionBuilderContext,
|
||||
module: Option<cranelift_object::ObjectModule>,
|
||||
ctrl_plane: cranelift_codegen::control::ControlPlane,
|
||||
ctrl_plane: cc::control::ControlPlane,
|
||||
funcs: Functions,
|
||||
globals: EntVec<hblang::ty::Global, Global>,
|
||||
globals: EntVec<hbty::Global, Global>,
|
||||
asm: Assembler,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
pub fn new(triple: target_lexicon::Triple) -> Result<Self, BackendCreationError> {
|
||||
pub fn new(triple: target_lexicon::Triple, flags: &str) -> Result<Self, BackendCreationError> {
|
||||
Ok(Self {
|
||||
ctx: cranelift_codegen::Context::new(),
|
||||
dt_ctx: cranelift_module::DataDescription::new(),
|
||||
fb_ctx: cranelift_frontend::FunctionBuilderContext::default(),
|
||||
ctrl_plane: cranelift_codegen::control::ControlPlane::default(),
|
||||
ctx: cc::Context::new(),
|
||||
dt_ctx: cm::DataDescription::new(),
|
||||
fb_ctx: cf::FunctionBuilderContext::default(),
|
||||
ctrl_plane: cc::control::ControlPlane::default(),
|
||||
module: cranelift_object::ObjectModule::new(cranelift_object::ObjectBuilder::new(
|
||||
cranelift_codegen::isa::lookup(triple)?.finish(
|
||||
cranelift_codegen::settings::Flags::new({
|
||||
let mut bl = cranelift_codegen::settings::builder();
|
||||
bl.set("enable_verifier", "true").unwrap();
|
||||
bl
|
||||
}),
|
||||
)?,
|
||||
cc::isa::lookup(triple)?.finish(cc::settings::Flags::new({
|
||||
let mut bl = cc::settings::builder();
|
||||
for (k, v) in flags.split(',').filter_map(|s| s.split_once('=')) {
|
||||
bl.set(k, v).map_err(|err| BackendCreationError::InvalidFlag {
|
||||
key: k.to_owned(),
|
||||
value: v.to_owned(),
|
||||
err,
|
||||
})?;
|
||||
}
|
||||
bl
|
||||
}))?,
|
||||
"main",
|
||||
cranelift_module::default_libcall_names(),
|
||||
cm::default_libcall_names(),
|
||||
)?)
|
||||
.into(),
|
||||
funcs: Default::default(),
|
||||
|
@ -60,9 +68,9 @@ impl Backend {
|
|||
impl hblang::backend::Backend for Backend {
|
||||
fn assemble_reachable(
|
||||
&mut self,
|
||||
from: hblang::ty::Func,
|
||||
types: &hblang::ty::Types,
|
||||
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||
from: hbty::Func,
|
||||
types: &hbty::Types,
|
||||
files: &hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> hblang::backend::AssemblySpec {
|
||||
debug_assert!(self.asm.frontier.is_empty());
|
||||
|
@ -71,10 +79,10 @@ impl hblang::backend::Backend for Backend {
|
|||
|
||||
let mut module = self.module.take().expect("backend can assemble only once");
|
||||
|
||||
fn clif_name_to_ty(name: UserExternalName) -> hblang::ty::Id {
|
||||
fn clif_name_to_ty(name: UserExternalName) -> hbty::Id {
|
||||
match name.namespace {
|
||||
0 => hblang::ty::Kind::Func(hblang::ty::Func::new(name.index as _)),
|
||||
1 => hblang::ty::Kind::Global(hblang::ty::Global::new(name.index as _)),
|
||||
0 => hbty::Kind::Func(hbty::Func::new(name.index as _)),
|
||||
1 => hbty::Kind::Global(hbty::Global::new(name.index as _)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.compress()
|
||||
|
@ -85,12 +93,16 @@ impl hblang::backend::Backend for Backend {
|
|||
self.asm.frontier.push(from.into());
|
||||
while let Some(itm) = self.asm.frontier.pop() {
|
||||
match itm.expand() {
|
||||
hblang::ty::Kind::Func(func) => {
|
||||
hbty::Kind::Func(func) => {
|
||||
let fd = &types.ins.funcs[func];
|
||||
if fd.is_import {
|
||||
self.funcs.headers.shadow(func.index() + 1);
|
||||
}
|
||||
let fuc = &mut self.funcs.headers[func];
|
||||
let file = &files[fd.file];
|
||||
if fuc.module_id.is_some() {
|
||||
continue;
|
||||
}
|
||||
self.asm.funcs.push(func);
|
||||
self.asm.frontier.extend(
|
||||
fuc.external_names.clone().map(|r| {
|
||||
clif_name_to_ty(self.funcs.external_names[r as usize].clone())
|
||||
|
@ -99,20 +111,23 @@ impl hblang::backend::Backend for Backend {
|
|||
self.asm.name.clear();
|
||||
if func == from {
|
||||
self.asm.name.push_str("main");
|
||||
} else if fd.is_import {
|
||||
self.asm.name.push_str(file.ident_str(fd.name));
|
||||
} else {
|
||||
let file = &files[types.ins.funcs[func].file];
|
||||
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
||||
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(fd.name));
|
||||
}
|
||||
let linkage = if func == from {
|
||||
cranelift_module::Linkage::Export
|
||||
cm::Linkage::Export
|
||||
} else if fd.is_import {
|
||||
cm::Linkage::Import
|
||||
} else {
|
||||
cranelift_module::Linkage::Local
|
||||
cm::Linkage::Local
|
||||
};
|
||||
build_signature(
|
||||
module.isa().default_call_conv(),
|
||||
types.ins.funcs[func].sig,
|
||||
fd.sig,
|
||||
types,
|
||||
&mut self.ctx.func.signature,
|
||||
&mut vec![],
|
||||
|
@ -122,25 +137,31 @@ impl hblang::backend::Backend for Backend {
|
|||
.declare_function(&self.asm.name, linkage, &self.ctx.func.signature)
|
||||
.unwrap(),
|
||||
);
|
||||
if !fd.is_import {
|
||||
self.asm.funcs.push(func);
|
||||
}
|
||||
}
|
||||
hblang::ty::Kind::Global(glob) => {
|
||||
hbty::Kind::Global(glob) => {
|
||||
if self.globals[glob].module_id.is_some() {
|
||||
continue;
|
||||
}
|
||||
self.asm.globals.push(glob);
|
||||
|
||||
self.asm.name.clear();
|
||||
let file = &files[types.ins.globals[glob].file];
|
||||
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
||||
self.asm.name.push('.');
|
||||
self.asm.name.push_str(file.ident_str(types.ins.globals[glob].name));
|
||||
let mutable = if types.ins.globals[glob].file == Default::default() {
|
||||
writeln!(self.asm.name, "anon{}", glob.index()).unwrap();
|
||||
false
|
||||
} else {
|
||||
let file = &files[types.ins.globals[glob].file];
|
||||
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
||||
self.asm.name.push('.');
|
||||
self.asm.name.push_str(file.ident_str(types.ins.globals[glob].name));
|
||||
true
|
||||
};
|
||||
|
||||
self.globals[glob].module_id = Some(
|
||||
module
|
||||
.declare_data(
|
||||
&self.asm.name,
|
||||
cranelift_module::Linkage::Local,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.declare_data(&self.asm.name, cm::Linkage::Local, mutable, false)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
@ -150,14 +171,22 @@ impl hblang::backend::Backend for Backend {
|
|||
|
||||
for &func in &self.asm.funcs {
|
||||
let fuc = &self.funcs.headers[func];
|
||||
assert!(!types.ins.funcs[func].is_import);
|
||||
debug_assert!(!fuc.code.is_empty());
|
||||
let names = &mut self.funcs.external_names
|
||||
[fuc.external_names.start as usize..fuc.external_names.end as usize];
|
||||
names.iter_mut().for_each(|nm| {
|
||||
nm.index = self.funcs.headers[hblang::ty::Func::new(nm.index as _)]
|
||||
.module_id
|
||||
.unwrap()
|
||||
.as_u32();
|
||||
self.ctx.func.clear();
|
||||
names.iter().for_each(|nm| {
|
||||
let mut nm = nm.clone();
|
||||
if nm.namespace == 0 {
|
||||
nm.index = self.funcs.headers[hbty::Func::new(nm.index as _)]
|
||||
.module_id
|
||||
.unwrap()
|
||||
.as_u32();
|
||||
} else {
|
||||
nm.index =
|
||||
self.globals[hbty::Global::new(nm.index as _)].module_id.unwrap().as_u32();
|
||||
}
|
||||
self.ctx.func.params.ensure_user_func_name(nm.clone());
|
||||
});
|
||||
module
|
||||
|
@ -187,8 +216,8 @@ impl hblang::backend::Backend for Backend {
|
|||
&'a self,
|
||||
_sluce: &[u8],
|
||||
_eca_handler: &mut dyn FnMut(&mut &[u8]),
|
||||
_types: &'a hblang::ty::Types,
|
||||
_files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||
_types: &'a hbty::Types,
|
||||
_files: &'a hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||
_output: &mut String,
|
||||
) -> Result<(), std::boxed::Box<dyn core::error::Error + Send + Sync + 'a>> {
|
||||
unimplemented!()
|
||||
|
@ -196,10 +225,10 @@ impl hblang::backend::Backend for Backend {
|
|||
|
||||
fn emit_body(
|
||||
&mut self,
|
||||
id: hblang::ty::Func,
|
||||
nodes: &hblang::nodes::Nodes,
|
||||
tys: &hblang::ty::Types,
|
||||
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||
id: hbty::Func,
|
||||
nodes: &hbnodes::Nodes,
|
||||
tys: &hbty::Types,
|
||||
files: &hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||
) {
|
||||
self.ctx.clear();
|
||||
let isa = self.module.as_ref().unwrap().isa();
|
||||
|
@ -226,12 +255,9 @@ impl hblang::backend::Backend for Backend {
|
|||
.build(tys.ins.funcs[id].sig);
|
||||
|
||||
self.ctx.func.name =
|
||||
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
||||
namespace: 0,
|
||||
index: id.index() as _,
|
||||
});
|
||||
cir::UserFuncName::User(cir::UserExternalName { namespace: 0, index: id.index() as _ });
|
||||
|
||||
std::eprintln!("{}", self.ctx.func.display());
|
||||
//std::eprintln!("{}", self.ctx.func.display());
|
||||
|
||||
self.ctx.compile(isa, &mut self.ctrl_plane).unwrap();
|
||||
let code = self.ctx.compiled_code().unwrap();
|
||||
|
@ -240,15 +266,15 @@ impl hblang::backend::Backend for Backend {
|
|||
}
|
||||
|
||||
fn build_signature(
|
||||
call_conv: cranelift_codegen::isa::CallConv,
|
||||
sig: hblang::ty::Sig,
|
||||
types: &hblang::ty::Types,
|
||||
signature: &mut cranelift_codegen::ir::Signature,
|
||||
call_conv: cc::isa::CallConv,
|
||||
sig: hbty::Sig,
|
||||
types: &hbty::Types,
|
||||
signature: &mut cir::Signature,
|
||||
arg_meta: &mut Vec<AbiMeta>,
|
||||
) -> bool {
|
||||
signature.clear(call_conv);
|
||||
match call_conv {
|
||||
cranelift_codegen::isa::CallConv::SystemV => {
|
||||
cc::isa::CallConv::SystemV => {
|
||||
x86_64::build_systemv_signature(sig, types, signature, arg_meta)
|
||||
}
|
||||
_ => todo!(),
|
||||
|
@ -262,18 +288,18 @@ struct AbiMeta {
|
|||
}
|
||||
|
||||
struct FuncBuilder<'a, 'b> {
|
||||
bl: cranelift_frontend::FunctionBuilder<'b>,
|
||||
bl: cf::FunctionBuilder<'b>,
|
||||
isa: &'a dyn TargetIsa,
|
||||
nodes: &'a hblang::nodes::Nodes,
|
||||
tys: &'a hblang::ty::Types,
|
||||
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
||||
nodes: &'a hbnodes::Nodes,
|
||||
tys: &'a hbty::Types,
|
||||
files: &'a hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||
values: &'b mut [Option<Result<cir::Value, cir::Block>>],
|
||||
arg_lens: &'a [AbiMeta],
|
||||
stack_ret: bool,
|
||||
}
|
||||
|
||||
impl FuncBuilder<'_, '_> {
|
||||
pub fn build(mut self, sig: hblang::ty::Sig) {
|
||||
pub fn build(mut self, sig: hbty::Sig) {
|
||||
let entry = self.bl.create_block();
|
||||
self.bl.append_block_params_for_function_params(entry);
|
||||
self.bl.switch_to_block(entry);
|
||||
|
@ -281,21 +307,21 @@ impl FuncBuilder<'_, '_> {
|
|||
|
||||
if self.stack_ret {
|
||||
let ret_ptr = *arg_vals.take_first().unwrap();
|
||||
self.values[hblang::nodes::MEM as usize] = Some(Ok(ret_ptr));
|
||||
self.values[hbnodes::MEM as usize] = Some(Ok(ret_ptr));
|
||||
}
|
||||
|
||||
let Self { nodes, tys, .. } = self;
|
||||
|
||||
let mut parama_len = self.arg_lens[(self.tys.size_of(sig.ret) != 0) as usize..].iter();
|
||||
let mut parama_len = self.arg_lens[1..].iter();
|
||||
let mut typs = sig.args.args();
|
||||
let mut args = nodes[hblang::nodes::VOID].outputs[hblang::nodes::ARG_START..].iter();
|
||||
let mut args = nodes[hbnodes::VOID].outputs[hbnodes::ARG_START..].iter();
|
||||
while let Some(aty) = typs.next(tys) {
|
||||
let hblang::ty::Arg::Value(ty) = aty else { continue };
|
||||
let hbty::Arg::Value(ty) = aty else { continue };
|
||||
let abi_meta = parama_len.next().unwrap();
|
||||
let &arg = args.next().unwrap();
|
||||
if !abi_meta.trough_mem && ty.is_aggregate(tys) {
|
||||
let slot = self.bl.create_sized_stack_slot(cranelift_codegen::ir::StackSlotData {
|
||||
kind: cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
|
||||
let slot = self.bl.create_sized_stack_slot(cir::StackSlotData {
|
||||
kind: cir::StackSlotKind::ExplicitSlot,
|
||||
size: self.tys.size_of(ty),
|
||||
align_shift: self.tys.align_of(ty).ilog2() as _,
|
||||
});
|
||||
|
@ -315,30 +341,30 @@ impl FuncBuilder<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
self.values[hblang::nodes::ENTRY as usize] = Some(Err(entry));
|
||||
self.values[hbnodes::ENTRY as usize] = Some(Err(entry));
|
||||
|
||||
self.emit_node(hblang::nodes::VOID, hblang::nodes::VOID);
|
||||
self.emit_node(hbnodes::VOID, hbnodes::VOID);
|
||||
|
||||
self.bl.finalize();
|
||||
}
|
||||
|
||||
fn value_of(&self, nid: hblang::nodes::Nid) -> cranelift_codegen::ir::Value {
|
||||
fn value_of(&self, nid: hbnodes::Nid) -> cir::Value {
|
||||
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: hbnodes::Nid) -> cir::Block {
|
||||
self.values[nid as usize].unwrap().unwrap_err()
|
||||
}
|
||||
|
||||
fn close_block(&mut self, nid: hblang::nodes::Nid) {
|
||||
if matches!(self.nodes[nid].kind, Kind::Loop) {
|
||||
fn close_block(&mut self, nid: hbnodes::Nid) {
|
||||
if matches!(self.nodes[nid].kind, hbnodes::Kind::Loop) {
|
||||
return;
|
||||
}
|
||||
self.bl.seal_block(self.block_of(nid));
|
||||
}
|
||||
|
||||
fn emit_node(&mut self, nid: hblang::nodes::Nid, block: hblang::nodes::Nid) {
|
||||
use hblang::nodes::*;
|
||||
fn emit_node(&mut self, nid: hbnodes::Nid, block: hbnodes::Nid) {
|
||||
use hbnodes::*;
|
||||
|
||||
let mut args = vec![];
|
||||
if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) {
|
||||
|
@ -359,10 +385,9 @@ impl FuncBuilder<'_, '_> {
|
|||
let next = self.bl.create_block();
|
||||
for &o in self.nodes[nid].outputs.iter() {
|
||||
if self.nodes[o].is_data_phi() {
|
||||
self.values[o as usize] = Some(Ok(self.bl.append_block_param(
|
||||
next,
|
||||
ty_to_clif_ty(self.nodes[o].ty, self.tys),
|
||||
)));
|
||||
self.values[o as usize] = Some(Ok(self
|
||||
.bl
|
||||
.append_block_param(next, self.nodes[o].ty.to_clif(self.tys))));
|
||||
}
|
||||
}
|
||||
self.bl.ins().jump(next, &args);
|
||||
|
@ -405,7 +430,7 @@ impl FuncBuilder<'_, '_> {
|
|||
if self.nodes[o].is_data_phi() {
|
||||
self.values[o as usize] = Some(Ok(self
|
||||
.bl
|
||||
.append_block_param(next, ty_to_clif_ty(self.nodes[o].ty, self.tys))));
|
||||
.append_block_param(next, self.nodes[o].ty.to_clif(self.tys))));
|
||||
}
|
||||
}
|
||||
self.values[nid as usize] = Some(Err(next));
|
||||
|
@ -434,7 +459,7 @@ impl FuncBuilder<'_, '_> {
|
|||
}
|
||||
Kind::Return { .. } => {
|
||||
let mut ir_args = vec![];
|
||||
if node.inputs[1] == hblang::nodes::VOID {
|
||||
if node.inputs[1] == hbnodes::VOID {
|
||||
} else {
|
||||
let abi_meta = self.arg_lens[0];
|
||||
let arg = node.inputs[1];
|
||||
|
@ -455,14 +480,25 @@ impl FuncBuilder<'_, '_> {
|
|||
));
|
||||
offset += align as i32;
|
||||
}
|
||||
} else if self.stack_ret {
|
||||
let src = self.value_of(self.nodes[arg].inputs[1]);
|
||||
let dest = self.value_of(MEM);
|
||||
self.bl.emit_small_memory_copy(
|
||||
self.isa.frontend_config(),
|
||||
dest,
|
||||
src,
|
||||
self.tys.size_of(self.nodes[arg].ty) as _,
|
||||
self.tys.align_of(self.nodes[arg].ty) as _,
|
||||
self.tys.align_of(self.nodes[arg].ty) as _,
|
||||
false,
|
||||
MemFlags::new(),
|
||||
);
|
||||
} else {
|
||||
ir_args.push(self.value_of(arg));
|
||||
}
|
||||
}
|
||||
|
||||
let ret = self.value_of(node.inputs[1]);
|
||||
|
||||
self.bl.ins().return_(&[ret]);
|
||||
self.bl.ins().return_(&ir_args);
|
||||
self.close_block(block);
|
||||
self.emit_node(node.outputs[0], block);
|
||||
Err(self.block_of(block))
|
||||
|
@ -484,8 +520,7 @@ impl FuncBuilder<'_, '_> {
|
|||
todo!()
|
||||
} else {
|
||||
let mut arg_lens = vec![];
|
||||
let mut signature =
|
||||
cranelift_codegen::ir::Signature::new(self.isa.default_call_conv());
|
||||
let mut signature = cir::Signature::new(self.isa.default_call_conv());
|
||||
let stack_ret = build_signature(
|
||||
self.isa.default_call_conv(),
|
||||
self.tys.ins.funcs[func].sig,
|
||||
|
@ -494,29 +529,28 @@ impl FuncBuilder<'_, '_> {
|
|||
&mut arg_lens,
|
||||
);
|
||||
|
||||
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 _,
|
||||
},
|
||||
);
|
||||
let func_ref =
|
||||
'b: {
|
||||
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||
cir::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;
|
||||
}
|
||||
if let Some(id) = self.bl.func.dfg.ext_funcs.keys().find(|&k| {
|
||||
self.bl.func.dfg.ext_funcs[k].name
|
||||
== cir::ExternalName::user(user_name_ref)
|
||||
}) {
|
||||
break 'b id;
|
||||
}
|
||||
|
||||
let signature = self.bl.func.import_signature(signature.clone());
|
||||
let signature = self.bl.func.import_signature(signature.clone());
|
||||
|
||||
self.bl.func.import_function(cranelift_codegen::ir::ExtFuncData {
|
||||
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
||||
signature,
|
||||
colocated: true,
|
||||
})
|
||||
};
|
||||
self.bl.func.import_function(cir::ExtFuncData {
|
||||
name: cir::ExternalName::user(user_name_ref),
|
||||
signature,
|
||||
// somehow, this works
|
||||
colocated: true, // !self.tys.ins.funcs[func].is_import,
|
||||
})
|
||||
};
|
||||
|
||||
let mut ir_args = vec![];
|
||||
|
||||
|
@ -525,13 +559,15 @@ impl FuncBuilder<'_, '_> {
|
|||
}
|
||||
|
||||
let mut params = signature.params.as_slice();
|
||||
let mut parama_len =
|
||||
arg_lens[(self.tys.size_of(node.ty) != 0) as usize..].iter();
|
||||
let mut parama_len = arg_lens[1..].iter();
|
||||
let mut typs = args.args();
|
||||
let mut args = node.inputs[1..].iter();
|
||||
while let Some(aty) = typs.next(self.tys) {
|
||||
let hblang::ty::Arg::Value(ty) = aty else { continue };
|
||||
let hbty::Arg::Value(ty) = aty else { continue };
|
||||
let abi_meta = parama_len.next().unwrap();
|
||||
if abi_meta.arg_count == 0 {
|
||||
continue;
|
||||
}
|
||||
let &arg = args.next().unwrap();
|
||||
if !abi_meta.trough_mem && ty.is_aggregate(self.tys) {
|
||||
let loc = params.take(..abi_meta.arg_count).unwrap();
|
||||
|
@ -590,101 +626,74 @@ impl FuncBuilder<'_, '_> {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Kind::CInt { value } if self.nodes[nid].ty.is_integer() => Ok(self.bl.ins().iconst(
|
||||
cranelift_codegen::ir::Type::int(self.tys.size_of(self.nodes[nid].ty) as u16 * 8)
|
||||
.unwrap(),
|
||||
Kind::CInt { value } if self.nodes[nid].ty.is_float() => {
|
||||
Ok(match self.tys.size_of(self.nodes[nid].ty) {
|
||||
4 => self.bl.ins().f32const(f64::from_bits(value as _) as f32),
|
||||
8 => self.bl.ins().f64const(f64::from_bits(value as _)),
|
||||
_ => unimplemented!(),
|
||||
})
|
||||
}
|
||||
Kind::CInt { value } => Ok(self.bl.ins().iconst(
|
||||
cir::Type::int(self.tys.size_of(node.ty) as u16 * 8).unwrap_or_else(|| {
|
||||
panic!("{}", hbty::Display::new(self.tys, self.files, node.ty),)
|
||||
}),
|
||||
value,
|
||||
)),
|
||||
Kind::CInt { value } => Ok(match self.tys.size_of(self.nodes[nid].ty) {
|
||||
4 => self.bl.ins().f32const(f64::from_bits(value as _) as f32),
|
||||
8 => self.bl.ins().f64const(f64::from_bits(value as _)),
|
||||
_ => unimplemented!(),
|
||||
}),
|
||||
Kind::BinOp { op } => {
|
||||
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||
let [lhs, rhs] = [self.value_of(lhs), self.value_of(rhs)];
|
||||
assert!(
|
||||
node.ty.is_integer() || node.ty == hblang::ty::Id::BOOL,
|
||||
"TODO: unsupported binary type {}",
|
||||
hblang::ty::Display::new(self.tys, self.files, node.ty)
|
||||
);
|
||||
let [lh, rh] = [self.value_of(lhs), self.value_of(rhs)];
|
||||
|
||||
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,
|
||||
let is_int_op = node.ty.is_integer()
|
||||
|| (node.ty == hbty::Id::BOOL
|
||||
&& (self.nodes[lhs].ty.is_integer()
|
||||
|| self.nodes[lhs].ty == hbty::Id::BOOL));
|
||||
let is_float_op = node.ty.is_float()
|
||||
|| (node.ty == hbty::Id::BOOL && self.nodes[lhs].ty.is_float());
|
||||
|
||||
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() {
|
||||
Ok(if is_int_op {
|
||||
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::Add => self.bl.ins().iadd(lh, rh),
|
||||
TokenKind::Sub => self.bl.ins().isub(lh, rh),
|
||||
TokenKind::Mul => self.bl.ins().imul(lh, rh),
|
||||
TokenKind::Shl => self.bl.ins().ishl(lh, rh),
|
||||
TokenKind::Xor => self.bl.ins().bxor(lh, rh),
|
||||
TokenKind::Band => self.bl.ins().band(lh, rh),
|
||||
TokenKind::Bor => self.bl.ins().bor(lh, rh),
|
||||
|
||||
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 if signed => self.bl.ins().sdiv(lh, rh),
|
||||
TokenKind::Mod if signed => self.bl.ins().srem(lh, rh),
|
||||
TokenKind::Shr if signed => self.bl.ins().sshr(lh, rh),
|
||||
|
||||
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::Div => self.bl.ins().udiv(lh, rh),
|
||||
TokenKind::Mod => self.bl.ins().urem(lh, rh),
|
||||
TokenKind::Shr => self.bl.ins().ushr(lh, rh),
|
||||
|
||||
TokenKind::Lt
|
||||
| TokenKind::Gt
|
||||
| TokenKind::Le
|
||||
| TokenKind::Ge
|
||||
| TokenKind::Eq
|
||||
| TokenKind::Ne => self.bl.ins().icmp(icc_of(op, signed), lhs, rhs),
|
||||
| TokenKind::Ne => self.bl.ins().icmp(op.to_int_cc(signed), lh, rh),
|
||||
op => todo!("{op}"),
|
||||
}
|
||||
} else if node.ty.is_float() {
|
||||
} else if is_float_op {
|
||||
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::Add => self.bl.ins().fadd(lh, rh),
|
||||
TokenKind::Sub => self.bl.ins().fsub(lh, rh),
|
||||
TokenKind::Mul => self.bl.ins().fmul(lh, rh),
|
||||
TokenKind::Div => self.bl.ins().fdiv(lh, rh),
|
||||
|
||||
TokenKind::Lt
|
||||
| TokenKind::Gt
|
||||
| TokenKind::Le
|
||||
| TokenKind::Ge
|
||||
| TokenKind::Eq
|
||||
| TokenKind::Ne => self.bl.ins().fcmp(fcc_of(op), lhs, rhs),
|
||||
| TokenKind::Ne => self.bl.ins().fcmp(op.to_float_cc(), lh, rh),
|
||||
op => todo!("{op}"),
|
||||
}
|
||||
} else {
|
||||
todo!()
|
||||
todo!("{}", hbty::Display::new(self.tys, self.files, node.ty))
|
||||
})
|
||||
}
|
||||
Kind::RetVal => Ok(self.value_of(node.inputs[0])),
|
||||
|
@ -696,7 +705,7 @@ impl FuncBuilder<'_, '_> {
|
|||
.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);
|
||||
let dty = dst.to_clif(self.tys);
|
||||
Ok(match op {
|
||||
TokenKind::Sub => self.bl.ins().ineg(oper),
|
||||
TokenKind::Not => self.bl.ins().bnot(oper),
|
||||
|
@ -715,55 +724,52 @@ impl FuncBuilder<'_, '_> {
|
|||
self.bl.ins().sextend(dty, oper)
|
||||
}
|
||||
TokenKind::Number
|
||||
if (src.is_unsigned() || src == hblang::ty::Id::BOOL)
|
||||
if (src.is_unsigned() || src == hbty::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() => {
|
||||
TokenKind::Float if dst == hbty::Id::F64 && src.is_float() => {
|
||||
self.bl.ins().fpromote(dty, oper)
|
||||
}
|
||||
TokenKind::Float if dst == hblang::ty::Id::F32 && src.is_float() => {
|
||||
TokenKind::Float if dst == hbty::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,
|
||||
let slot = self.bl.create_sized_stack_slot(cir::StackSlotData {
|
||||
kind: cir::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))
|
||||
Ok(self.bl.ins().stack_addr(cir::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 {
|
||||
let user_name_ref =
|
||||
self.bl.func.declare_imported_user_function(cir::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,
|
||||
},
|
||||
)
|
||||
});
|
||||
self.bl.func.create_global_value(cir::GlobalValueData::Symbol {
|
||||
name: cir::ExternalName::user(user_name_ref),
|
||||
offset: cir::immediates::Imm64::new(0),
|
||||
colocated,
|
||||
tls: false,
|
||||
})
|
||||
};
|
||||
|
||||
Ok(self.bl.ins().global_value(cranelift_codegen::ir::types::I64, glob_ref))
|
||||
Ok(self.bl.ins().global_value(cir::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))
|
||||
Ok(self.bl.ins().load(node.ty.to_clif(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]);
|
||||
|
@ -792,22 +798,72 @@ impl FuncBuilder<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ty_to_clif_ty(ty: hblang::ty::Id, tys: &hblang::ty::Types) -> cranelift_codegen::ir::Type {
|
||||
if ty.is_integer() {
|
||||
cranelift_codegen::ir::Type::int(tys.size_of(ty) as u16 * 8).unwrap()
|
||||
} else {
|
||||
unimplemented!()
|
||||
trait ToCondcodes {
|
||||
fn to_int_cc(self, signed: bool) -> condcodes::IntCC;
|
||||
fn to_float_cc(self) -> condcodes::FloatCC;
|
||||
}
|
||||
|
||||
impl ToCondcodes for TokenKind {
|
||||
fn to_int_cc(self, signed: bool) -> condcodes::IntCC {
|
||||
use condcodes::IntCC as ICC;
|
||||
match self {
|
||||
Self::Lt if signed => ICC::SignedLessThan,
|
||||
Self::Gt if signed => ICC::SignedGreaterThan,
|
||||
Self::Le if signed => ICC::SignedLessThanOrEqual,
|
||||
Self::Ge if signed => ICC::SignedGreaterThanOrEqual,
|
||||
|
||||
Self::Lt => ICC::UnsignedLessThan,
|
||||
Self::Gt => ICC::UnsignedGreaterThan,
|
||||
Self::Le => ICC::UnsignedLessThanOrEqual,
|
||||
Self::Ge => ICC::UnsignedGreaterThanOrEqual,
|
||||
|
||||
Self::Eq => ICC::Equal,
|
||||
Self::Ne => ICC::NotEqual,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_float_cc(self) -> condcodes::FloatCC {
|
||||
use condcodes::FloatCC as FCC;
|
||||
match self {
|
||||
Self::Lt => FCC::LessThan,
|
||||
Self::Gt => FCC::GreaterThan,
|
||||
Self::Le => FCC::LessThanOrEqual,
|
||||
Self::Ge => FCC::GreaterThanOrEqual,
|
||||
Self::Eq => FCC::Equal,
|
||||
Self::Ne => FCC::NotEqual,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ToClifTy {
|
||||
fn to_clif(self, cx: &hbty::Types) -> cir::Type;
|
||||
}
|
||||
|
||||
impl ToClifTy for hbty::Id {
|
||||
fn to_clif(self, cx: &hbty::Types) -> cir::Type {
|
||||
debug_assert!(!self.is_aggregate(cx));
|
||||
if self.is_integer() | self.is_pointer() | self.is_optional() || self == hbty::Id::BOOL {
|
||||
cir::Type::int(cx.size_of(self) as u16 * 8).unwrap()
|
||||
} else if self == hbty::Id::F32 {
|
||||
cir::types::F32
|
||||
} else if self == hbty::Id::F64 {
|
||||
cir::types::F64
|
||||
} else {
|
||||
unimplemented!("{:?}", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Global {
|
||||
module_id: Option<cranelift_module::DataId>,
|
||||
module_id: Option<cm::DataId>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FuncHeaders {
|
||||
module_id: Option<cranelift_module::FuncId>,
|
||||
module_id: Option<cm::FuncId>,
|
||||
alignment: u32,
|
||||
code: Range<u32>,
|
||||
relocs: Range<u32>,
|
||||
|
@ -816,19 +872,14 @@ struct FuncHeaders {
|
|||
|
||||
#[derive(Default)]
|
||||
struct Functions {
|
||||
headers: EntVec<hblang::ty::Func, FuncHeaders>,
|
||||
headers: EntVec<hbty::Func, FuncHeaders>,
|
||||
code: Vec<u8>,
|
||||
relocs: Vec<FinalizedMachReloc>,
|
||||
external_names: Vec<UserExternalName>,
|
||||
}
|
||||
|
||||
impl Functions {
|
||||
fn push(
|
||||
&mut self,
|
||||
id: hblang::ty::Func,
|
||||
func: &cranelift_codegen::ir::Function,
|
||||
code: &MachBufferFinalized<Final>,
|
||||
) {
|
||||
fn push(&mut self, id: hbty::Func, func: &cir::Function, code: &MachBufferFinalized<Final>) {
|
||||
self.headers.shadow(id.index() + 1);
|
||||
self.headers[id] = FuncHeaders {
|
||||
module_id: None,
|
||||
|
@ -847,9 +898,9 @@ impl Functions {
|
|||
#[derive(Default)]
|
||||
struct Assembler {
|
||||
name: String,
|
||||
frontier: Vec<hblang::ty::Id>,
|
||||
globals: Vec<hblang::ty::Global>,
|
||||
funcs: Vec<hblang::ty::Func>,
|
||||
frontier: Vec<hbty::Id>,
|
||||
globals: Vec<hbty::Global>,
|
||||
funcs: Vec<hbty::Func>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -857,6 +908,7 @@ pub enum BackendCreationError {
|
|||
UnsupportedTriplet(LookupError),
|
||||
InvalidFlags(CodegenError),
|
||||
UnsupportedModuleConfig(ModuleError),
|
||||
InvalidFlag { key: String, value: String, err: SetError },
|
||||
}
|
||||
|
||||
impl Display for BackendCreationError {
|
||||
|
@ -871,6 +923,13 @@ impl Display for BackendCreationError {
|
|||
BackendCreationError::UnsupportedModuleConfig(err) => {
|
||||
write!(f, "Unsupported module configuration: {}", err)
|
||||
}
|
||||
BackendCreationError::InvalidFlag { key, value, err } => {
|
||||
write!(
|
||||
f,
|
||||
"Problem setting a '{key}' to '{value}': {err}\navailable flags: {}",
|
||||
cc::settings::Flags::new(cc::settings::builder())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// The classification code for the x86_64 ABI is taken from the clay language
|
||||
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
||||
|
||||
use crate::AbiMeta;
|
||||
use {crate::AbiMeta, hblang::ty};
|
||||
|
||||
pub fn build_systemv_signature(
|
||||
sig: hblang::ty::Sig,
|
||||
|
@ -12,11 +12,14 @@ pub fn build_systemv_signature(
|
|||
let mut alloca = Alloca::new();
|
||||
|
||||
alloca.next(false, sig.ret, types, &mut signature.returns);
|
||||
let stack_ret = signature.params.len() == 1
|
||||
&& signature.params[0].purpose == cranelift_codegen::ir::ArgumentPurpose::StructReturn;
|
||||
let stack_ret = signature.returns.len() == 1
|
||||
&& signature.returns[0].purpose == cranelift_codegen::ir::ArgumentPurpose::StructReturn;
|
||||
|
||||
if stack_ret {
|
||||
signature.params.append(&mut signature.returns);
|
||||
arg_lens.push(AbiMeta { arg_count: signature.params.len(), trough_mem: true });
|
||||
} else {
|
||||
arg_lens.push(AbiMeta { arg_count: signature.returns.len(), trough_mem: false });
|
||||
}
|
||||
|
||||
let mut args = sig.args.args();
|
||||
|
@ -66,7 +69,7 @@ fn classify_arg(
|
|||
|
||||
let mut c = match layout.expand() {
|
||||
_ if size == 0 => return Ok(()),
|
||||
_ if layout.is_integer() || layout.is_pointer() => Class::Int,
|
||||
_ if layout.is_integer() || layout.is_pointer() || layout == ty::Id::BOOL => Class::Int,
|
||||
_ if layout.is_float() => Class::Sse,
|
||||
|
||||
hblang::ty::Kind::Struct(s) => {
|
||||
|
@ -115,7 +118,7 @@ fn classify_arg(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
ty => unimplemented!("{ty:?}"),
|
||||
};
|
||||
|
||||
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
|
||||
|
@ -241,6 +244,10 @@ impl Alloca {
|
|||
cx: &hblang::ty::Types,
|
||||
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
||||
) -> bool {
|
||||
if cx.size_of(arg) == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut cls_or_mem = classify_arg(cx, arg);
|
||||
|
||||
if is_arg {
|
||||
|
|
47
examples/raylib/main.hb
Normal file
47
examples/raylib/main.hb
Normal file
|
@ -0,0 +1,47 @@
|
|||
InitWindow := fn(w: uint, h: uint, name: ^u8): uint @import()
|
||||
WindowShouldClose := fn(): bool @import()
|
||||
BeginDrawing := fn(): void @import()
|
||||
EndDrawing := fn(): void @import()
|
||||
DrawRectangleV := fn(pos: Vec2, size: Vec2, color: Color): void @import()
|
||||
DrawRectangle := fn(a: uint, b: uint, c: uint, d: uint, color: Color): void @import()
|
||||
ClearBackground := fn(color: Color): void @import()
|
||||
SetTargetFPS := fn(target: uint): void @import()
|
||||
GetFrameTime := fn(): f32 @import()
|
||||
|
||||
Vec2 := struct {x: f32, y: f32}
|
||||
Color := struct {r: u8, g: u8, b: u8, a: u8}
|
||||
|
||||
$W := 800
|
||||
$H := 600
|
||||
|
||||
main := fn(): uint {
|
||||
_ = InitWindow(W, H, "whawee\0".ptr)
|
||||
|
||||
SetTargetFPS(60)
|
||||
|
||||
pos := Vec2.(100, 100)
|
||||
vel := Vec2.(300, 300)
|
||||
size := Vec2.(100, 100)
|
||||
color := Color.(17, 255, 17, 255)
|
||||
|
||||
loop if WindowShouldClose() break else {
|
||||
BeginDrawing()
|
||||
ClearBackground(.(0, 0, 0, 255))
|
||||
|
||||
DrawRectangleV(pos, size, color)
|
||||
pos += vel * .(GetFrameTime(), GetFrameTime())
|
||||
|
||||
if pos.x < 0 | pos.x + size.x > W {
|
||||
vel.x *= -1
|
||||
color += .(32, 11, 20, 0)
|
||||
}
|
||||
|
||||
if pos.y < 0 | pos.y + size.y > H {
|
||||
vel.y *= -1
|
||||
color += .(32, 11, 20, 0)
|
||||
}
|
||||
EndDrawing()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
4
examples/raylib/run.sh
Executable file
4
examples/raylib/run.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
DIR=$(dirname $0)
|
||||
cd $DIR
|
||||
cargo run -p hbc main.hb > out.o && gcc -o main out.o -lraylib -lm -ldl -lpthread -lrt -lGL -lX11 && ./main
|
|
@ -1,5 +0,0 @@
|
|||
--fmt - format all imported source files
|
||||
--fmt-stdout - dont write the formatted file but print it
|
||||
--dump-asm - output assembly instead of raw code, (the assembly is more for debugging the compiler)
|
||||
--threads <1...> - number of extra threads compiler can use [default: 0]
|
||||
--path-resolver <name> - choose between builtin path resolvers, options are: ableos
|
|
@ -106,7 +106,7 @@ pub struct HbvmBackend {
|
|||
offsets: Vec<Offset>,
|
||||
}
|
||||
|
||||
pub const TARGET_TRIPLE: &str = "hbvm-virt-ableos";
|
||||
pub const TARGET_TRIPLE: &str = "unknown-virt-unknown";
|
||||
|
||||
impl HbvmBackend {
|
||||
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
|
||||
|
|
|
@ -6,7 +6,7 @@ use {
|
|||
ty, FnvBuildHasher,
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{fmt::Write, num::NonZeroUsize, ops::Deref},
|
||||
core::{fmt::Write, ops::Deref},
|
||||
hashbrown::hash_map,
|
||||
std::{
|
||||
borrow::ToOwned,
|
||||
|
@ -74,62 +74,6 @@ pub struct Options<'a> {
|
|||
pub backend: Option<&'a mut dyn Backend>,
|
||||
}
|
||||
|
||||
impl<'a> Options<'a> {
|
||||
pub fn from_args(
|
||||
args: &[&str],
|
||||
out: &mut Vec<u8>,
|
||||
resolvers: &'a [(&str, PathResolver)],
|
||||
backend: Option<&'a mut dyn Backend>,
|
||||
) -> std::io::Result<Self> {
|
||||
if args.contains(&"--help") || args.contains(&"-h") {
|
||||
writeln!(out, "Usage: hbc [OPTIONS...] <FILE>")?;
|
||||
writeln!(out, include_str!("../command-help.txt"))?;
|
||||
return Err(std::io::ErrorKind::Other.into());
|
||||
}
|
||||
|
||||
Ok(Options {
|
||||
fmt: args.contains(&"--fmt"),
|
||||
fmt_stdout: args.contains(&"--fmt-stdout"),
|
||||
dump_asm: args.contains(&"--dump-asm"),
|
||||
extra_threads: args
|
||||
.iter()
|
||||
.position(|&a| a == "--threads")
|
||||
.map(|i| {
|
||||
args[i + 1].parse::<NonZeroUsize>().map_err(|e| {
|
||||
writeln!(out, "--threads expects non zero integer: {e}")
|
||||
.err()
|
||||
.unwrap_or(std::io::ErrorKind::Other.into())
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
.map_or(1, NonZeroUsize::get)
|
||||
- 1,
|
||||
resolver: args
|
||||
.iter()
|
||||
.position(|&a| a == "--path-resolver")
|
||||
.map(|i| {
|
||||
resolvers.iter().find(|&&(n, _)| args[i + 1] == n).map(|&(_, r)| r).ok_or_else(
|
||||
|| {
|
||||
writeln!(
|
||||
out,
|
||||
"--path-resolver can only be one of: {}",
|
||||
resolvers
|
||||
.iter()
|
||||
.map(|&(n, _)| n)
|
||||
.intersperse(", ")
|
||||
.collect::<String>()
|
||||
)
|
||||
.err()
|
||||
.unwrap_or(std::io::ErrorKind::Other.into())
|
||||
},
|
||||
)
|
||||
})
|
||||
.transpose()?,
|
||||
backend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_compiler(
|
||||
root_file: &str,
|
||||
options: Options,
|
||||
|
|
|
@ -257,7 +257,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
None => {
|
||||
let ident = match Ident::new(token.start, name.len() as _) {
|
||||
None => {
|
||||
self.report(token.start, "identifier can at most have 64 characters");
|
||||
self.report(
|
||||
token.start,
|
||||
"identifier can at most have 63 characters, \
|
||||
the code is too clean to efficiently represent in memory",
|
||||
);
|
||||
Ident::new(token.start, 63).unwrap()
|
||||
}
|
||||
Some(id) => id,
|
||||
|
|
115
lang/src/son.rs
115
lang/src/son.rs
|
@ -1202,14 +1202,6 @@ impl<'a> Codegen<'a> {
|
|||
let mut lhs = self.ptr_expr_ctx(left, ctx)?;
|
||||
self.implicit_unwrap(left.pos(), &mut lhs);
|
||||
|
||||
fn is_scalar_op(op: TokenKind, ty: ty::Id) -> bool {
|
||||
ty.is_pointer()
|
||||
|| ty.is_integer()
|
||||
|| ty == ty::Id::BOOL
|
||||
|| (ty == ty::Id::TYPE && matches!(op, TokenKind::Eq | TokenKind::Ne))
|
||||
|| (ty.is_float() && op.is_supported_float_op())
|
||||
}
|
||||
|
||||
match lhs.ty.expand() {
|
||||
ty::Kind::Struct(s) if op.is_homogenous() => {
|
||||
debug_assert!(lhs.ptr);
|
||||
|
@ -3095,7 +3087,7 @@ impl<'a> Codegen<'a> {
|
|||
let rhs = self.offset(rhs, off);
|
||||
let dst = self.offset(dst, off);
|
||||
match ty.expand() {
|
||||
_ if ty.is_pointer() || ty.is_integer() || ty == ty::Id::BOOL => {
|
||||
_ if is_scalar_op(op, ty) => {
|
||||
let lhs = self.load_mem(lhs, ty);
|
||||
let rhs = self.load_mem(rhs, ty);
|
||||
let res =
|
||||
|
@ -3279,6 +3271,7 @@ impl<'a> Codegen<'a> {
|
|||
sig: Sig { args, ret },
|
||||
is_inline,
|
||||
is_generic: true,
|
||||
is_import: false,
|
||||
comp_state: Default::default(),
|
||||
})
|
||||
.into()
|
||||
|
@ -4238,32 +4231,49 @@ impl<'a> Codegen<'a> {
|
|||
},
|
||||
|s, base| s.ins.unions.push(UnionData { base, ..Default::default() }),
|
||||
),
|
||||
Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => {
|
||||
let sig = 'b: {
|
||||
let arg_base = self.tys.tmp.args.len();
|
||||
for arg in args {
|
||||
let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id);
|
||||
if sym.flags & idfl::COMPTIME != 0 {
|
||||
self.tys.tmp.args.truncate(arg_base);
|
||||
break 'b None;
|
||||
}
|
||||
let ty = self.parse_ty(sc.anon(), &arg.ty);
|
||||
if ty == ty::Id::ANY_TYPE {
|
||||
break 'b None;
|
||||
}
|
||||
self.tys.tmp.args.push(ty);
|
||||
}
|
||||
|
||||
let Some(args) = self.tys.pack_args(arg_base) else {
|
||||
return self.error_low(sc.file, pos, "function has too many argumnets");
|
||||
};
|
||||
let ret = self.parse_ty(sc.anon(), ret);
|
||||
|
||||
Some(Sig { args, ret })
|
||||
Expr::Closure {
|
||||
pos,
|
||||
args,
|
||||
ret,
|
||||
body: &Expr::Directive { name: "import", args: import_args, .. },
|
||||
} if let Some(name) = sc.name => {
|
||||
let Some(sig) = self.try_parse_concrete_signature(pos, sc, args, ret) else {
|
||||
return self.error_low(
|
||||
sc.file,
|
||||
pos,
|
||||
"I am too tired to deal with your bulllshit",
|
||||
);
|
||||
};
|
||||
//let returns_type = matches!(ret, &Expr::Ident { id, .. } if );
|
||||
|
||||
match sig {
|
||||
let name = if let &[Expr::String { pos, literal }] = import_args {
|
||||
let Some(name) = Ident::new(pos + 1, literal.len() as u32 - 2) else {
|
||||
return self.error_low(
|
||||
sc.file,
|
||||
pos,
|
||||
"the simbol name is limmited to 63 characters, please don't import java",
|
||||
);
|
||||
};
|
||||
name
|
||||
} else {
|
||||
name
|
||||
};
|
||||
|
||||
let func = FuncData {
|
||||
file: sc.file,
|
||||
parent: sc.parent,
|
||||
name,
|
||||
pos,
|
||||
sig,
|
||||
expr: ExprRef::new(expr),
|
||||
is_inline: sc.is_ct,
|
||||
is_generic: false,
|
||||
is_import: true,
|
||||
comp_state: [CompState::Compiled.into(); 2],
|
||||
};
|
||||
self.tys.ins.funcs.push(func).into()
|
||||
}
|
||||
Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => {
|
||||
match self.try_parse_concrete_signature(pos, sc, args, ret) {
|
||||
Some(sig) => {
|
||||
let func = FuncData {
|
||||
file: sc.file,
|
||||
|
@ -4274,6 +4284,7 @@ impl<'a> Codegen<'a> {
|
|||
expr: ExprRef::new(expr),
|
||||
is_inline: sc.is_ct,
|
||||
is_generic: false,
|
||||
is_import: false,
|
||||
comp_state: Default::default(),
|
||||
};
|
||||
self.tys.ins.funcs.push(func).into()
|
||||
|
@ -4310,6 +4321,36 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_parse_concrete_signature(
|
||||
&mut self,
|
||||
pos: Pos,
|
||||
sc: TyScope,
|
||||
args: &[parser::Arg],
|
||||
ret: &Expr,
|
||||
) -> Option<Sig> {
|
||||
let arg_base = self.tys.tmp.args.len();
|
||||
for arg in args {
|
||||
let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id);
|
||||
if sym.flags & idfl::COMPTIME != 0 {
|
||||
self.tys.tmp.args.truncate(arg_base);
|
||||
return None;
|
||||
}
|
||||
let ty = self.parse_ty(sc.anon(), &arg.ty);
|
||||
if ty == ty::Id::ANY_TYPE {
|
||||
return None;
|
||||
}
|
||||
self.tys.tmp.args.push(ty);
|
||||
}
|
||||
|
||||
let Some(args) = self.tys.pack_args(arg_base) else {
|
||||
self.error_low(sc.file, pos, "function has too many argumnets");
|
||||
return None;
|
||||
};
|
||||
let ret = self.parse_ty(sc.anon(), ret);
|
||||
|
||||
Some(Sig { args, ret })
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn parse_base_ty<A, F, T: Into<ty::Id>>(
|
||||
&mut self,
|
||||
|
@ -4396,6 +4437,14 @@ impl TyScope {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_scalar_op(op: TokenKind, ty: ty::Id) -> bool {
|
||||
ty.is_pointer()
|
||||
|| ty.is_integer()
|
||||
|| ty == ty::Id::BOOL
|
||||
|| (ty == ty::Id::TYPE && matches!(op, TokenKind::Eq | TokenKind::Ne))
|
||||
|| (ty.is_float() && op.is_supported_float_op())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {
|
||||
|
|
|
@ -671,6 +671,7 @@ pub struct FuncData {
|
|||
pub sig: Sig,
|
||||
pub is_inline: bool,
|
||||
pub is_generic: bool,
|
||||
pub is_import: bool,
|
||||
pub comp_state: [PackedCompState; 2],
|
||||
}
|
||||
|
||||
|
@ -928,6 +929,7 @@ impl Types {
|
|||
| Kind::Slice(_)
|
||||
| Kind::Tuple(_)
|
||||
| Kind::Opt(_) => utils::is_pascal_case,
|
||||
Kind::Func(f) if self.ins.funcs[f].is_import => |_| Ok(()),
|
||||
Kind::Func(f)
|
||||
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
|
||||
self.ins.funcs[f].expr.get(&files[self.ins.funcs[f].file])
|
||||
|
@ -1127,7 +1129,7 @@ impl Types {
|
|||
}
|
||||
}
|
||||
Kind::Opt(opt) => self.align_of(self.ins.opts[opt].base),
|
||||
Kind::Builtin(_) | Kind::Enum(_) | Kind::Ptr(_) => self.size_of(ty),
|
||||
Kind::Builtin(_) | Kind::Enum(_) | Kind::Ptr(_) => self.size_of(ty).max(1),
|
||||
Kind::Func(_)
|
||||
| Kind::Template(_)
|
||||
| Kind::Global(_)
|
||||
|
|
Loading…
Reference in a new issue