diff --git a/cranelift-backend/src/lib.rs b/cranelift-backend/src/lib.rs index 70e82eae..418175be 100644 --- a/cranelift-backend/src/lib.rs +++ b/cranelift-backend/src/lib.rs @@ -67,6 +67,10 @@ impl Backend { } impl hblang::backend::Backend for Backend { + fn triple(&self) -> String { + self.module.as_ref().unwrap().isa().triple().to_string() + } + fn assemble_reachable( &mut self, from: hbty::Func, diff --git a/lang/README.md b/lang/README.md index 09122ac5..e76da693 100644 --- a/lang/README.md +++ b/lang/README.md @@ -454,6 +454,8 @@ main := fn(): uint { embedded_array := @as([15]u8, @embed("text.txt")) two_fields := @lenof(foo.Type) the_struct_kind := @kindof(foo.Type) + if @target("compile-time") die + if !@target("*-virt-unknown") die return @inline(foo.foo) } @@ -486,6 +488,7 @@ arbitrary text - `@Any()`: generic parameter based on inference, TBD: this will ake arguments in the future that restrict what is accepted - `@error(...)`: emit compiler error, if reachable, and use arguments to construct a message, can display strings and types - `@ChildOf()`: returns the child type of the ``, works for pointers and optionals (`@ChildOf(?u8) == u8`) +- `@target("")`: if the supplied pattern matches the target triple code is compiled to this returns `true`, compile time target is `"compile-time"` #### c_strings ```hb diff --git a/lang/src/backend/hbvm.rs b/lang/src/backend/hbvm.rs index 805d0af9..1be31f01 100644 --- a/lang/src/backend/hbvm.rs +++ b/lang/src/backend/hbvm.rs @@ -11,6 +11,7 @@ use { core::{assert_matches::debug_assert_matches, error, mem, ops::Range}, hbbytecode::{self as instrs, *}, reg::Reg, + std::borrow::ToOwned, }; mod regalloc; @@ -115,6 +116,10 @@ impl HbvmBackend { } impl Backend for HbvmBackend { + fn triple(&self) -> String { + TARGET_TRIPLE.to_owned() + } + fn assemble_bin( &mut self, entry: ty::Func, diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 3d7553ee..ecdb1a2c 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -1,5 +1,6 @@ #![feature( iter_array_chunks, + str_split_remainder, assert_matches, let_chains, if_let_guard, @@ -75,9 +76,51 @@ pub mod backend { utils::EntSlice, }, alloc::{string::String, vec::Vec}, - core::error, + core::{error, mem::take}, }; + pub fn match_triple(pattern: &str, triple: &str) -> Result { + if pattern == "*" { + return Err("you can replace this with 'true'"); + } + + if pattern.ends_with("-*") { + return Err("trailing '*' is redundant"); + } + + let mut matcher = pattern.split('-'); + let mut matchee = triple.split('-'); + let mut eat_start = false; + loop { + match matcher.next() { + Some("*") if eat_start => return Err("consecutive '*' are redundant"), + Some("*") if matchee.next().is_none() => return Ok(false), + Some("*") => eat_start = true, + Some(pat) if take(&mut eat_start) => { + if matchee.by_ref().all(|v| v != pat) { + return Ok(false); + } + } + Some(pat) if matchee.next() != Some(pat) => return Ok(false), + Some(_) => {} + None => return Ok(true), + } + } + } + + #[test] + fn sanity_match_triple() { + assert!(match_triple("a-b-c", "a-b-c").unwrap()); + assert!(match_triple("*-b-c", "a-b-c").unwrap()); + assert!(match_triple("*-c", "a-b-c").unwrap()); + assert!(match_triple("a", "a-b-c").unwrap()); + + assert!(!match_triple("*-a", "a-b-c").unwrap()); + assert!(!match_triple("*-a", "a-b-c").unwrap()); + assert!(match_triple("*-*", "a-b-c").is_err()); + assert!(match_triple("*-b-*", "a-b-c").is_err()); + } + pub mod hbvm; pub struct AssemblySpec { @@ -87,6 +130,7 @@ pub mod backend { } pub trait Backend { + fn triple(&self) -> String; fn assemble_reachable( &mut self, from: ty::Func, diff --git a/lang/src/son.rs b/lang/src/son.rs index bdff748d..b289696d 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -564,6 +564,7 @@ pub struct Codegen<'a> { pub files: &'a EntSlice, pub errors: &'a RefCell, pub warnings: &'a RefCell, + backend_triple: String, tys: &'a mut Types, ci: ItemCtx, pool: &'a mut Pool, @@ -596,6 +597,7 @@ impl<'a> Codegen<'a> { files: files.into(), errors: &ctx.parser.errors, warnings: &ctx.parser.warnings, + backend_triple: backend.triple(), tys: &mut ctx.tys, ci: Default::default(), pool: &mut ctx.pool, @@ -1446,6 +1448,16 @@ impl<'a> Codegen<'a> { self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID], self.tys); Some(Value::ptr(g).ty(glob.ty)) } + Expr::Directive { name: "target", args: &[Expr::String { pos, literal }], .. } => { + let value = match crate::backend::match_triple( + &literal[1..literal.len() - 1], + if self.ct.active() { "compile-time" } else { &self.backend_triple }, + ) { + Ok(v) => v, + Err(msg) => return self.error(pos, msg), + }; + self.gen_inferred_const(ctx, ty::Id::BOOL, value) + } Expr::Directive { name: "kindof", args: [ty], .. } => { let ty = self.ty(ty); self.gen_inferred_const(ctx, ty::Id::U8, ty.kind())