1mod builder_methods;
2mod byte_addressable_buffer;
3mod ext_inst;
4mod format_args_decompiler;
5mod intrinsics;
6pub mod libm_intrinsics;
7mod spirv_asm;
8
9pub use ext_inst::ExtInst;
10use rustc_span::{BytePos, DUMMY_SP, SourceFile, Symbol};
11pub use spirv_asm::InstructionTable;
12
13use crate::maybe_pqp_cg_ssa as rustc_codegen_ssa;
15
16use crate::builder_spirv::{SpirvValue, SpirvValueExt};
17use crate::codegen_cx::CodegenCx;
18use crate::spirv_type::SpirvType;
19use rspirv::spirv::Word;
20use rustc_abi::{HasDataLayout, Size, TargetDataLayout};
21use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
22use rustc_codegen_ssa::mir::place::PlaceRef;
23use rustc_codegen_ssa::traits::{
24 AbiBuilderMethods, ArgAbiBuilderMethods, BackendTypes, BuilderMethods,
25 CoverageInfoBuilderMethods, DebugInfoBuilderMethods, StaticBuilderMethods,
26 TypeMembershipCodegenMethods,
27};
28use rustc_errors::{Diag, DiagMessage};
29use rustc_middle::mir::coverage::CoverageKind;
30use rustc_middle::span_bug;
31use rustc_middle::ty::layout::{
32 FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
33 LayoutOfHelpers, TyAndLayout,
34};
35use rustc_middle::ty::{Instance, Ty, TyCtxt, TypingEnv};
36use rustc_span::Span;
37use rustc_span::def_id::DefId;
38use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
39use rustc_target::spec::{HasTargetSpec, Target};
40use std::ops::{Deref, Range};
41
42pub struct Builder<'a, 'tcx> {
43 cx: &'a CodegenCx<'tcx>,
44 current_block: <Self as BackendTypes>::BasicBlock,
45 current_span: Option<Span>,
46}
47
48impl<'a, 'tcx> Builder<'a, 'tcx> {
49 pub fn emit(&mut self) -> std::cell::RefMut<'a, rspirv::dr::Builder> {
55 self.cx.builder.builder_for_block(self.current_block)
56 }
57
58 pub fn zombie(&self, word: Word, reason: &str) {
59 if let Some(current_span) = self.current_span {
60 self.zombie_with_span(word, current_span, reason);
61 } else {
62 self.zombie_no_span(word, reason);
63 }
64 }
65
66 pub fn undef_zombie(&self, word: Word, reason: &str) -> SpirvValue {
67 if let Some(current_span) = self.current_span {
68 self.undef_zombie_with_span(word, current_span, reason)
69 } else {
70 self.undef_zombie_no_span(word, reason)
71 }
72 }
73 pub fn undef_zombie_with_span(&self, ty: Word, span: Span, reason: &str) -> SpirvValue {
74 let undef = self.undef(ty);
75 self.zombie_with_span(undef.def(self), span, reason);
76 undef
77 }
78 pub fn undef_zombie_no_span(&self, ty: Word, reason: &str) -> SpirvValue {
79 let undef = self.undef(ty);
80 self.zombie_no_span(undef.def(self), reason);
81 undef
82 }
83
84 pub fn validate_atomic(&self, ty: Word, to_zombie: Word) {
85 if !self.i8_i16_atomics_allowed {
86 match self.lookup_type(ty) {
87 SpirvType::Integer(width, _) if width < 32 => {
88 self.zombie(to_zombie, "atomic on i8 or i16 when disallowed by runtime");
89 }
90 _ => (),
91 }
92 }
93 }
94
95 #[track_caller]
96 pub fn struct_err(&self, msg: impl Into<DiagMessage>) -> Diag<'_> {
97 if let Some(current_span) = self.current_span {
98 self.tcx.dcx().struct_span_err(current_span, msg)
99 } else {
100 self.tcx.dcx().struct_err(msg)
101 }
102 }
103
104 #[track_caller]
105 pub fn err(&self, msg: impl Into<DiagMessage>) {
106 if let Some(current_span) = self.current_span {
107 self.tcx.dcx().span_err(current_span, msg);
108 } else {
109 self.tcx.dcx().err(msg);
110 }
111 }
112
113 #[track_caller]
114 pub fn fatal(&self, msg: impl Into<DiagMessage>) -> ! {
115 if let Some(current_span) = self.current_span {
116 self.tcx.dcx().span_fatal(current_span, msg)
117 } else {
118 self.tcx.dcx().fatal(msg)
119 }
120 }
121
122 pub fn span(&self) -> Span {
123 self.current_span.unwrap_or(DUMMY_SP)
124 }
125
126 pub fn type_ptr_to(&self, ty: Word) -> Word {
128 SpirvType::Pointer { pointee: ty }.def(self.span(), self)
129 }
130
131 fn rotate(&mut self, value: SpirvValue, shift: SpirvValue, is_left: bool) -> SpirvValue {
133 let width = match self.lookup_type(shift.ty) {
134 SpirvType::Integer(width, _) => width,
135 other => self.fatal(format!(
136 "cannot rotate non-integer type: {}",
137 other.debug(shift.ty, self)
138 )),
139 };
140 let int_size = self.constant_int(shift.ty, width.into());
141 let mask = self.constant_int(shift.ty, (width - 1).into());
142 let zero = self.constant_int(shift.ty, 0);
143 let bool = SpirvType::Bool.def(self.span(), self);
144 let mask_shift = self.and(shift, mask);
146 let sub = self.sub(int_size, mask_shift);
147 let (lhs, rhs) = if is_left {
148 (self.shl(value, mask_shift), self.lshr(value, sub))
149 } else {
150 (self.lshr(value, mask_shift), self.shl(value, sub))
151 };
152 let or = self.or(lhs, rhs);
153 let mask_is_zero = self
156 .emit()
157 .i_equal(bool, None, mask_shift.def(self), zero.def(self))
158 .unwrap()
159 .with_type(bool);
160 self.select(mask_is_zero, value, or)
161 }
162}
163
164impl<'a, 'tcx> Deref for Builder<'a, 'tcx> {
166 type Target = CodegenCx<'tcx>;
167
168 fn deref(&self) -> &Self::Target {
169 self.cx
170 }
171}
172
173impl<'a, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'tcx> {
174 fn add_coverage(&mut self, _instance: Instance<'tcx>, _kind: &CoverageKind) {}
175}
176
177impl<'a, 'tcx> DebugInfoBuilderMethods<'_> for Builder<'a, 'tcx> {
178 fn dbg_var_addr(
179 &mut self,
180 _dbg_var: Self::DIVariable,
181 _scope_metadata: Self::DILocation,
182 _variable_alloca: Self::Value,
183 _direct_offset: Size,
184 _indirect_offsets: &[Size],
186 _fragment: &Option<Range<Size>>,
187 ) {
188 }
189
190 fn set_dbg_loc(&mut self, _: Self::DILocation) {}
191
192 fn clear_dbg_loc(&mut self) {}
193
194 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {}
195
196 fn set_var_name(&mut self, _value: Self::Value, _name: &str) {}
197
198 fn dbg_var_value(
199 &mut self,
200 _dbg_var: Self::DIVariable,
201 _dbg_loc: Self::DILocation,
202 _value: Self::Value,
203 _direct_offset: Size,
204 _indirect_offsets: &[Size],
206 _fragment: &Option<Range<Size>>,
209 ) {
210 }
211
212 fn dbg_scope_fn(
213 &mut self,
214 _instance: Instance<'_>,
215 _fn_abi: &FnAbi<'_, Ty<'_>>,
216 _maybe_definition_llfn: Option<Self::Function>,
217 ) -> Self::DIScope {
218 }
219
220 fn dbg_create_lexical_block(
221 &mut self,
222 _pos: BytePos,
223 _parent_scope: Self::DIScope,
224 ) -> Self::DIScope {
225 }
226
227 fn dbg_location_clone_with_discriminator(
228 &mut self,
229 _loc: Self::DILocation,
230 _discriminator: u32,
231 ) -> Option<Self::DILocation> {
232 None
233 }
234
235 fn dbg_loc(
236 &mut self,
237 _scope: Self::DIScope,
238 _inlined_at: Option<Self::DILocation>,
239 _span: Span,
240 ) -> Self::DILocation {
241 }
242
243 fn extend_scope_to_file(
244 &mut self,
245 _scope_metadata: Self::DIScope,
246 _file: &SourceFile,
247 ) -> Self::DIScope {
248 }
249
250 fn create_dbg_var(
251 &mut self,
252 _variable_name: Symbol,
253 _variable_type: Ty<'_>,
254 _scope_metadata: Self::DIScope,
255 _variable_kind: rustc_codegen_ssa::mir::debuginfo::VariableKind,
256 _span: Span,
257 ) -> Self::DIVariable {
258 }
259}
260
261impl<'a, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'a, 'tcx> {
262 fn store_fn_arg(
263 &mut self,
264 arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
265 idx: &mut usize,
266 dst: PlaceRef<'tcx, Self::Value>,
267 ) {
268 fn next(bx: &mut Builder<'_, '_>, idx: &mut usize) -> SpirvValue {
269 let val = bx.get_param(*idx);
270 *idx += 1;
271 val
272 }
273 match arg_abi.mode {
274 PassMode::Ignore => {}
275 PassMode::Direct(_) => {
276 let arg = next(self, idx);
277 self.store_arg(arg_abi, arg, dst);
278 }
279 PassMode::Pair(..) => {
280 OperandValue::Pair(next(self, idx), next(self, idx)).store(self, dst);
281 }
282 PassMode::Cast { .. } | PassMode::Indirect { .. } => span_bug!(
283 self.span(),
284 "query hooks should've made this `PassMode` impossible: {:#?}",
285 arg_abi
286 ),
287 }
288 }
289
290 fn store_arg(
291 &mut self,
292 arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
293 val: Self::Value,
294 dst: PlaceRef<'tcx, Self::Value>,
295 ) {
296 match arg_abi.mode {
297 PassMode::Ignore => {}
298 PassMode::Direct(_) | PassMode::Pair(..) => {
299 OperandRef::from_immediate_or_packed_pair(self, val, arg_abi.layout)
300 .val
301 .store(self, dst);
302 }
303 PassMode::Cast { .. } | PassMode::Indirect { .. } => span_bug!(
304 self.span(),
305 "query hooks should've made this `PassMode` impossible: {:#?}",
306 arg_abi
307 ),
308 }
309 }
310}
311
312impl AbiBuilderMethods for Builder<'_, '_> {
313 fn get_param(&mut self, index: usize) -> Self::Value {
314 let builder = self.emit();
315 let param =
316 &builder.module_ref().functions[builder.selected_function().unwrap()].parameters[index];
317 param
318 .result_id
319 .unwrap()
320 .with_type(param.result_type.unwrap())
321 }
322}
323
324impl<'a, 'tcx> StaticBuilderMethods for Builder<'a, 'tcx> {
325 fn get_static(&mut self, def_id: DefId) -> Self::Value {
326 self.cx.get_static(def_id)
327 }
328}
329
330impl<'a, 'tcx> BackendTypes for Builder<'a, 'tcx> {
331 type Value = <CodegenCx<'tcx> as BackendTypes>::Value;
332 type Function = <CodegenCx<'tcx> as BackendTypes>::Function;
333
334 type BasicBlock = <CodegenCx<'tcx> as BackendTypes>::BasicBlock;
335 type Type = <CodegenCx<'tcx> as BackendTypes>::Type;
336 type FunctionSignature = <CodegenCx<'tcx> as BackendTypes>::FunctionSignature;
337 type Funclet = <CodegenCx<'tcx> as BackendTypes>::Funclet;
338
339 type DIScope = <CodegenCx<'tcx> as BackendTypes>::DIScope;
340 type DIVariable = <CodegenCx<'tcx> as BackendTypes>::DIVariable;
341 type DILocation = <CodegenCx<'tcx> as BackendTypes>::DILocation;
342}
343
344impl<'a, 'tcx> HasTypingEnv<'tcx> for Builder<'a, 'tcx> {
345 fn typing_env(&self) -> TypingEnv<'tcx> {
346 self.cx.typing_env()
347 }
348}
349
350impl<'a, 'tcx> HasTargetSpec for Builder<'a, 'tcx> {
351 fn target_spec(&self) -> &Target {
352 self.cx.target_spec()
353 }
354}
355
356impl<'a, 'tcx> HasTyCtxt<'tcx> for Builder<'a, 'tcx> {
357 fn tcx(&self) -> TyCtxt<'tcx> {
358 self.cx.tcx
359 }
360}
361
362impl<'a, 'tcx> HasDataLayout for Builder<'a, 'tcx> {
363 fn data_layout(&self) -> &TargetDataLayout {
364 self.cx.data_layout()
365 }
366}
367
368impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx> {
369 type LayoutOfResult = TyAndLayout<'tcx>;
370
371 #[inline]
372 fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
373 self.cx.handle_layout_err(err, span, ty)
374 }
375}
376
377impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx> {
378 type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
379
380 #[inline]
381 fn handle_fn_abi_err(
382 &self,
383 err: FnAbiError<'tcx>,
384 span: Span,
385 fn_abi_request: FnAbiRequest<'tcx>,
386 ) -> ! {
387 self.cx.handle_fn_abi_err(err, span, fn_abi_request)
388 }
389}
390
391impl<'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'tcx> {}