1use alloc::{format, string::String};
37use core::fmt::Write;
38
39use super::{help::WrappedConstructor, BackendResult, Error};
40use crate::{
41 back,
42 proc::{Alignment, NameKey},
43 Handle,
44};
45
46const WORDS_PER_REGISTER: u32 = 4;
48
49const COMPONENTS: [char; WORDS_PER_REGISTER as usize] = ['x', 'y', 'z', 'w'];
51
52fn immediate_word(raw: &str, word: u32) -> String {
54 let component = COMPONENTS[(word % WORDS_PER_REGISTER) as usize];
55 format!("{raw}[{}].{component}", word / WORDS_PER_REGISTER)
56}
57
58impl<W: Write> super::Writer<'_, W> {
59 pub(super) fn write_global_immediate(
67 &mut self,
68 module: &crate::Module,
69 handle: Handle<crate::GlobalVariable>,
70 global: &crate::GlobalVariable,
71 ) -> BackendResult {
72 let target = self
73 .options
74 .immediates_target
75 .as_ref()
76 .expect("No bind target was defined for the immediates block");
77 let (register, space) = (target.register, target.space);
78
79 let word_count = module.types[global.ty]
80 .inner
81 .size(module.to_ctx())
82 .div_ceil(4);
83 let register_count = word_count.div_ceil(WORDS_PER_REGISTER);
84
85 let name = self.names[&NameKey::GlobalVariable(handle)].clone();
86 let block_name = self.namer.call(&format!("{name}_block"));
87 let raw_name = self.namer.call(&format!("{name}_raw"));
88
89 write!(self.out, "cbuffer {block_name} : register(b{register}")?;
90 if space != 0 {
91 write!(self.out, ", space{space}")?;
92 }
93 writeln!(self.out, ") {{ uint4 {raw_name}[{register_count}]; }};")?;
94
95 write!(self.out, "static ")?;
96 self.write_type(module, global.ty)?;
97 writeln!(self.out, " {name};")?;
98
99 self.immediate_raw_names.insert(handle, raw_name);
100
101 Ok(())
102 }
103
104 pub(super) fn write_immediate_constructors(&mut self, module: &crate::Module) -> BackendResult {
109 for (_, global) in module.global_variables.iter() {
110 if global.space == crate::AddressSpace::Immediate {
111 self.write_wrapped_constructors_for_type(module, global.ty)?;
112 }
113 }
114 Ok(())
115 }
116
117 pub(super) fn write_immediates_initialization(
122 &mut self,
123 module: &crate::Module,
124 info: &crate::valid::FunctionInfo,
125 ) -> BackendResult {
126 for (handle, global) in module.global_variables.iter() {
127 if global.space != crate::AddressSpace::Immediate || info[handle].is_empty() {
128 continue;
129 }
130
131 let name = self.names[&NameKey::GlobalVariable(handle)].clone();
132 let raw = self.immediate_raw_names[&handle].clone();
133
134 write!(self.out, "{}{name} = ", back::INDENT)?;
135 self.write_immediate_load(module, &raw, global.ty, 0)?;
136 writeln!(self.out, ";")?;
137 }
138 Ok(())
139 }
140
141 fn write_immediate_load(
144 &mut self,
145 module: &crate::Module,
146 raw: &str,
147 ty: Handle<crate::Type>,
148 offset: u32,
149 ) -> BackendResult {
150 match module.types[ty].inner {
151 crate::TypeInner::Scalar(scalar) => self.write_immediate_scalar(raw, scalar, offset),
152 crate::TypeInner::Vector { size, scalar } => {
153 self.write_immediate_vector(raw, size, scalar, offset)
154 }
155 crate::TypeInner::Matrix {
156 columns,
157 rows,
158 scalar,
159 } => {
160 write!(
161 self.out,
162 "{}{}x{}(",
163 scalar.to_hlsl_str()?,
164 columns as u8,
165 rows as u8,
166 )?;
167
168 let column_stride = Alignment::from(rows) * scalar.width as u32;
170 for column in 0..columns as u32 {
171 if column != 0 {
172 write!(self.out, ", ")?;
173 }
174 self.write_immediate_vector(
175 raw,
176 rows,
177 scalar,
178 offset + column * column_stride,
179 )?;
180 }
181 write!(self.out, ")")?;
182 Ok(())
183 }
184 crate::TypeInner::Struct { ref members, .. } => {
185 let constructor = WrappedConstructor { ty };
186 self.write_wrapped_constructor_function_name(module, constructor)?;
187 write!(self.out, "(")?;
188 for (i, member) in members.iter().enumerate() {
189 if i != 0 {
190 write!(self.out, ", ")?;
191 }
192 self.write_immediate_load(module, raw, member.ty, offset + member.offset)?;
193 }
194 write!(self.out, ")")?;
195 Ok(())
196 }
197 ref other => Err(Error::Unimplemented(format!(
198 "immediate data of type {other:?}"
199 ))),
200 }
201 }
202
203 fn write_immediate_scalar(
205 &mut self,
206 raw: &str,
207 scalar: crate::Scalar,
208 offset: u32,
209 ) -> BackendResult {
210 use crate::ScalarKind as Kind;
211
212 let word = offset / 4;
213 match (scalar.kind, scalar.width) {
214 (Kind::Float | Kind::Sint | Kind::Uint, 4) => {
215 let cast = scalar.kind.to_hlsl_cast();
216 write!(self.out, "{cast}({})", immediate_word(raw, word))?;
217 }
218 (Kind::Float | Kind::Sint | Kind::Uint, 2) => {
220 let bits = format!("{} >> {}u", immediate_word(raw, word), (offset % 4) * 8);
221 if scalar.kind == Kind::Float {
222 write!(self.out, "asfloat16(uint16_t({bits}))")?;
223 } else {
224 write!(self.out, "{}({bits})", scalar.to_hlsl_str()?)?;
225 }
226 }
227 (Kind::Float | Kind::Sint | Kind::Uint, 8) => {
229 let low = immediate_word(raw, word);
230 let high = immediate_word(raw, word + 1);
231 let bits = format!("uint64_t({low}) | (uint64_t({high}) << 32u)");
232 match scalar.kind {
233 Kind::Float => write!(self.out, "asdouble({low}, {high})")?,
234 Kind::Sint => write!(self.out, "int64_t({bits})")?,
235 _ => write!(self.out, "({bits})")?,
236 }
237 }
238 _ => return Err(Error::UnsupportedScalar(scalar)),
239 }
240 Ok(())
241 }
242
243 fn write_immediate_vector(
249 &mut self,
250 raw: &str,
251 size: crate::VectorSize,
252 scalar: crate::Scalar,
253 offset: u32,
254 ) -> BackendResult {
255 let count = size as u32;
256
257 write!(self.out, "{}{}(", scalar.to_hlsl_str()?, count)?;
258 for component in 0..count {
259 if component != 0 {
260 write!(self.out, ", ")?;
261 }
262 self.write_immediate_scalar(raw, scalar, offset + component * scalar.width as u32)?;
263 }
264 write!(self.out, ")")?;
265 Ok(())
266 }
267}