diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index deab2b087c..f94cd49d62 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -9,7 +9,7 @@ use crate::custom_insts::CustomInst; use crate::spirv_type::SpirvType; use rspirv::dr::Operand; use rspirv::spirv::GLOp; -use rustc_codegen_ssa::mir::operand::OperandRef; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{BuilderMethods, IntrinsicCallBuilderMethods}; use rustc_middle::ty::layout::LayoutOf; @@ -240,6 +240,33 @@ impl<'a, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'tcx> { sym::ctpop => self.count_ones(args[0].immediate()), sym::bitreverse => self.bit_reverse(args[0].immediate()), + sym::black_box => { + // TODO(LegNeato): do something more sophisticated that prevents DCE + self.tcx + .dcx() + .warn("black_box intrinsic does not prevent optimization in Rust GPU"); + + let layout = self.layout_of(arg_tys[0]); + let llty = layout.spirv_type(self.span(), self); + + match args[0].val { + // Pass through scalars + OperandValue::Immediate(v) => v, + + // Preserve both elements by spilling + reloading + OperandValue::Pair(..) => { + let tmp = self.alloca(layout.size, layout.align.abi); + self.store(args[0].immediate(), tmp, layout.align.abi); + self.load(llty, tmp, layout.align.abi) + } + + // For lvalues, load + OperandValue::Ref(place) => self.load(llty, place.llval, place.align), + + // For ZSTs, return undef of the right type + OperandValue::ZeroSized => self.undef(llty), + } + } sym::bswap => { // https://github.com/KhronosGroup/SPIRV-LLVM/pull/221/files // TODO: Definitely add tests to make sure this impl is right. diff --git a/tests/compiletests/ui/lang/core/intrinsics/black_box.rs b/tests/compiletests/ui/lang/core/intrinsics/black_box.rs new file mode 100644 index 0000000000..f6afc814b8 --- /dev/null +++ b/tests/compiletests/ui/lang/core/intrinsics/black_box.rs @@ -0,0 +1,54 @@ +// Test black_box intrinsic +// build-pass +// compile-flags: -C llvm-args=--disassemble-fn=black_box::disassemble + +#![allow(internal_features)] +#![feature(core_intrinsics)] +#![no_std] + +use core::hint::black_box; +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] out: &mut [u32]) { + let result = disassemble(); + for i in 0..result.len() { + out[i] = result[i]; + } +} + +pub fn disassemble() -> [u32; 12] { + // Test with various types + let x = 42i32; + let y = black_box(x); + + let a = 3.14f32; + let b = black_box(a); + + let v = [1, 2, 3, 4]; + let w = black_box(v); + + // Test in expressions + let result = black_box(10) + black_box(20); + + // Test with references + let data = 100u32; + let ref_data = black_box(&data); + + let ref_slice = black_box(v.as_slice()); + + [ + y as u32, + f32::to_bits(b), + w[0], + w[1], + w[2], + w[3], + result, + *ref_data, + ref_slice[0], + ref_slice[1], + ref_slice[2], + ref_slice[3], + ] +} diff --git a/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr b/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr new file mode 100644 index 0000000000..a61737d9c2 --- /dev/null +++ b/tests/compiletests/ui/lang/core/intrinsics/black_box.stderr @@ -0,0 +1,17 @@ +warning: black_box intrinsic does not prevent optimization in Rust GPU + +%1 = OpFunction %2 None %3 +%4 = OpLabel +OpLine %5 34 17 +%6 = OpIAdd %7 %8 %9 +OpLine %5 40 5 +%10 = OpBitcast %7 %11 +OpLine %12 1092 17 +%13 = OpBitcast %7 %14 +OpLine %5 40 4 +%15 = OpCompositeConstruct %2 %10 %13 %16 %17 %18 %19 %6 %20 +OpNoLine +OpReturnValue %15 +OpFunctionEnd +warning: 1 warning emitted +