Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion crates/rustc_codegen_spirv/src/builder/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of args[0].immediate() is guaranteed to panic, see my latest additions to the test ICE-ing:

    pub fn immediate(self) -> V {
        match self.val {
            OperandValue::Immediate(s) => s,
            _ => bug!("not immediate: {:?}", self),
        }
    }

Our ABI takes apart ScalarPairs into an Adt(a, b), but only if the ScalarPair consists out of two non-ZST fields. I have no idea how to correctly load / store ScalarPairs, especially given that condition. Maybe @eddyb can help us here?

BackendRepr::ScalarPair(a, b) => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I've been feeling around in the dark, no clue here.

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.
Expand Down
54 changes: 54 additions & 0 deletions tests/compiletests/ui/lang/core/intrinsics/black_box.rs
Original file line number Diff line number Diff line change
@@ -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],
]
}
17 changes: 17 additions & 0 deletions tests/compiletests/ui/lang/core/intrinsics/black_box.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading