softgpu_functional/
memory.rs1use crate::error::{FunctionalError, Result};
4use crate::ir::TypeId;
5
6#[derive(Debug, Clone)]
8pub struct GlobalArena {
9 bytes: Vec<u8>,
10}
11
12impl GlobalArena {
13 pub fn new(len: usize) -> Self {
14 Self {
15 bytes: vec![0u8; len],
16 }
17 }
18
19 pub fn from_bytes(bytes: Vec<u8>) -> Self {
20 Self { bytes }
21 }
22
23 pub fn len(&self) -> usize {
24 self.bytes.len()
25 }
26
27 pub fn is_empty(&self) -> bool {
28 self.bytes.is_empty()
29 }
30
31 pub fn as_slice(&self) -> &[u8] {
32 &self.bytes
33 }
34
35 pub fn as_mut_slice(&mut self) -> &mut [u8] {
36 &mut self.bytes
37 }
38
39 pub fn fill_i32_ramp(&mut self, start: i32) {
40 let mut v = start;
41 for chunk in self.bytes.chunks_exact_mut(4) {
42 chunk.copy_from_slice(&v.to_le_bytes());
43 v = v.wrapping_add(1);
44 }
45 }
46
47 pub fn read_i32_slice(&self) -> Result<Vec<i32>> {
48 if self.bytes.len() % 4 != 0 {
49 return Err(FunctionalError::Validation {
50 detail: "arena length not multiple of 4".into(),
51 });
52 }
53 Ok(self
54 .bytes
55 .chunks_exact(4)
56 .map(|c| i32::from_le_bytes([c[0], c[1], c[2], c[3]]))
57 .collect())
58 }
59
60 pub fn load(&self, addr: u64, ty: TypeId) -> Result<i64> {
61 let size = ty_size(ty);
62 let start = usize::try_from(addr).map_err(|_| FunctionalError::Bounds {
63 addr,
64 size,
65 arena_len: self.bytes.len(),
66 })?;
67 let end = start.checked_add(size).ok_or(FunctionalError::Bounds {
68 addr,
69 size,
70 arena_len: self.bytes.len(),
71 })?;
72 if end > self.bytes.len() {
73 return Err(FunctionalError::Bounds {
74 addr,
75 size,
76 arena_len: self.bytes.len(),
77 });
78 }
79 let s = &self.bytes[start..end];
80 Ok(match ty {
81 TypeId::I32 => i32::from_le_bytes([s[0], s[1], s[2], s[3]]) as i64,
82 TypeId::U32 => u32::from_le_bytes([s[0], s[1], s[2], s[3]]) as i64,
83 TypeId::U64 => {
84 u64::from_le_bytes([s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]]) as i64
85 }
86 })
87 }
88
89 pub fn store(&mut self, addr: u64, ty: TypeId, value: i64) -> Result<()> {
90 let size = ty_size(ty);
91 let start = usize::try_from(addr).map_err(|_| FunctionalError::Bounds {
92 addr,
93 size,
94 arena_len: self.bytes.len(),
95 })?;
96 let end = start.checked_add(size).ok_or(FunctionalError::Bounds {
97 addr,
98 size,
99 arena_len: self.bytes.len(),
100 })?;
101 if end > self.bytes.len() {
102 return Err(FunctionalError::Bounds {
103 addr,
104 size,
105 arena_len: self.bytes.len(),
106 });
107 }
108 match ty {
109 TypeId::I32 => {
110 self.bytes[start..end].copy_from_slice(&(value as i32).to_le_bytes());
111 }
112 TypeId::U32 => {
113 self.bytes[start..end].copy_from_slice(&(value as u32).to_le_bytes());
114 }
115 TypeId::U64 => {
116 self.bytes[start..end].copy_from_slice(&(value as u64).to_le_bytes());
117 }
118 }
119 Ok(())
120 }
121}
122
123pub fn ty_size(ty: TypeId) -> usize {
124 match ty {
125 TypeId::I32 | TypeId::U32 => 4,
126 TypeId::U64 => 8,
127 }
128}
129
130pub fn kernarg_load(kernarg: &[u8], offset: u32, ty: TypeId) -> Result<i64> {
131 let size = ty_size(ty);
132 let start = offset as usize;
133 let end = start.checked_add(size).ok_or(FunctionalError::Bounds {
134 addr: u64::from(offset),
135 size,
136 arena_len: kernarg.len(),
137 })?;
138 if end > kernarg.len() {
139 return Err(FunctionalError::Bounds {
140 addr: u64::from(offset),
141 size,
142 arena_len: kernarg.len(),
143 });
144 }
145 let s = &kernarg[start..end];
146 Ok(match ty {
147 TypeId::I32 => i32::from_le_bytes([s[0], s[1], s[2], s[3]]) as i64,
148 TypeId::U32 => u32::from_le_bytes([s[0], s[1], s[2], s[3]]) as i64,
149 TypeId::U64 => u64::from_le_bytes([s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]]) as i64,
150 })
151}