Zombies are errors in user code

This commit is contained in:
khyperia 2020-10-10 13:53:33 +02:00
parent e56c35aaf3
commit 01ccf5cf39
6 changed files with 77 additions and 38 deletions

View File

@ -305,6 +305,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
cursor: Default::default(),
current_fn: Default::default(),
basic_block: Default::default(),
current_span: Default::default(),
}
}
@ -336,6 +337,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
cursor,
current_fn: llfn,
basic_block: label,
current_span: Default::default(),
}
}
@ -354,6 +356,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
cursor: new_cursor,
current_fn: self.current_fn,
basic_block: new_bb,
current_span: Default::default(),
}
}
@ -365,8 +368,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
self.basic_block
}
fn set_span(&self, _span: Span) {
// TODO
fn set_span(&self, span: Span) {
*self.current_span.borrow_mut() = Some(span);
}
fn ret_void(&mut self) {
@ -380,7 +383,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
fn br(&mut self, dest: Self::BasicBlock) {
if !self.kernel_mode && self.basic_block == dest {
// TODO: Remove once structurizer is done.
self.zombie(dest, "Infinite loop before structurizer is done");
self.zombie_even_in_user_code(dest, "Infinite loop before structurizer is done");
}
self.emit().branch(dest).unwrap()
}

View File

@ -8,7 +8,7 @@ use crate::abi::ConvSpirvType;
use crate::builder_spirv::{BuilderCursor, SpirvValue, SpirvValueExt};
use crate::codegen_cx::CodegenCx;
use crate::spirv_type::SpirvType;
use rspirv::spirv::StorageClass;
use rspirv::spirv::{StorageClass, Word};
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::mir::place::PlaceRef;
@ -28,6 +28,7 @@ use rustc_span::source_map::Span;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
use rustc_target::spec::{HasTargetSpec, Target};
use std::cell::RefCell;
use std::ops::Deref;
pub struct Builder<'a, 'tcx> {
@ -35,6 +36,7 @@ pub struct Builder<'a, 'tcx> {
cursor: BuilderCursor,
current_fn: <Self as BackendTypes>::Function,
basic_block: <Self as BackendTypes>::BasicBlock,
current_span: RefCell<Option<Span>>,
}
impl<'a, 'tcx> Builder<'a, 'tcx> {
@ -43,6 +45,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.emit_with_cursor(self.cursor)
}
pub fn zombie(&self, word: Word, reason: &'static str) {
if let Some(current_span) = *self.current_span.borrow() {
self.zombie_with_span(word, current_span, reason);
} else {
self.zombie_no_span(word, reason);
}
}
pub fn validate_atomic(&self, ty: Word, to_zombie: Word) {
if !self.i8_i16_atomics_allowed {
match self.lookup_type(ty) {
SpirvType::Integer(width, _) if width < 32 => {
self.zombie(to_zombie, "atomic on i8 or i16 when disallowed by runtime");
}
_ => (),
}
}
}
pub fn gep_help(
&self,
ptr: SpirvValue,

View File

@ -67,7 +67,7 @@ impl<'tcx> CodegenCx<'tcx> {
},
SpirvType::Integer(128, _) => {
let result = self.undef(ty);
self.zombie(result.def, "u128 constant");
self.zombie_no_span(result.def, "u128 constant");
result
}
other => panic!("constant_int invalid on type {}", other.debug(ty, self)),
@ -160,7 +160,7 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> {
let len = s.as_str().len();
let ty = self.type_ptr_to(self.layout_of(self.tcx.types.str_).spirv_type(self));
let result = self.undef(ty);
self.zombie(result.def, "constant string");
self.zombie_no_span(result.def, "constant string");
(result, self.const_usize(len as u64))
}
fn const_struct(&self, elts: &[Self::Value], _packed: bool) -> Self::Value {
@ -283,7 +283,7 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> {
) => {
if a_space != b_space {
// TODO: Emit the correct type that is passed into this function.
self.zombie(value.def, "invalid pointer space in constant");
self.zombie_no_span(value.def, "invalid pointer space in constant");
}
assert_ty_eq!(self, a, b);
}
@ -313,7 +313,7 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> {
} else {
// constant ptrcast is not supported in spir-v
let result = val.def.with_type(ty);
self.zombie(result.def, "const_ptrcast");
self.zombie_no_span(result.def, "const_ptrcast");
result
}
}
@ -421,7 +421,7 @@ impl<'tcx> CodegenCx<'tcx> {
*data = *c + asdf->y[*c];
}
*/
self.zombie(result.def, "constant runtime array value");
self.zombie_no_span(result.def, "constant runtime array value");
result
}
SpirvType::Pointer { .. } => {

View File

@ -14,6 +14,7 @@ use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::{Instance, ParamEnv, Ty, TypeFoldable};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Align, LayoutOf};
use std::collections::HashMap;
@ -83,7 +84,8 @@ impl<'tcx> CodegenCx<'tcx> {
if crate::is_blocklisted_fn(name) {
// This can happen if we call a blocklisted function in another crate.
let result = self.undef(function_type);
self.zombie(result.def, "called blocklisted fn");
// TODO: Span info here
self.zombie_no_span(result.def, "called blocklisted fn");
return result;
}
let mut emit = self.emit_global();
@ -130,13 +132,14 @@ impl<'tcx> CodegenCx<'tcx> {
let ty = instance.ty(self.tcx, ParamEnv::reveal_all());
let sym = self.tcx.symbol_name(instance).name;
let g = self.declare_global(self.layout_of(ty).spirv_type(self));
let span = self.tcx.def_span(def_id);
let g = self.declare_global(span, self.layout_of(ty).spirv_type(self));
self.instances.borrow_mut().insert(instance, g);
self.set_linkage(g.def, sym.to_string(), LinkageType::Import);
g
}
fn declare_global(&self, ty: Word) -> SpirvValue {
fn declare_global(&self, span: Span, ty: Word) -> SpirvValue {
let ptr_ty = SpirvType::Pointer {
storage_class: StorageClass::Function,
pointee: ty,
@ -147,7 +150,7 @@ impl<'tcx> CodegenCx<'tcx> {
.variable(ptr_ty, None, StorageClass::Function, None)
.with_type(ptr_ty);
// TODO: These should be StorageClass::Private, so just zombie for now.
self.zombie(result.def, "declare_global");
self.zombie_with_span(result.def, span, "Globals are not supported yet");
result
}
@ -292,7 +295,8 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> {
other => panic!("TODO: Linkage type not supported yet: {:?}", other),
};
let g = self.declare_global(spvty);
let span = self.tcx.def_span(def_id);
let g = self.declare_global(span, spvty);
// unsafe {
// llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
@ -356,7 +360,7 @@ impl<'tcx> StaticMethods for CodegenCx<'tcx> {
}
.def(self);
let result = self.undef(ty);
self.zombie(result.def, "static_addr_of");
self.zombie_no_span(result.def, "static_addr_of");
result
}

View File

@ -23,7 +23,7 @@ use rustc_middle::ty::{Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::def_id::CrateNum;
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::SourceFile;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
@ -116,10 +116,32 @@ impl<'tcx> CodegenCx<'tcx> {
///
/// Finally, if *user* code is marked as zombie, then this means that the user tried to do something that isn't
/// supported, and should be an error.
pub fn zombie(&self, word: Word, reason: &'static str) {
pub fn zombie_with_span(&self, word: Word, span: Span, reason: &'static str) {
if self.is_system_crate() {
self.zombie_values.borrow_mut().insert(word, reason);
} else {
self.tcx.sess.span_err(span, reason);
}
}
pub fn zombie_no_span(&self, word: Word, reason: &'static str) {
if self.is_system_crate() {
self.zombie_values.borrow_mut().insert(word, reason);
} else {
self.tcx.sess.err(reason);
}
}
pub fn zombie_even_in_user_code(&self, word: Word, reason: &'static str) {
self.zombie_values.borrow_mut().insert(word, reason);
}
fn is_system_crate(&self) -> bool {
let krate_attrs = self.tcx.hir().krate_attrs();
self.tcx
.sess
.contains_name(krate_attrs, sym::compiler_builtins)
|| self.tcx.sess.contains_name(krate_attrs, sym::core)
}
pub fn finalize_module(self) -> Module {
let mut result = self.builder.finalize();
export_zombies(&mut result, &self.zombie_values.borrow());
@ -152,8 +174,8 @@ impl<'tcx> CodegenCx<'tcx> {
.def(self);
// We want a unique ID for these undefs, so don't use the caching system.
let result = self.emit_global().undef(ty, None).with_type(ty);
// It's obviously invalid, so zombie it.
self.zombie(result.def, "get_fn_addr");
// It's obviously invalid, so zombie it. Zombie it in user code as well, because it's valid there too.
self.zombie_even_in_user_code(result.def, "get_fn_addr");
self.function_pointers
.borrow_mut()
.insert_no_overwrite(result, function)
@ -168,17 +190,6 @@ impl<'tcx> CodegenCx<'tcx> {
.get_by_left(&pointer)
.cloned()
}
pub fn validate_atomic(&self, ty: Word, to_zombie: Word) {
if !self.i8_i16_atomics_allowed {
match self.lookup_type(ty) {
SpirvType::Integer(width, _) if width < 32 => {
self.zombie(to_zombie, "atomic on i8 or i16 when disallowed by runtime");
}
_ => (),
}
}
}
}
impl<'tcx> BackendTypes for CodegenCx<'tcx> {

View File

@ -72,16 +72,16 @@ impl SpirvType {
.type_int(width, if signedness { 1 } else { 0 });
match width {
8 if !cx.builder.has_capability(Capability::Int8) => {
cx.zombie(result, "u8 without OpCapability Int8")
cx.zombie_no_span(result, "u8 without OpCapability Int8")
}
16 if !cx.builder.has_capability(Capability::Int16) => {
cx.zombie(result, "u16 without OpCapability Int16")
cx.zombie_no_span(result, "u16 without OpCapability Int16")
}
64 if !cx.builder.has_capability(Capability::Int64) => {
cx.zombie(result, "u64 without OpCapability Int64")
cx.zombie_no_span(result, "u64 without OpCapability Int64")
}
8 | 16 | 32 | 64 => (),
128 => cx.zombie(result, "u128"),
128 => cx.zombie_no_span(result, "u128"),
other => panic!("Integer width {} invalid for spir-v", other),
};
result
@ -90,7 +90,7 @@ impl SpirvType {
let result = cx.emit_global().type_float(width);
match width {
64 if !cx.builder.has_capability(Capability::Float64) => {
cx.zombie(result, "f64 without OpCapability Float64")
cx.zombie_no_span(result, "f64 without OpCapability Float64")
}
32 | 64 => (),
other => panic!("Float width {} invalid for spir-v", other),
@ -154,7 +154,7 @@ impl SpirvType {
SpirvType::RuntimeArray { element } => {
let result = cx.emit_global().type_runtime_array(element);
if cx.kernel_mode {
cx.zombie(result, "RuntimeArray in kernel mode");
cx.zombie_no_span(result, "RuntimeArray in kernel mode");
}
result
}
@ -165,7 +165,7 @@ impl SpirvType {
let result = cx.emit_global().type_pointer(None, storage_class, pointee);
// no pointers to functions
if let SpirvType::Function { .. } = cx.lookup_type(pointee) {
cx.zombie(result, "pointer to function")
cx.zombie_even_in_user_code(result, "pointer to function")
}
result
}
@ -197,7 +197,7 @@ impl SpirvType {
.type_pointer(Some(id), storage_class, pointee);
// no pointers to functions
if let SpirvType::Function { .. } = cx.lookup_type(pointee) {
cx.zombie(result, "pointer to function")
cx.zombie_even_in_user_code(result, "pointer to function")
}
result
}