mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-22 14:56:27 +00:00
Duplicate SpirvValueKind::ConstantPointer
into a separate FnAddr
variant. (#557)
This commit is contained in:
parent
d6ff9cd439
commit
820573a21f
@ -2075,33 +2075,59 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
fn call(
|
fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut llfn: Self::Value,
|
callee: Self::Value,
|
||||||
args: &[Self::Value],
|
args: &[Self::Value],
|
||||||
funclet: Option<&Self::Funclet>,
|
funclet: Option<&Self::Funclet>,
|
||||||
) -> Self::Value {
|
) -> Self::Value {
|
||||||
if funclet.is_some() {
|
if funclet.is_some() {
|
||||||
self.fatal("TODO: Funclets are not supported");
|
self.fatal("TODO: Funclets are not supported");
|
||||||
}
|
}
|
||||||
// dereference pointers
|
|
||||||
let (result_type, argument_types) = loop {
|
// NOTE(eddyb) see the comment on `SpirvValueKind::FnAddr`, this should
|
||||||
match self.lookup_type(llfn.ty) {
|
// be fixed upstream, so we never see any "function pointer" values being
|
||||||
SpirvType::Pointer { .. } => {
|
// created just to perform direct calls.
|
||||||
// Note that this doesn't necessarily mean a dynamic load, the function is
|
let (callee_val, result_type, argument_types) = match self.lookup_type(callee.ty) {
|
||||||
// probably in cx.constant_pointers
|
// HACK(eddyb) this seems to be needed, but it's not what `get_fn_addr`
|
||||||
llfn = self.load(llfn, Align::from_bytes(0).unwrap());
|
// produces, are these coming from inside `rustc_codegen_spirv`?
|
||||||
}
|
|
||||||
SpirvType::Function {
|
SpirvType::Function {
|
||||||
return_type,
|
return_type,
|
||||||
arguments,
|
arguments,
|
||||||
} => break (return_type, arguments),
|
} => (callee.def(self), return_type, arguments),
|
||||||
ty => self.fatal(&format!("Calling non-function type: {:?}", ty)),
|
|
||||||
|
SpirvType::Pointer { pointee } => match self.lookup_type(pointee) {
|
||||||
|
SpirvType::Function {
|
||||||
|
return_type,
|
||||||
|
arguments,
|
||||||
|
} => (
|
||||||
|
match callee.kind {
|
||||||
|
SpirvValueKind::FnAddr { function } => function,
|
||||||
|
|
||||||
|
// Truly indirect call.
|
||||||
|
_ => {
|
||||||
|
let fn_ptr_val = callee.def(self);
|
||||||
|
self.zombie(fn_ptr_val, "indirect calls are not supported in SPIR-V");
|
||||||
|
fn_ptr_val
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
return_type,
|
||||||
|
arguments,
|
||||||
|
),
|
||||||
|
_ => bug!(
|
||||||
|
"call expected `fn` pointer to point to function type, got `{}`",
|
||||||
|
self.debug_type(pointee)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => bug!(
|
||||||
|
"call expected function or `fn` pointer type, got `{}`",
|
||||||
|
self.debug_type(callee.ty)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (argument, argument_type) in args.iter().zip(argument_types) {
|
for (argument, argument_type) in args.iter().zip(argument_types) {
|
||||||
assert_ty_eq!(self, argument.ty, argument_type);
|
assert_ty_eq!(self, argument.ty, argument_type);
|
||||||
}
|
}
|
||||||
let llfn_def = llfn.def(self);
|
let libm_intrinsic = self.libm_intrinsics.borrow().get(&callee_val).cloned();
|
||||||
let libm_intrinsic = self.libm_intrinsics.borrow().get(&llfn_def).cloned();
|
|
||||||
if let Some(libm_intrinsic) = libm_intrinsic {
|
if let Some(libm_intrinsic) = libm_intrinsic {
|
||||||
let result = self.call_libm_intrinsic(libm_intrinsic, result_type, args);
|
let result = self.call_libm_intrinsic(libm_intrinsic, result_type, args);
|
||||||
if result_type != result.ty {
|
if result_type != result.ty {
|
||||||
@ -2114,7 +2140,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else if [self.panic_fn_id.get(), self.panic_bounds_check_fn_id.get()]
|
} else if [self.panic_fn_id.get(), self.panic_bounds_check_fn_id.get()]
|
||||||
.contains(&Some(llfn_def))
|
.contains(&Some(callee_val))
|
||||||
{
|
{
|
||||||
// HACK(eddyb) redirect builtin panic calls to an abort, to avoid
|
// HACK(eddyb) redirect builtin panic calls to an abort, to avoid
|
||||||
// needing to materialize `&core::panic::Location` or `format_args!`.
|
// needing to materialize `&core::panic::Location` or `format_args!`.
|
||||||
@ -2123,7 +2149,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
let args = args.iter().map(|arg| arg.def(self)).collect::<Vec<_>>();
|
let args = args.iter().map(|arg| arg.def(self)).collect::<Vec<_>>();
|
||||||
self.emit()
|
self.emit()
|
||||||
.function_call(result_type, None, llfn_def, args)
|
.function_call(result_type, None, callee_val, args)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_type(result_type)
|
.with_type(result_type)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,14 @@ use std::{fs::File, io::Write, path::Path};
|
|||||||
pub enum SpirvValueKind {
|
pub enum SpirvValueKind {
|
||||||
Def(Word),
|
Def(Word),
|
||||||
|
|
||||||
|
// FIXME(eddyb) this shouldn't be needed, but `rustc_codegen_ssa` still relies
|
||||||
|
// on converting `Function`s to `Value`s even for direct calls, the `Builder`
|
||||||
|
// should just have direct and indirect `call` variants (or a `Callee` enum).
|
||||||
|
// FIXME(eddyb) document? not sure what to do with the `ConstantPointer` comment.
|
||||||
|
FnAddr {
|
||||||
|
function: Word,
|
||||||
|
},
|
||||||
|
|
||||||
/// There are a fair number of places where `rustc_codegen_ssa` creates a pointer to something
|
/// There are a fair number of places where `rustc_codegen_ssa` creates a pointer to something
|
||||||
/// that cannot be pointed to in SPIR-V. For example, constant values are frequently emitted as
|
/// that cannot be pointed to in SPIR-V. For example, constant values are frequently emitted as
|
||||||
/// a pointer to constant memory, and then dereferenced where they're used. Functions are the
|
/// a pointer to constant memory, and then dereferenced where they're used. Functions are the
|
||||||
@ -69,7 +77,9 @@ impl SpirvValue {
|
|||||||
Some(initializer.with_type(ty))
|
Some(initializer.with_type(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
SpirvValueKind::Def(_) | SpirvValueKind::LogicalPtrCast { .. } => None,
|
SpirvValueKind::FnAddr { .. }
|
||||||
|
| SpirvValueKind::Def(_)
|
||||||
|
| SpirvValueKind::LogicalPtrCast { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +99,21 @@ impl SpirvValue {
|
|||||||
pub fn def_with_span(self, cx: &CodegenCx<'_>, span: Span) -> Word {
|
pub fn def_with_span(self, cx: &CodegenCx<'_>, span: Span) -> Word {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
SpirvValueKind::Def(word) => word,
|
SpirvValueKind::Def(word) => word,
|
||||||
|
SpirvValueKind::FnAddr { .. } => {
|
||||||
|
if cx.is_system_crate() {
|
||||||
|
*cx.zombie_undefs_for_system_fn_addrs
|
||||||
|
.borrow()
|
||||||
|
.get(&self.ty)
|
||||||
|
.expect("FnAddr didn't go through proper undef registration")
|
||||||
|
} else {
|
||||||
|
cx.tcx
|
||||||
|
.sess
|
||||||
|
.err("Cannot use this function pointer for anything other than calls");
|
||||||
|
// Because we never get beyond compilation (into e.g. linking),
|
||||||
|
// emitting an invalid ID reference here is OK.
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SpirvValueKind::ConstantPointer {
|
SpirvValueKind::ConstantPointer {
|
||||||
initializer: _,
|
initializer: _,
|
||||||
|
@ -60,6 +60,7 @@ pub struct CodegenCx<'tcx> {
|
|||||||
/// Cache of all the builtin symbols we need
|
/// Cache of all the builtin symbols we need
|
||||||
pub sym: Rc<Symbols>,
|
pub sym: Rc<Symbols>,
|
||||||
pub instruction_table: InstructionTable,
|
pub instruction_table: InstructionTable,
|
||||||
|
pub zombie_undefs_for_system_fn_addrs: RefCell<HashMap<Word, Word>>,
|
||||||
pub libm_intrinsics: RefCell<HashMap<Word, super::builder::libm_intrinsics::LibmIntrinsic>>,
|
pub libm_intrinsics: RefCell<HashMap<Word, super::builder::libm_intrinsics::LibmIntrinsic>>,
|
||||||
|
|
||||||
/// Simple `panic!("...")` and builtin panics (from MIR `Assert`s) call `#[lang = "panic"]`.
|
/// Simple `panic!("...")` and builtin panics (from MIR `Assert`s) call `#[lang = "panic"]`.
|
||||||
@ -120,6 +121,7 @@ impl<'tcx> CodegenCx<'tcx> {
|
|||||||
kernel_mode,
|
kernel_mode,
|
||||||
sym,
|
sym,
|
||||||
instruction_table: InstructionTable::new(),
|
instruction_table: InstructionTable::new(),
|
||||||
|
zombie_undefs_for_system_fn_addrs: Default::default(),
|
||||||
libm_intrinsics: Default::default(),
|
libm_intrinsics: Default::default(),
|
||||||
panic_fn_id: Default::default(),
|
panic_fn_id: Default::default(),
|
||||||
panic_bounds_check_fn_id: Default::default(),
|
panic_bounds_check_fn_id: Default::default(),
|
||||||
@ -361,10 +363,36 @@ impl<'tcx> MiscMethods<'tcx> for CodegenCx<'tcx> {
|
|||||||
self.get_fn_ext(instance)
|
self.get_fn_ext(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(eddyb) see the comment on `SpirvValueKind::FnAddr`, this should
|
||||||
|
// be fixed upstream, so we never see any "function pointer" values being
|
||||||
|
// created just to perform direct calls.
|
||||||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value {
|
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value {
|
||||||
let function = self.get_fn(instance);
|
let function = self.get_fn(instance);
|
||||||
let span = self.tcx.def_span(instance.def_id());
|
let span = self.tcx.def_span(instance.def_id());
|
||||||
self.make_constant_pointer(span, function)
|
|
||||||
|
let ty = SpirvType::Pointer {
|
||||||
|
pointee: function.ty,
|
||||||
|
}
|
||||||
|
.def(span, self);
|
||||||
|
|
||||||
|
if self.is_system_crate() {
|
||||||
|
// Create these undefs up front instead of on demand in SpirvValue::def because
|
||||||
|
// SpirvValue::def can't use cx.emit()
|
||||||
|
self.zombie_undefs_for_system_fn_addrs
|
||||||
|
.borrow_mut()
|
||||||
|
.entry(ty)
|
||||||
|
.or_insert_with(|| {
|
||||||
|
// We want a unique ID for these undefs, so don't use the caching system.
|
||||||
|
self.emit_global().undef(ty, None)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SpirvValue {
|
||||||
|
kind: SpirvValueKind::FnAddr {
|
||||||
|
function: function.def_cx(self),
|
||||||
|
},
|
||||||
|
ty,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eh_personality(&self) -> Self::Value {
|
fn eh_personality(&self) -> Self::Value {
|
||||||
|
Loading…
Reference in New Issue
Block a user