Skip to content
This repository was archived by the owner on Jun 10, 2024. It is now read-only.

Commit 0c76822

Browse files
committed
feat: finish up codegen from ssa ir
- Lowering from kernel to ssa is finished - Clean up and rework of lowering from ssa to mlir is finished - Fix up backtrace implementation in rt crate - Implement a variety of supporting intrinsics - Provide a few hacked together runtime functions for testing a stripped down init - Implement atom table generation for runtime similar to the intern crate used by the compiler NOTE: No real testing of the generated executables has been done, but quite complex Erlang source code can now be compiled and linked as desired, but there are certainly bugs present
1 parent 8c26261 commit 0c76822

File tree

111 files changed

+7866
-3618
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+7866
-3618
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ default-members = [
1313
]
1414

1515
exclude = [
16+
"library/macros",
1617
"liblumen_alloc",
1718
"liblumen_alloc_macros",
1819
"native_implemented/*",

compiler/binary/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ default = []
1212
std = ["anyhow/std"]
1313

1414
[dependencies]
15+
static_assertions = "1.1"
1516
paste = "1.0"
1617

1718
[dependencies.anyhow]

compiler/binary/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![feature(str_internals)]
88
#![feature(const_option_ext)]
99
#![feature(slice_take)]
10+
#![feature(arbitrary_enum_discriminant)]
1011

1112
extern crate alloc;
1213
#[cfg(any(test, feature = "std"))]
@@ -78,7 +79,7 @@ pub use self::traits::{Aligned, Binary, Bitstring, FromEndianBytes, ToEndianByte
7879
/// machine, or big-endian value on big-endian machine), this is already the case. When reading a value with non-native endianness
7980
/// though, we need to swap the order of the bytes first.
8081
///
81-
#[repr(C)]
82+
#[repr(u8)]
8283
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8384
pub enum Endianness {
8485
/// Most-significant bits "first"

compiler/binary/src/matcher.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ impl<'a> Matcher<'a> {
2222
}
2323
}
2424

25+
#[inline]
26+
pub fn bit_size(&self) -> usize {
27+
self.selection.bit_size()
28+
}
29+
2530
/// Reads a single byte from the current position in the input without
2631
/// advancing the input.
2732
pub fn read_byte(&mut self) -> Option<u8> {
@@ -55,6 +60,37 @@ impl<'a> Matcher<'a> {
5560
true
5661
}
5762

63+
/// Reads up to the specified number of bits into the provided buffer.
64+
///
65+
/// If the bitsize given is larger than the provided buffer, this function will panic.
66+
///
67+
/// If the number of bits requested was read, returns true, otherwise false.
68+
pub fn read_bits<const N: usize>(&mut self, buf: &mut [u8; N], bitsize: usize) -> bool {
69+
assert!(bitsize <= N * 8);
70+
71+
match self.selection.take(bitsize) {
72+
Ok(s) => {
73+
let trailing_bits = bitsize % 8;
74+
let needed = (bitsize / 8) + ((trailing_bits > 0) as usize);
75+
if let Some(slice) = s.as_bytes() {
76+
let buf2 = &mut buf[..needed];
77+
buf2.copy_from_slice(&slice[..needed]);
78+
} else {
79+
let ptr = buf.as_mut_ptr();
80+
let mut idx = 0;
81+
for byte in s.iter().take(needed) {
82+
unsafe {
83+
*ptr.add(idx) = byte;
84+
}
85+
idx += 1;
86+
}
87+
}
88+
true
89+
}
90+
Err(_) => false,
91+
}
92+
}
93+
5894
/// Reads a single number from the current position in the input without
5995
/// advancing the input. This should be used to build matchers which are
6096
/// fallible and operate on numeric values.
@@ -80,7 +116,7 @@ impl<'a> Matcher<'a> {
80116
endianness: Endianness,
81117
) -> Option<N>
82118
where
83-
N: FromEndianBytes<S> + core::ops::Shr<usize, Output = N>,
119+
N: FromEndianBytes<S> + core::ops::Shr<u32, Output = N>,
84120
{
85121
assert!(
86122
bitsize <= (S * 8),
@@ -91,7 +127,7 @@ impl<'a> Matcher<'a> {
91127
let mut bytes = [0u8; S];
92128

93129
let mut matcher = Matcher::new(selection);
94-
if matcher.read_bytes(&mut bytes) {
130+
if matcher.read_bits(&mut bytes, bitsize) {
95131
match endianness {
96132
Endianness::Native => {
97133
let n = N::from_ne_bytes(bytes);
@@ -101,15 +137,15 @@ impl<'a> Matcher<'a> {
101137
} else {
102138
// We need to shift the bytes right so that the least-significant
103139
// bits begin at the correct byte boundary
104-
let shift = 8 - (bitsize % 8);
140+
let shift: u32 = (8 - (bitsize % 8)).try_into().unwrap();
105141
Some(n >> shift)
106142
}
107143
}
108144
// Big-endian bytes never require a shift
109145
Endianness::Big => Some(N::from_be_bytes(bytes)),
110146
// Little-endian bytes always require a shift
111147
Endianness::Little => {
112-
let shift = 8 - (bitsize % 8);
148+
let shift: u32 = (8 - (bitsize % 8)).try_into().unwrap();
113149
let n = N::from_le_bytes(bytes);
114150
Some(n >> shift)
115151
}
@@ -165,6 +201,23 @@ impl<'a> Matcher<'a> {
165201
Some(matched)
166202
}
167203

204+
/// Matches any primitive numeric type from the input, of arbitrary bit size up to the
205+
/// containing type size, advancing the input if successful
206+
pub fn match_ap_number<N, const S: usize>(
207+
&mut self,
208+
bitsize: usize,
209+
endianness: Endianness,
210+
) -> Option<N>
211+
where
212+
N: FromEndianBytes<S> + core::ops::Shr<u32, Output = N>,
213+
{
214+
let matched = self.read_ap_number(bitsize, endianness)?;
215+
216+
self.selection = self.selection.shrink_front(S * 8);
217+
218+
Some(matched)
219+
}
220+
168221
/// Matches a big integer from the input, advancing the input if successful
169222
pub fn match_bigint(
170223
&mut self,

compiler/binary/src/select.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ impl<'a> Selection<'a> {
171171
}
172172
}
173173

174+
/// Creates a new selection covering all of the bits in the provided bitstring
175+
pub fn from_bitstring(data: &'a dyn Bitstring) -> Self {
176+
let bit_size = data.bit_size();
177+
if bit_size == 0 {
178+
return Self::Empty;
179+
}
180+
let bytes = unsafe { data.as_bytes_unchecked() };
181+
Self::new(bytes, 0, data.bit_offset(), None, bit_size).unwrap()
182+
}
183+
174184
/// This function can be used to select `n` bits from `data`, taking into account both byte
175185
/// and bit offsets, as well as an optional bit length constraint on `data` (i.e. the buffer
176186
/// is 8 bytes, but we only want to treat it as if it was 7 1/2 bytes).

compiler/binary/src/spec.rs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
1+
use static_assertions::assert_eq_size;
2+
13
use crate::Endianness;
24

35
/// Represents a binary segment constructor/match specification, e.g. `<<42:8/signed-little-integer>>`
6+
///
7+
/// The size and layout of this type is relied upon by our compiler. It can be represented as a single i64
8+
/// value, and has a layout equivalent to the following struct:
9+
///
10+
/// ```rust,ignore
11+
/// #[repr(C)]
12+
/// pub struct BinaryEntrySpecifier {
13+
/// tag: u32,
14+
/// data: [u32; 1]
15+
/// }
16+
/// ```
17+
///
18+
/// Where individual variants of the enum are discriminated by the tag and are encoded like:
19+
///
20+
/// ```rust,ignore
21+
/// #[repr(C)]
22+
/// pub struct BinaryEntrySpecifierInteger {
23+
/// _tag: [i8; 4],
24+
/// signed: u8,
25+
/// endianness: u8,
26+
/// unit: u8,
27+
/// _padding: [i8; 1]
28+
/// }
29+
/// ```
30+
///
31+
/// NOTE: This compact encoding is possible because `Endianness` is `#[repr(u8)]`
432
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33+
#[repr(u32)]
534
pub enum BinaryEntrySpecifier {
635
Integer {
736
signed: bool,
837
endianness: Endianness,
9-
unit: usize,
10-
},
38+
unit: u8,
39+
} = 0,
1140
Float {
1241
endianness: Endianness,
13-
unit: usize,
14-
},
42+
unit: u8,
43+
} = 1,
1544
Binary {
16-
unit: usize,
17-
},
18-
Utf8,
45+
unit: u8,
46+
} = 2,
47+
Utf8 = 3,
1948
Utf16 {
2049
endianness: Endianness,
21-
},
50+
} = 4,
2251
Utf32 {
2352
endianness: Endianness,
24-
},
53+
} = 5,
2554
}
55+
56+
assert_eq_size!(BinaryEntrySpecifier, u64);
57+
2658
impl BinaryEntrySpecifier {
2759
pub const DEFAULT: Self = Self::Integer {
2860
signed: false,
@@ -40,7 +72,7 @@ impl BinaryEntrySpecifier {
4072
pub fn unit(&self) -> usize {
4173
match self {
4274
Self::Integer { unit, .. } | Self::Float { unit, .. } | Self::Binary { unit, .. } => {
43-
*unit
75+
*unit as usize
4476
}
4577
_ => 1,
4678
}

0 commit comments

Comments
 (0)