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
|
a.out
|
||||||
out.o
|
out.o
|
||||||
|
/examples/raylib/main
|
||||||
|
|
||||||
# sqlite
|
# sqlite
|
||||||
db.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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
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]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.95"
|
version = "1.0.95"
|
||||||
|
@ -323,6 +372,46 @@ dependencies = [
|
||||||
"libloading",
|
"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]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.51"
|
version = "0.1.51"
|
||||||
|
@ -332,6 +421,12 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_format"
|
name = "const_format"
|
||||||
version = "0.2.33"
|
version = "0.2.33"
|
||||||
|
@ -572,7 +667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -769,6 +864,7 @@ version = "0.1.0"
|
||||||
name = "hbc"
|
name = "hbc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"cranelift-backend",
|
"cranelift-backend",
|
||||||
"hblang",
|
"hblang",
|
||||||
"log",
|
"log",
|
||||||
|
@ -818,7 +914,7 @@ version = "0.5.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -945,6 +1041,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -1086,7 +1188,7 @@ dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1288,7 +1390,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
"spin",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1333,7 +1435,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1477,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1492,6 +1594,12 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
|
@ -1559,7 +1667,7 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1690,6 +1798,12 @@ version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -1805,6 +1919,15 @@ dependencies = [
|
||||||
"windows-targets",
|
"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]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clap = { version = "4.5.23", features = ["derive", "env"] }
|
||||||
cranelift-backend = { version = "0.1.0", path = "../cranelift-backend" }
|
cranelift-backend = { version = "0.1.0", path = "../cranelift-backend" }
|
||||||
hblang = { workspace = true, features = ["std"] }
|
hblang = { workspace = true, features = ["std"] }
|
||||||
log = "0.4.22"
|
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() {
|
fn main() {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
|
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
|
||||||
let args = std::env::args().collect::<Vec<_>>();
|
let Args {
|
||||||
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
backend_flags,
|
||||||
|
target,
|
||||||
|
path_resolver,
|
||||||
|
fmt,
|
||||||
|
fmt_stdout,
|
||||||
|
dump_asm,
|
||||||
|
extra_threads,
|
||||||
|
file,
|
||||||
|
} = Args::parse();
|
||||||
|
|
||||||
let resolvers = &[("ableos", hblang::ABLEOS_PATH_RESOLVER)];
|
let resolvers = &[("ableos", hblang::ABLEOS_PATH_RESOLVER)];
|
||||||
|
|
||||||
let mut native = None;
|
let mut native = None;
|
||||||
let backend = match args.iter().position(|&v| v == "--target").map(|i| args[i + 1]) {
|
let backend = if target
|
||||||
Some(hblang::backend::hbvm::TARGET_TRIPLE) => None,
|
== target_lexicon::Triple::from_str(hblang::backend::hbvm::TARGET_TRIPLE).unwrap()
|
||||||
Some(target) => Some(
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
native.insert(
|
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)?,
|
.map_err(io::Error::other)?,
|
||||||
) as &mut dyn hblang::backend::Backend,
|
) 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 opts = hblang::Options {
|
||||||
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
|
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();
|
log::set_logger(&hblang::fs::Logger).unwrap();
|
||||||
|
@ -38,9 +85,10 @@ fn main() {
|
||||||
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
std::io::stderr().write_all(warnings.as_bytes()).unwrap();
|
||||||
std::io::stdout().write_all(&out).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(warnings.as_bytes()).unwrap();
|
||||||
std::io::stderr().write_all(&out).unwrap();
|
std::io::stderr().write_all(&out).unwrap();
|
||||||
|
std::eprint!("{e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,51 +3,59 @@
|
||||||
use {
|
use {
|
||||||
core::panic,
|
core::panic,
|
||||||
cranelift_codegen::{
|
cranelift_codegen::{
|
||||||
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
self as cc, CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||||
ir::{InstBuilder, MemFlags, TrapCode, UserExternalName},
|
ir::{self as cir, InstBuilder, MemFlags, TrapCode, UserExternalName, condcodes},
|
||||||
isa::{LookupError, TargetIsa},
|
isa::{LookupError, TargetIsa},
|
||||||
settings::Configurable,
|
settings::{Configurable, SetError},
|
||||||
},
|
},
|
||||||
cranelift_frontend::FunctionBuilder,
|
cranelift_frontend::{self as cf, FunctionBuilder},
|
||||||
cranelift_module::{Module, ModuleError},
|
cranelift_module::{self as cm, Module, ModuleError},
|
||||||
hblang::{
|
hblang::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
nodes::Kind,
|
nodes::{self as hbnodes},
|
||||||
utils::{Ent, EntVec},
|
ty as hbty,
|
||||||
|
utils::{self as hbutils, Ent, EntVec},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
fmt::{Display, Write},
|
||||||
|
ops::Range,
|
||||||
},
|
},
|
||||||
std::{fmt::Display, ops::Range},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
ctx: cranelift_codegen::Context,
|
ctx: cc::Context,
|
||||||
dt_ctx: cranelift_module::DataDescription,
|
dt_ctx: cm::DataDescription,
|
||||||
fb_ctx: cranelift_frontend::FunctionBuilderContext,
|
fb_ctx: cf::FunctionBuilderContext,
|
||||||
module: Option<cranelift_object::ObjectModule>,
|
module: Option<cranelift_object::ObjectModule>,
|
||||||
ctrl_plane: cranelift_codegen::control::ControlPlane,
|
ctrl_plane: cc::control::ControlPlane,
|
||||||
funcs: Functions,
|
funcs: Functions,
|
||||||
globals: EntVec<hblang::ty::Global, Global>,
|
globals: EntVec<hbty::Global, Global>,
|
||||||
asm: Assembler,
|
asm: Assembler,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
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 {
|
Ok(Self {
|
||||||
ctx: cranelift_codegen::Context::new(),
|
ctx: cc::Context::new(),
|
||||||
dt_ctx: cranelift_module::DataDescription::new(),
|
dt_ctx: cm::DataDescription::new(),
|
||||||
fb_ctx: cranelift_frontend::FunctionBuilderContext::default(),
|
fb_ctx: cf::FunctionBuilderContext::default(),
|
||||||
ctrl_plane: cranelift_codegen::control::ControlPlane::default(),
|
ctrl_plane: cc::control::ControlPlane::default(),
|
||||||
module: cranelift_object::ObjectModule::new(cranelift_object::ObjectBuilder::new(
|
module: cranelift_object::ObjectModule::new(cranelift_object::ObjectBuilder::new(
|
||||||
cranelift_codegen::isa::lookup(triple)?.finish(
|
cc::isa::lookup(triple)?.finish(cc::settings::Flags::new({
|
||||||
cranelift_codegen::settings::Flags::new({
|
let mut bl = cc::settings::builder();
|
||||||
let mut bl = cranelift_codegen::settings::builder();
|
for (k, v) in flags.split(',').filter_map(|s| s.split_once('=')) {
|
||||||
bl.set("enable_verifier", "true").unwrap();
|
bl.set(k, v).map_err(|err| BackendCreationError::InvalidFlag {
|
||||||
bl
|
key: k.to_owned(),
|
||||||
}),
|
value: v.to_owned(),
|
||||||
)?,
|
err,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
bl
|
||||||
|
}))?,
|
||||||
"main",
|
"main",
|
||||||
cranelift_module::default_libcall_names(),
|
cm::default_libcall_names(),
|
||||||
)?)
|
)?)
|
||||||
.into(),
|
.into(),
|
||||||
funcs: Default::default(),
|
funcs: Default::default(),
|
||||||
|
@ -60,9 +68,9 @@ impl Backend {
|
||||||
impl hblang::backend::Backend for Backend {
|
impl hblang::backend::Backend for Backend {
|
||||||
fn assemble_reachable(
|
fn assemble_reachable(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: hblang::ty::Func,
|
from: hbty::Func,
|
||||||
types: &hblang::ty::Types,
|
types: &hbty::Types,
|
||||||
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||||
to: &mut Vec<u8>,
|
to: &mut Vec<u8>,
|
||||||
) -> hblang::backend::AssemblySpec {
|
) -> hblang::backend::AssemblySpec {
|
||||||
debug_assert!(self.asm.frontier.is_empty());
|
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");
|
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 {
|
match name.namespace {
|
||||||
0 => hblang::ty::Kind::Func(hblang::ty::Func::new(name.index as _)),
|
0 => hbty::Kind::Func(hbty::Func::new(name.index as _)),
|
||||||
1 => hblang::ty::Kind::Global(hblang::ty::Global::new(name.index as _)),
|
1 => hbty::Kind::Global(hbty::Global::new(name.index as _)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
.compress()
|
.compress()
|
||||||
|
@ -85,12 +93,16 @@ impl hblang::backend::Backend for Backend {
|
||||||
self.asm.frontier.push(from.into());
|
self.asm.frontier.push(from.into());
|
||||||
while let Some(itm) = self.asm.frontier.pop() {
|
while let Some(itm) = self.asm.frontier.pop() {
|
||||||
match itm.expand() {
|
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 fuc = &mut self.funcs.headers[func];
|
||||||
|
let file = &files[fd.file];
|
||||||
if fuc.module_id.is_some() {
|
if fuc.module_id.is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
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| {
|
||||||
clif_name_to_ty(self.funcs.external_names[r as usize].clone())
|
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();
|
self.asm.name.clear();
|
||||||
if func == from {
|
if func == from {
|
||||||
self.asm.name.push_str("main");
|
self.asm.name.push_str("main");
|
||||||
|
} else if fd.is_import {
|
||||||
|
self.asm.name.push_str(file.ident_str(fd.name));
|
||||||
} else {
|
} else {
|
||||||
let file = &files[types.ins.funcs[func].file];
|
|
||||||
self.asm.name.push_str(hblang::strip_cwd(&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(fd.name));
|
||||||
}
|
}
|
||||||
let linkage = if func == from {
|
let linkage = if func == from {
|
||||||
cranelift_module::Linkage::Export
|
cm::Linkage::Export
|
||||||
|
} else if fd.is_import {
|
||||||
|
cm::Linkage::Import
|
||||||
} else {
|
} else {
|
||||||
cranelift_module::Linkage::Local
|
cm::Linkage::Local
|
||||||
};
|
};
|
||||||
build_signature(
|
build_signature(
|
||||||
module.isa().default_call_conv(),
|
module.isa().default_call_conv(),
|
||||||
types.ins.funcs[func].sig,
|
fd.sig,
|
||||||
types,
|
types,
|
||||||
&mut self.ctx.func.signature,
|
&mut self.ctx.func.signature,
|
||||||
&mut vec![],
|
&mut vec![],
|
||||||
|
@ -122,25 +137,31 @@ impl hblang::backend::Backend for Backend {
|
||||||
.declare_function(&self.asm.name, linkage, &self.ctx.func.signature)
|
.declare_function(&self.asm.name, linkage, &self.ctx.func.signature)
|
||||||
.unwrap(),
|
.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() {
|
if self.globals[glob].module_id.is_some() {
|
||||||
continue;
|
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 mutable = if types.ins.globals[glob].file == Default::default() {
|
||||||
self.asm.name.push_str(hblang::strip_cwd(&file.path));
|
writeln!(self.asm.name, "anon{}", glob.index()).unwrap();
|
||||||
self.asm.name.push('.');
|
false
|
||||||
self.asm.name.push_str(file.ident_str(types.ins.globals[glob].name));
|
} 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(
|
self.globals[glob].module_id = Some(
|
||||||
module
|
module
|
||||||
.declare_data(
|
.declare_data(&self.asm.name, cm::Linkage::Local, mutable, false)
|
||||||
&self.asm.name,
|
|
||||||
cranelift_module::Linkage::Local,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -150,14 +171,22 @@ impl hblang::backend::Backend for Backend {
|
||||||
|
|
||||||
for &func in &self.asm.funcs {
|
for &func in &self.asm.funcs {
|
||||||
let fuc = &self.funcs.headers[func];
|
let fuc = &self.funcs.headers[func];
|
||||||
|
assert!(!types.ins.funcs[func].is_import);
|
||||||
debug_assert!(!fuc.code.is_empty());
|
debug_assert!(!fuc.code.is_empty());
|
||||||
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| {
|
self.ctx.func.clear();
|
||||||
nm.index = self.funcs.headers[hblang::ty::Func::new(nm.index as _)]
|
names.iter().for_each(|nm| {
|
||||||
.module_id
|
let mut nm = nm.clone();
|
||||||
.unwrap()
|
if nm.namespace == 0 {
|
||||||
.as_u32();
|
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());
|
self.ctx.func.params.ensure_user_func_name(nm.clone());
|
||||||
});
|
});
|
||||||
module
|
module
|
||||||
|
@ -187,8 +216,8 @@ impl hblang::backend::Backend for Backend {
|
||||||
&'a self,
|
&'a self,
|
||||||
_sluce: &[u8],
|
_sluce: &[u8],
|
||||||
_eca_handler: &mut dyn FnMut(&mut &[u8]),
|
_eca_handler: &mut dyn FnMut(&mut &[u8]),
|
||||||
_types: &'a hblang::ty::Types,
|
_types: &'a hbty::Types,
|
||||||
_files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
_files: &'a hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||||
_output: &mut String,
|
_output: &mut String,
|
||||||
) -> Result<(), std::boxed::Box<dyn core::error::Error + Send + Sync + 'a>> {
|
) -> Result<(), std::boxed::Box<dyn core::error::Error + Send + Sync + 'a>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -196,10 +225,10 @@ impl hblang::backend::Backend for Backend {
|
||||||
|
|
||||||
fn emit_body(
|
fn emit_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: hblang::ty::Func,
|
id: hbty::Func,
|
||||||
nodes: &hblang::nodes::Nodes,
|
nodes: &hbnodes::Nodes,
|
||||||
tys: &hblang::ty::Types,
|
tys: &hbty::Types,
|
||||||
files: &hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||||
) {
|
) {
|
||||||
self.ctx.clear();
|
self.ctx.clear();
|
||||||
let isa = self.module.as_ref().unwrap().isa();
|
let isa = self.module.as_ref().unwrap().isa();
|
||||||
|
@ -226,12 +255,9 @@ impl hblang::backend::Backend for Backend {
|
||||||
.build(tys.ins.funcs[id].sig);
|
.build(tys.ins.funcs[id].sig);
|
||||||
|
|
||||||
self.ctx.func.name =
|
self.ctx.func.name =
|
||||||
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
cir::UserFuncName::User(cir::UserExternalName { namespace: 0, index: id.index() as _ });
|
||||||
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();
|
self.ctx.compile(isa, &mut self.ctrl_plane).unwrap();
|
||||||
let code = self.ctx.compiled_code().unwrap();
|
let code = self.ctx.compiled_code().unwrap();
|
||||||
|
@ -240,15 +266,15 @@ impl hblang::backend::Backend for Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_signature(
|
fn build_signature(
|
||||||
call_conv: cranelift_codegen::isa::CallConv,
|
call_conv: cc::isa::CallConv,
|
||||||
sig: hblang::ty::Sig,
|
sig: hbty::Sig,
|
||||||
types: &hblang::ty::Types,
|
types: &hbty::Types,
|
||||||
signature: &mut cranelift_codegen::ir::Signature,
|
signature: &mut cir::Signature,
|
||||||
arg_meta: &mut Vec<AbiMeta>,
|
arg_meta: &mut Vec<AbiMeta>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
signature.clear(call_conv);
|
signature.clear(call_conv);
|
||||||
match call_conv {
|
match call_conv {
|
||||||
cranelift_codegen::isa::CallConv::SystemV => {
|
cc::isa::CallConv::SystemV => {
|
||||||
x86_64::build_systemv_signature(sig, types, signature, arg_meta)
|
x86_64::build_systemv_signature(sig, types, signature, arg_meta)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
@ -262,18 +288,18 @@ struct AbiMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FuncBuilder<'a, 'b> {
|
struct FuncBuilder<'a, 'b> {
|
||||||
bl: cranelift_frontend::FunctionBuilder<'b>,
|
bl: cf::FunctionBuilder<'b>,
|
||||||
isa: &'a dyn TargetIsa,
|
isa: &'a dyn TargetIsa,
|
||||||
nodes: &'a hblang::nodes::Nodes,
|
nodes: &'a hbnodes::Nodes,
|
||||||
tys: &'a hblang::ty::Types,
|
tys: &'a hbty::Types,
|
||||||
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &'a hbutils::EntSlice<hbty::Module, hblang::parser::Ast>,
|
||||||
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
values: &'b mut [Option<Result<cir::Value, cir::Block>>],
|
||||||
arg_lens: &'a [AbiMeta],
|
arg_lens: &'a [AbiMeta],
|
||||||
stack_ret: bool,
|
stack_ret: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncBuilder<'_, '_> {
|
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();
|
let entry = self.bl.create_block();
|
||||||
self.bl.append_block_params_for_function_params(entry);
|
self.bl.append_block_params_for_function_params(entry);
|
||||||
self.bl.switch_to_block(entry);
|
self.bl.switch_to_block(entry);
|
||||||
|
@ -281,21 +307,21 @@ impl FuncBuilder<'_, '_> {
|
||||||
|
|
||||||
if self.stack_ret {
|
if self.stack_ret {
|
||||||
let ret_ptr = *arg_vals.take_first().unwrap();
|
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 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 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) {
|
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 abi_meta = parama_len.next().unwrap();
|
||||||
let &arg = args.next().unwrap();
|
let &arg = args.next().unwrap();
|
||||||
if !abi_meta.trough_mem && ty.is_aggregate(tys) {
|
if !abi_meta.trough_mem && ty.is_aggregate(tys) {
|
||||||
let slot = self.bl.create_sized_stack_slot(cranelift_codegen::ir::StackSlotData {
|
let slot = self.bl.create_sized_stack_slot(cir::StackSlotData {
|
||||||
kind: cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
|
kind: cir::StackSlotKind::ExplicitSlot,
|
||||||
size: self.tys.size_of(ty),
|
size: self.tys.size_of(ty),
|
||||||
align_shift: self.tys.align_of(ty).ilog2() as _,
|
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();
|
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()
|
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()
|
self.values[nid as usize].unwrap().unwrap_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_block(&mut self, nid: hblang::nodes::Nid) {
|
fn close_block(&mut self, nid: hbnodes::Nid) {
|
||||||
if matches!(self.nodes[nid].kind, Kind::Loop) {
|
if matches!(self.nodes[nid].kind, hbnodes::Kind::Loop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.bl.seal_block(self.block_of(nid));
|
self.bl.seal_block(self.block_of(nid));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_node(&mut self, nid: hblang::nodes::Nid, block: hblang::nodes::Nid) {
|
fn emit_node(&mut self, nid: hbnodes::Nid, block: hbnodes::Nid) {
|
||||||
use hblang::nodes::*;
|
use hbnodes::*;
|
||||||
|
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) {
|
if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) {
|
||||||
|
@ -359,10 +385,9 @@ impl FuncBuilder<'_, '_> {
|
||||||
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.bl.append_block_param(
|
self.values[o as usize] = Some(Ok(self
|
||||||
next,
|
.bl
|
||||||
ty_to_clif_ty(self.nodes[o].ty, self.tys),
|
.append_block_param(next, self.nodes[o].ty.to_clif(self.tys))));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.bl.ins().jump(next, &args);
|
self.bl.ins().jump(next, &args);
|
||||||
|
@ -405,7 +430,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
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
|
.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));
|
self.values[nid as usize] = Some(Err(next));
|
||||||
|
@ -434,7 +459,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
Kind::Return { .. } => {
|
Kind::Return { .. } => {
|
||||||
let mut ir_args = vec![];
|
let mut ir_args = vec![];
|
||||||
if node.inputs[1] == hblang::nodes::VOID {
|
if node.inputs[1] == hbnodes::VOID {
|
||||||
} else {
|
} else {
|
||||||
let abi_meta = self.arg_lens[0];
|
let abi_meta = self.arg_lens[0];
|
||||||
let arg = node.inputs[1];
|
let arg = node.inputs[1];
|
||||||
|
@ -455,14 +480,25 @@ impl FuncBuilder<'_, '_> {
|
||||||
));
|
));
|
||||||
offset += align as i32;
|
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 {
|
} else {
|
||||||
ir_args.push(self.value_of(arg));
|
ir_args.push(self.value_of(arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = self.value_of(node.inputs[1]);
|
self.bl.ins().return_(&ir_args);
|
||||||
|
|
||||||
self.bl.ins().return_(&[ret]);
|
|
||||||
self.close_block(block);
|
self.close_block(block);
|
||||||
self.emit_node(node.outputs[0], block);
|
self.emit_node(node.outputs[0], block);
|
||||||
Err(self.block_of(block))
|
Err(self.block_of(block))
|
||||||
|
@ -484,8 +520,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
let mut arg_lens = vec![];
|
let mut arg_lens = vec![];
|
||||||
let mut signature =
|
let mut signature = cir::Signature::new(self.isa.default_call_conv());
|
||||||
cranelift_codegen::ir::Signature::new(self.isa.default_call_conv());
|
|
||||||
let stack_ret = build_signature(
|
let stack_ret = build_signature(
|
||||||
self.isa.default_call_conv(),
|
self.isa.default_call_conv(),
|
||||||
self.tys.ins.funcs[func].sig,
|
self.tys.ins.funcs[func].sig,
|
||||||
|
@ -494,29 +529,28 @@ impl FuncBuilder<'_, '_> {
|
||||||
&mut arg_lens,
|
&mut arg_lens,
|
||||||
);
|
);
|
||||||
|
|
||||||
let func_ref = 'b: {
|
let func_ref =
|
||||||
let user_name_ref = self.bl.func.declare_imported_user_function(
|
'b: {
|
||||||
cranelift_codegen::ir::UserExternalName {
|
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||||
namespace: 0,
|
cir::UserExternalName { namespace: 0, index: func.index() as _ },
|
||||||
index: func.index() as _,
|
);
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(id) = self.bl.func.dfg.ext_funcs.keys().find(|&k| {
|
if let Some(id) = self.bl.func.dfg.ext_funcs.keys().find(|&k| {
|
||||||
self.bl.func.dfg.ext_funcs[k].name
|
self.bl.func.dfg.ext_funcs[k].name
|
||||||
== cranelift_codegen::ir::ExternalName::user(user_name_ref)
|
== cir::ExternalName::user(user_name_ref)
|
||||||
}) {
|
}) {
|
||||||
break 'b id;
|
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 {
|
self.bl.func.import_function(cir::ExtFuncData {
|
||||||
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
name: cir::ExternalName::user(user_name_ref),
|
||||||
signature,
|
signature,
|
||||||
colocated: true,
|
// somehow, this works
|
||||||
})
|
colocated: true, // !self.tys.ins.funcs[func].is_import,
|
||||||
};
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let mut ir_args = vec![];
|
let mut ir_args = vec![];
|
||||||
|
|
||||||
|
@ -525,13 +559,15 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut params = signature.params.as_slice();
|
let mut params = signature.params.as_slice();
|
||||||
let mut parama_len =
|
let mut parama_len = arg_lens[1..].iter();
|
||||||
arg_lens[(self.tys.size_of(node.ty) != 0) as usize..].iter();
|
|
||||||
let mut typs = args.args();
|
let mut typs = args.args();
|
||||||
let mut args = node.inputs[1..].iter();
|
let mut args = node.inputs[1..].iter();
|
||||||
while let Some(aty) = typs.next(self.tys) {
|
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();
|
let abi_meta = parama_len.next().unwrap();
|
||||||
|
if abi_meta.arg_count == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let &arg = args.next().unwrap();
|
let &arg = args.next().unwrap();
|
||||||
if !abi_meta.trough_mem && ty.is_aggregate(self.tys) {
|
if !abi_meta.trough_mem && ty.is_aggregate(self.tys) {
|
||||||
let loc = params.take(..abi_meta.arg_count).unwrap();
|
let loc = params.take(..abi_meta.arg_count).unwrap();
|
||||||
|
@ -590,101 +626,74 @@ impl FuncBuilder<'_, '_> {
|
||||||
return;
|
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_float() => {
|
||||||
cranelift_codegen::ir::Type::int(self.tys.size_of(self.nodes[nid].ty) as u16 * 8)
|
Ok(match self.tys.size_of(self.nodes[nid].ty) {
|
||||||
.unwrap(),
|
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,
|
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 } => {
|
Kind::BinOp { op } => {
|
||||||
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
let [lhs, rhs] = [self.value_of(lhs), self.value_of(rhs)];
|
let [lh, rh] = [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)
|
|
||||||
);
|
|
||||||
|
|
||||||
use cranelift_codegen::ir::condcodes::IntCC as ICC;
|
let is_int_op = node.ty.is_integer()
|
||||||
fn icc_of(op: TokenKind, signed: bool) -> ICC {
|
|| (node.ty == hbty::Id::BOOL
|
||||||
match op {
|
&& (self.nodes[lhs].ty.is_integer()
|
||||||
TokenKind::Lt if signed => ICC::SignedLessThan,
|
|| self.nodes[lhs].ty == hbty::Id::BOOL));
|
||||||
TokenKind::Gt if signed => ICC::SignedGreaterThan,
|
let is_float_op = node.ty.is_float()
|
||||||
TokenKind::Le if signed => ICC::SignedLessThanOrEqual,
|
|| (node.ty == hbty::Id::BOOL && self.nodes[lhs].ty.is_float());
|
||||||
TokenKind::Ge if signed => ICC::SignedGreaterThanOrEqual,
|
|
||||||
|
|
||||||
TokenKind::Lt => ICC::UnsignedLessThan,
|
Ok(if is_int_op {
|
||||||
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();
|
let signed = node.ty.is_signed();
|
||||||
match op {
|
match op {
|
||||||
TokenKind::Add => self.bl.ins().iadd(lhs, rhs),
|
TokenKind::Add => self.bl.ins().iadd(lh, rh),
|
||||||
TokenKind::Sub => self.bl.ins().isub(lhs, rhs),
|
TokenKind::Sub => self.bl.ins().isub(lh, rh),
|
||||||
TokenKind::Mul => self.bl.ins().imul(lhs, rhs),
|
TokenKind::Mul => self.bl.ins().imul(lh, rh),
|
||||||
TokenKind::Shl => self.bl.ins().ishl(lhs, rhs),
|
TokenKind::Shl => self.bl.ins().ishl(lh, rh),
|
||||||
TokenKind::Xor => self.bl.ins().bxor(lhs, rhs),
|
TokenKind::Xor => self.bl.ins().bxor(lh, rh),
|
||||||
TokenKind::Band => self.bl.ins().band(lhs, rhs),
|
TokenKind::Band => self.bl.ins().band(lh, rh),
|
||||||
TokenKind::Bor => self.bl.ins().bor(lhs, rhs),
|
TokenKind::Bor => self.bl.ins().bor(lh, rh),
|
||||||
|
|
||||||
TokenKind::Div if signed => self.bl.ins().sdiv(lhs, rhs),
|
TokenKind::Div if signed => self.bl.ins().sdiv(lh, rh),
|
||||||
TokenKind::Mod if signed => self.bl.ins().srem(lhs, rhs),
|
TokenKind::Mod if signed => self.bl.ins().srem(lh, rh),
|
||||||
TokenKind::Shr if signed => self.bl.ins().sshr(lhs, rhs),
|
TokenKind::Shr if signed => self.bl.ins().sshr(lh, rh),
|
||||||
|
|
||||||
TokenKind::Div => self.bl.ins().udiv(lhs, rhs),
|
TokenKind::Div => self.bl.ins().udiv(lh, rh),
|
||||||
TokenKind::Mod => self.bl.ins().urem(lhs, rhs),
|
TokenKind::Mod => self.bl.ins().urem(lh, rh),
|
||||||
TokenKind::Shr => self.bl.ins().ushr(lhs, rhs),
|
TokenKind::Shr => self.bl.ins().ushr(lh, rh),
|
||||||
|
|
||||||
TokenKind::Lt
|
TokenKind::Lt
|
||||||
| TokenKind::Gt
|
| TokenKind::Gt
|
||||||
| TokenKind::Le
|
| TokenKind::Le
|
||||||
| TokenKind::Ge
|
| TokenKind::Ge
|
||||||
| TokenKind::Eq
|
| 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}"),
|
op => todo!("{op}"),
|
||||||
}
|
}
|
||||||
} else if node.ty.is_float() {
|
} else if is_float_op {
|
||||||
match op {
|
match op {
|
||||||
TokenKind::Add => self.bl.ins().fadd(lhs, rhs),
|
TokenKind::Add => self.bl.ins().fadd(lh, rh),
|
||||||
TokenKind::Sub => self.bl.ins().fsub(lhs, rhs),
|
TokenKind::Sub => self.bl.ins().fsub(lh, rh),
|
||||||
TokenKind::Mul => self.bl.ins().fmul(lhs, rhs),
|
TokenKind::Mul => self.bl.ins().fmul(lh, rh),
|
||||||
TokenKind::Div => self.bl.ins().fdiv(lhs, rhs),
|
TokenKind::Div => self.bl.ins().fdiv(lh, rh),
|
||||||
|
|
||||||
TokenKind::Lt
|
TokenKind::Lt
|
||||||
| TokenKind::Gt
|
| TokenKind::Gt
|
||||||
| TokenKind::Le
|
| TokenKind::Le
|
||||||
| TokenKind::Ge
|
| TokenKind::Ge
|
||||||
| TokenKind::Eq
|
| 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}"),
|
op => todo!("{op}"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!("{}", hbty::Display::new(self.tys, self.files, node.ty))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Kind::RetVal => Ok(self.value_of(node.inputs[0])),
|
Kind::RetVal => Ok(self.value_of(node.inputs[0])),
|
||||||
|
@ -696,7 +705,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
.inner_of(self.nodes[node.inputs[1]].ty)
|
.inner_of(self.nodes[node.inputs[1]].ty)
|
||||||
.unwrap_or(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 {
|
Ok(match op {
|
||||||
TokenKind::Sub => self.bl.ins().ineg(oper),
|
TokenKind::Sub => self.bl.ins().ineg(oper),
|
||||||
TokenKind::Not => self.bl.ins().bnot(oper),
|
TokenKind::Not => self.bl.ins().bnot(oper),
|
||||||
|
@ -715,55 +724,52 @@ impl FuncBuilder<'_, '_> {
|
||||||
self.bl.ins().sextend(dty, oper)
|
self.bl.ins().sextend(dty, oper)
|
||||||
}
|
}
|
||||||
TokenKind::Number
|
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()) =>
|
&& (dst.is_integer() || dst.is_pointer()) =>
|
||||||
{
|
{
|
||||||
self.bl.ins().uextend(dty, oper)
|
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)
|
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)
|
self.bl.ins().fdemote(dty, oper)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Kind::Stck => {
|
Kind::Stck => {
|
||||||
let slot = self.bl.create_sized_stack_slot(cranelift_codegen::ir::StackSlotData {
|
let slot = self.bl.create_sized_stack_slot(cir::StackSlotData {
|
||||||
kind: cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
|
kind: cir::StackSlotKind::ExplicitSlot,
|
||||||
size: self.tys.size_of(node.ty),
|
size: self.tys.size_of(node.ty),
|
||||||
align_shift: self.tys.align_of(node.ty).ilog2() as _,
|
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 } => {
|
Kind::Global { global } => {
|
||||||
let glob_ref = {
|
let glob_ref = {
|
||||||
// already deduplicated by the SoN
|
// already deduplicated by the SoN
|
||||||
let colocated = true;
|
let colocated = true;
|
||||||
let user_name_ref = self.bl.func.declare_imported_user_function(
|
let user_name_ref =
|
||||||
cranelift_codegen::ir::UserExternalName {
|
self.bl.func.declare_imported_user_function(cir::UserExternalName {
|
||||||
namespace: 1,
|
namespace: 1,
|
||||||
index: global.index() as u32,
|
index: global.index() as u32,
|
||||||
},
|
});
|
||||||
);
|
self.bl.func.create_global_value(cir::GlobalValueData::Symbol {
|
||||||
self.bl.func.create_global_value(
|
name: cir::ExternalName::user(user_name_ref),
|
||||||
cranelift_codegen::ir::GlobalValueData::Symbol {
|
offset: cir::immediates::Imm64::new(0),
|
||||||
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
colocated,
|
||||||
offset: cranelift_codegen::ir::immediates::Imm64::new(0),
|
tls: false,
|
||||||
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 if node.ty.is_aggregate(self.tys) => return,
|
||||||
Kind::Load => {
|
Kind::Load => {
|
||||||
let ptr = self.value_of(node.inputs[1]);
|
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) => {
|
Kind::Stre if node.ty.is_aggregate(self.tys) => {
|
||||||
let src = self.value_of(self.nodes[node.inputs[1]].inputs[1]);
|
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 {
|
trait ToCondcodes {
|
||||||
if ty.is_integer() {
|
fn to_int_cc(self, signed: bool) -> condcodes::IntCC;
|
||||||
cranelift_codegen::ir::Type::int(tys.size_of(ty) as u16 * 8).unwrap()
|
fn to_float_cc(self) -> condcodes::FloatCC;
|
||||||
} else {
|
}
|
||||||
unimplemented!()
|
|
||||||
|
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)]
|
#[derive(Default)]
|
||||||
struct Global {
|
struct Global {
|
||||||
module_id: Option<cranelift_module::DataId>,
|
module_id: Option<cm::DataId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct FuncHeaders {
|
struct FuncHeaders {
|
||||||
module_id: Option<cranelift_module::FuncId>,
|
module_id: Option<cm::FuncId>,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
code: Range<u32>,
|
code: Range<u32>,
|
||||||
relocs: Range<u32>,
|
relocs: Range<u32>,
|
||||||
|
@ -816,19 +872,14 @@ struct FuncHeaders {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Functions {
|
struct Functions {
|
||||||
headers: EntVec<hblang::ty::Func, FuncHeaders>,
|
headers: EntVec<hbty::Func, FuncHeaders>,
|
||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
relocs: Vec<FinalizedMachReloc>,
|
relocs: Vec<FinalizedMachReloc>,
|
||||||
external_names: Vec<UserExternalName>,
|
external_names: Vec<UserExternalName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Functions {
|
impl Functions {
|
||||||
fn push(
|
fn push(&mut self, id: hbty::Func, func: &cir::Function, code: &MachBufferFinalized<Final>) {
|
||||||
&mut self,
|
|
||||||
id: hblang::ty::Func,
|
|
||||||
func: &cranelift_codegen::ir::Function,
|
|
||||||
code: &MachBufferFinalized<Final>,
|
|
||||||
) {
|
|
||||||
self.headers.shadow(id.index() + 1);
|
self.headers.shadow(id.index() + 1);
|
||||||
self.headers[id] = FuncHeaders {
|
self.headers[id] = FuncHeaders {
|
||||||
module_id: None,
|
module_id: None,
|
||||||
|
@ -847,9 +898,9 @@ impl Functions {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Assembler {
|
struct Assembler {
|
||||||
name: String,
|
name: String,
|
||||||
frontier: Vec<hblang::ty::Id>,
|
frontier: Vec<hbty::Id>,
|
||||||
globals: Vec<hblang::ty::Global>,
|
globals: Vec<hbty::Global>,
|
||||||
funcs: Vec<hblang::ty::Func>,
|
funcs: Vec<hbty::Func>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -857,6 +908,7 @@ pub enum BackendCreationError {
|
||||||
UnsupportedTriplet(LookupError),
|
UnsupportedTriplet(LookupError),
|
||||||
InvalidFlags(CodegenError),
|
InvalidFlags(CodegenError),
|
||||||
UnsupportedModuleConfig(ModuleError),
|
UnsupportedModuleConfig(ModuleError),
|
||||||
|
InvalidFlag { key: String, value: String, err: SetError },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BackendCreationError {
|
impl Display for BackendCreationError {
|
||||||
|
@ -871,6 +923,13 @@ impl Display for BackendCreationError {
|
||||||
BackendCreationError::UnsupportedModuleConfig(err) => {
|
BackendCreationError::UnsupportedModuleConfig(err) => {
|
||||||
write!(f, "Unsupported module configuration: {}", 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
|
// The classification code for the x86_64 ABI is taken from the clay language
|
||||||
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
||||||
|
|
||||||
use crate::AbiMeta;
|
use {crate::AbiMeta, hblang::ty};
|
||||||
|
|
||||||
pub fn build_systemv_signature(
|
pub fn build_systemv_signature(
|
||||||
sig: hblang::ty::Sig,
|
sig: hblang::ty::Sig,
|
||||||
|
@ -12,11 +12,14 @@ pub fn build_systemv_signature(
|
||||||
let mut alloca = Alloca::new();
|
let mut alloca = Alloca::new();
|
||||||
|
|
||||||
alloca.next(false, sig.ret, types, &mut signature.returns);
|
alloca.next(false, sig.ret, types, &mut signature.returns);
|
||||||
let stack_ret = signature.params.len() == 1
|
let stack_ret = signature.returns.len() == 1
|
||||||
&& signature.params[0].purpose == cranelift_codegen::ir::ArgumentPurpose::StructReturn;
|
&& signature.returns[0].purpose == cranelift_codegen::ir::ArgumentPurpose::StructReturn;
|
||||||
|
|
||||||
if stack_ret {
|
if stack_ret {
|
||||||
signature.params.append(&mut signature.returns);
|
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();
|
let mut args = sig.args.args();
|
||||||
|
@ -66,7 +69,7 @@ fn classify_arg(
|
||||||
|
|
||||||
let mut c = match layout.expand() {
|
let mut c = match layout.expand() {
|
||||||
_ if size == 0 => return Ok(()),
|
_ 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,
|
_ if layout.is_float() => Class::Sse,
|
||||||
|
|
||||||
hblang::ty::Kind::Struct(s) => {
|
hblang::ty::Kind::Struct(s) => {
|
||||||
|
@ -115,7 +118,7 @@ fn classify_arg(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unimplemented!(),
|
ty => unimplemented!("{ty:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
|
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
|
||||||
|
@ -241,6 +244,10 @@ impl Alloca {
|
||||||
cx: &hblang::ty::Types,
|
cx: &hblang::ty::Types,
|
||||||
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if cx.size_of(arg) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let mut cls_or_mem = classify_arg(cx, arg);
|
let mut cls_or_mem = classify_arg(cx, arg);
|
||||||
|
|
||||||
if is_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>,
|
offsets: Vec<Offset>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TARGET_TRIPLE: &str = "hbvm-virt-ableos";
|
pub const TARGET_TRIPLE: &str = "unknown-virt-unknown";
|
||||||
|
|
||||||
impl HbvmBackend {
|
impl HbvmBackend {
|
||||||
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
|
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use {
|
||||||
ty, FnvBuildHasher,
|
ty, FnvBuildHasher,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{fmt::Write, num::NonZeroUsize, ops::Deref},
|
core::{fmt::Write, ops::Deref},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
std::{
|
std::{
|
||||||
borrow::ToOwned,
|
borrow::ToOwned,
|
||||||
|
@ -74,62 +74,6 @@ pub struct Options<'a> {
|
||||||
pub backend: Option<&'a mut dyn Backend>,
|
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(
|
pub fn run_compiler(
|
||||||
root_file: &str,
|
root_file: &str,
|
||||||
options: Options,
|
options: Options,
|
||||||
|
|
|
@ -257,7 +257,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
None => {
|
None => {
|
||||||
let ident = match Ident::new(token.start, name.len() as _) {
|
let ident = match Ident::new(token.start, name.len() as _) {
|
||||||
None => {
|
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()
|
Ident::new(token.start, 63).unwrap()
|
||||||
}
|
}
|
||||||
Some(id) => id,
|
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)?;
|
let mut lhs = self.ptr_expr_ctx(left, ctx)?;
|
||||||
self.implicit_unwrap(left.pos(), &mut lhs);
|
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() {
|
match lhs.ty.expand() {
|
||||||
ty::Kind::Struct(s) if op.is_homogenous() => {
|
ty::Kind::Struct(s) if op.is_homogenous() => {
|
||||||
debug_assert!(lhs.ptr);
|
debug_assert!(lhs.ptr);
|
||||||
|
@ -3095,7 +3087,7 @@ impl<'a> Codegen<'a> {
|
||||||
let rhs = self.offset(rhs, off);
|
let rhs = self.offset(rhs, off);
|
||||||
let dst = self.offset(dst, off);
|
let dst = self.offset(dst, off);
|
||||||
match ty.expand() {
|
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 lhs = self.load_mem(lhs, ty);
|
||||||
let rhs = self.load_mem(rhs, ty);
|
let rhs = self.load_mem(rhs, ty);
|
||||||
let res =
|
let res =
|
||||||
|
@ -3279,6 +3271,7 @@ impl<'a> Codegen<'a> {
|
||||||
sig: Sig { args, ret },
|
sig: Sig { args, ret },
|
||||||
is_inline,
|
is_inline,
|
||||||
is_generic: true,
|
is_generic: true,
|
||||||
|
is_import: false,
|
||||||
comp_state: Default::default(),
|
comp_state: Default::default(),
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
|
@ -4238,32 +4231,49 @@ impl<'a> Codegen<'a> {
|
||||||
},
|
},
|
||||||
|s, base| s.ins.unions.push(UnionData { base, ..Default::default() }),
|
|s, base| s.ins.unions.push(UnionData { base, ..Default::default() }),
|
||||||
),
|
),
|
||||||
Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => {
|
Expr::Closure {
|
||||||
let sig = 'b: {
|
pos,
|
||||||
let arg_base = self.tys.tmp.args.len();
|
args,
|
||||||
for arg in args {
|
ret,
|
||||||
let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id);
|
body: &Expr::Directive { name: "import", args: import_args, .. },
|
||||||
if sym.flags & idfl::COMPTIME != 0 {
|
} if let Some(name) = sc.name => {
|
||||||
self.tys.tmp.args.truncate(arg_base);
|
let Some(sig) = self.try_parse_concrete_signature(pos, sc, args, ret) else {
|
||||||
break 'b None;
|
return self.error_low(
|
||||||
}
|
sc.file,
|
||||||
let ty = self.parse_ty(sc.anon(), &arg.ty);
|
pos,
|
||||||
if ty == ty::Id::ANY_TYPE {
|
"I am too tired to deal with your bulllshit",
|
||||||
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 })
|
|
||||||
};
|
};
|
||||||
//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) => {
|
Some(sig) => {
|
||||||
let func = FuncData {
|
let func = FuncData {
|
||||||
file: sc.file,
|
file: sc.file,
|
||||||
|
@ -4274,6 +4284,7 @@ impl<'a> Codegen<'a> {
|
||||||
expr: ExprRef::new(expr),
|
expr: ExprRef::new(expr),
|
||||||
is_inline: sc.is_ct,
|
is_inline: sc.is_ct,
|
||||||
is_generic: false,
|
is_generic: false,
|
||||||
|
is_import: false,
|
||||||
comp_state: Default::default(),
|
comp_state: Default::default(),
|
||||||
};
|
};
|
||||||
self.tys.ins.funcs.push(func).into()
|
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)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
fn parse_base_ty<A, F, T: Into<ty::Id>>(
|
fn parse_base_ty<A, F, T: Into<ty::Id>>(
|
||||||
&mut self,
|
&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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
|
|
|
@ -671,6 +671,7 @@ pub struct FuncData {
|
||||||
pub sig: Sig,
|
pub sig: Sig,
|
||||||
pub is_inline: bool,
|
pub is_inline: bool,
|
||||||
pub is_generic: bool,
|
pub is_generic: bool,
|
||||||
|
pub is_import: bool,
|
||||||
pub comp_state: [PackedCompState; 2],
|
pub comp_state: [PackedCompState; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,6 +929,7 @@ impl Types {
|
||||||
| Kind::Slice(_)
|
| Kind::Slice(_)
|
||||||
| Kind::Tuple(_)
|
| Kind::Tuple(_)
|
||||||
| Kind::Opt(_) => utils::is_pascal_case,
|
| Kind::Opt(_) => utils::is_pascal_case,
|
||||||
|
Kind::Func(f) if self.ins.funcs[f].is_import => |_| Ok(()),
|
||||||
Kind::Func(f)
|
Kind::Func(f)
|
||||||
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
|
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
|
||||||
self.ins.funcs[f].expr.get(&files[self.ins.funcs[f].file])
|
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::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::Func(_)
|
||||||
| Kind::Template(_)
|
| Kind::Template(_)
|
||||||
| Kind::Global(_)
|
| Kind::Global(_)
|
||||||
|
|
Loading…
Reference in a new issue