Implement many things

This commit is contained in:
khyperia 2020-08-20 15:13:36 +02:00
parent 2c8c2937ad
commit 5f93702a92
5 changed files with 252 additions and 103 deletions

View File

@ -5,6 +5,7 @@ use rustc_target::abi::{Abi, FieldsShape, Primitive, Scalar, Size};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SpirvType {
Void,
Bool,
Integer(u32, bool),
Float(u32),
@ -110,6 +111,7 @@ fn trans_scalar<'spv, 'tcx>(
} else {
// TODO: Implement this properly
let void = cx.emit_global().type_void();
cx.def_type(void, SpirvType::Void);
(
cx.emit_global()
.type_pointer(None, StorageClass::Generic, void),
@ -164,7 +166,16 @@ fn trans_aggregate<'spv, 'tcx>(cx: &CodegenCx<'spv, 'tcx>, ty: TyAndLayout<'tcx>
// TODO: Is this the right thing to do?
FieldsShape::Union(_field_count) => {
let byte = cx.emit_global().type_int(8, 0);
cx.emit_global().type_array(byte, ty.size.bytes() as u32)
cx.def_type(byte, SpirvType::Integer(8, false));
let result = cx.emit_global().type_array(byte, ty.size.bytes() as u32);
cx.def_type(
result,
SpirvType::Array {
element: byte,
count: ty.size.bytes() as u32,
},
);
result
}
FieldsShape::Array { stride: _, count } => {
// TODO: Assert stride is same as spirv's stride?

View File

@ -1,14 +1,18 @@
use super::Builder;
use crate::abi::SpirvType;
use crate::builder_spirv::{BuilderCursor, SpirvValueExt};
use rspirv::spirv::StorageClass;
use rustc_codegen_ssa::base::to_immediate;
use rustc_codegen_ssa::common::{
AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope,
};
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::LayoutTypeMethods;
use rustc_codegen_ssa::traits::{BuilderMethods, OverflowOp};
use rustc_codegen_ssa::MemFlags;
use rustc_middle::ty::Ty;
use rustc_target::abi::{Align, Size};
use rustc_target::abi::{Abi, Align, Size};
use std::ops::Range;
impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
@ -80,26 +84,37 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
self.emit().ret_value(value.def).unwrap();
}
fn br(&mut self, _dest: Self::BasicBlock) {
todo!()
fn br(&mut self, dest: Self::BasicBlock) {
self.emit().branch(dest).unwrap()
}
fn cond_br(
&mut self,
_cond: Self::Value,
_then_llbb: Self::BasicBlock,
_else_llbb: Self::BasicBlock,
cond: Self::Value,
then_llbb: Self::BasicBlock,
else_llbb: Self::BasicBlock,
) {
todo!()
self.emit()
.branch_conditional(cond.def, then_llbb, else_llbb, &[])
.unwrap()
}
fn switch(
&mut self,
_v: Self::Value,
_else_llbb: Self::BasicBlock,
_cases: impl ExactSizeIterator<Item = (u128, Self::BasicBlock)>,
v: Self::Value,
else_llbb: Self::BasicBlock,
cases: impl ExactSizeIterator<Item = (u128, Self::BasicBlock)>,
) {
todo!()
let cases = cases
.map(|(i, b)| {
if i > u32::MAX as u128 {
panic!("Switches to values above u32::MAX not supported: {:?}", i)
} else {
(i as u32, b)
}
})
.collect::<Vec<_>>();
self.emit().switch(v.def, else_llbb, cases).unwrap()
}
fn invoke(
@ -114,7 +129,7 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
}
fn unreachable(&mut self) {
todo!()
self.emit().unreachable().unwrap()
}
fn add(&mut self, _lhs: Self::Value, _rhs: Self::Value) -> Self::Value {
@ -268,24 +283,36 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
todo!()
}
fn alloca(&mut self, _ty: Self::Type, _align: Align) -> Self::Value {
todo!()
fn alloca(&mut self, ty: Self::Type, _align: Align) -> Self::Value {
let ptr_ty = self.emit().type_pointer(None, StorageClass::Function, ty);
self.def_type(ptr_ty, SpirvType::Pointer { pointee: ty });
self.emit()
.variable(ptr_ty, None, StorageClass::Function, None)
.with_type(ptr_ty)
}
fn dynamic_alloca(&mut self, _ty: Self::Type, _align: Align) -> Self::Value {
todo!()
fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value {
self.alloca(ty, align)
}
fn array_alloca(&mut self, _ty: Self::Type, _len: Self::Value, _align: Align) -> Self::Value {
todo!()
}
fn load(&mut self, _ptr: Self::Value, _align: Align) -> Self::Value {
todo!()
fn load(&mut self, ptr: Self::Value, _align: Align) -> Self::Value {
let ty = match self.lookup_type(ptr.ty) {
SpirvType::Pointer { pointee } => pointee,
ty => panic!("load called on variable that wasn't a pointer: {:?}", ty),
};
self.emit()
.load(ty, None, ptr.def, None, [])
.unwrap()
.with_type(ty)
}
fn volatile_load(&mut self, _ptr: Self::Value) -> Self::Value {
todo!()
fn volatile_load(&mut self, ptr: Self::Value) -> Self::Value {
// TODO: Can we do something here?
self.load(ptr, Align::from_bytes(0).unwrap())
}
fn atomic_load(
@ -299,9 +326,36 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
fn load_operand(
&mut self,
_place: PlaceRef<'tcx, Self::Value>,
place: PlaceRef<'tcx, Self::Value>,
) -> OperandRef<'tcx, Self::Value> {
todo!()
if place.layout.is_zst() {
return OperandRef::new_zst(self, place.layout);
}
let val = if let Some(llextra) = place.llextra {
OperandValue::Ref(place.llval, Some(llextra), place.align)
} else if self.cx.is_backend_immediate(place.layout) {
let llval = self.load(place.llval, place.align);
OperandValue::Immediate(to_immediate(self, llval, place.layout))
} else if let Abi::ScalarPair(ref a, ref b) = place.layout.abi {
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
let mut load = |i, align| {
let llptr = self.struct_gep(place.llval, i as u64);
self.load(llptr, align)
};
OperandValue::Pair(
load(0, place.align),
load(1, place.align.restrict_for_offset(b_offset)),
)
} else {
OperandValue::Ref(place.llval, None, place.align)
};
OperandRef {
val,
layout: place.layout,
}
}
/// Called for Rvalue::Repeat when the elem is neither a ZST nor optimizable using memset.
@ -322,18 +376,24 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
todo!()
}
fn store(&mut self, _val: Self::Value, _ptr: Self::Value, _align: Align) -> Self::Value {
todo!()
fn store(&mut self, val: Self::Value, ptr: Self::Value, _align: Align) -> Self::Value {
let ptr_elem_ty = match self.lookup_type(ptr.ty) {
SpirvType::Pointer { pointee } => pointee,
ty => panic!("store called on variable that wasn't a pointer: {:?}", ty),
};
assert_eq!(ptr_elem_ty, val.ty);
self.emit().store(ptr.def, val.def, None, &[]).unwrap();
val
}
fn store_with_flags(
&mut self,
_val: Self::Value,
_ptr: Self::Value,
_align: Align,
val: Self::Value,
ptr: Self::Value,
align: Align,
_flags: MemFlags,
) -> Self::Value {
todo!()
self.store(val, ptr, align)
}
fn atomic_store(
@ -398,29 +458,58 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
todo!()
}
fn ptrtoint(&mut self, _val: Self::Value, _dest_ty: Self::Type) -> Self::Value {
todo!()
fn ptrtoint(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
match self.lookup_type(val.ty) {
SpirvType::Pointer { .. } => (),
other => panic!("ptrtoint called on non-pointer source type: {:?}", other),
}
self.emit()
.bitcast(dest_ty, None, val.def)
.unwrap()
.with_type(dest_ty)
}
fn inttoptr(&mut self, _val: Self::Value, _dest_ty: Self::Type) -> Self::Value {
todo!()
fn inttoptr(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
match self.lookup_type(dest_ty) {
SpirvType::Pointer { .. } => (),
other => panic!("inttoptr called on non-pointer dest type: {:?}", other),
}
self.emit()
.bitcast(dest_ty, None, val.def)
.unwrap()
.with_type(dest_ty)
}
fn bitcast(&mut self, _val: Self::Value, _dest_ty: Self::Type) -> Self::Value {
todo!()
fn bitcast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
self.emit()
.bitcast(dest_ty, None, val.def)
.unwrap()
.with_type(dest_ty)
}
fn intcast(
&mut self,
_val: Self::Value,
_dest_ty: Self::Type,
_is_signed: bool,
) -> Self::Value {
todo!()
fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value {
panic!(
"TODO: intcast not implemented yet: val={:?} val.ty={:?} dest_ty={:?} is_signed={}",
val,
self.lookup_type(val.ty),
self.lookup_type(dest_ty),
is_signed
);
}
fn pointercast(&mut self, _val: Self::Value, _dest_ty: Self::Type) -> Self::Value {
todo!()
fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
match self.lookup_type(val.ty) {
SpirvType::Pointer { .. } => (),
other => panic!("pointercast called on non-pointer source type: {:?}", other),
}
match self.lookup_type(dest_ty) {
SpirvType::Pointer { .. } => (),
other => panic!("pointercast called on non-pointer dest type: {:?}", other),
}
self.emit()
.bitcast(dest_ty, None, val.def)
.unwrap()
.with_type(dest_ty)
}
fn icmp(&mut self, _op: IntPredicate, _lhs: Self::Value, _rhs: Self::Value) -> Self::Value {
@ -581,12 +670,12 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
/// Called for `StorageLive`
fn lifetime_start(&mut self, _ptr: Self::Value, _size: Size) {
todo!()
// ignore
}
/// Called for `StorageDead`
fn lifetime_end(&mut self, _ptr: Self::Value, _size: Size) {
todo!()
// ignore
}
fn instrprof_increment(
@ -601,11 +690,22 @@ impl<'a, 'spv, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'spv, 'tcx> {
fn call(
&mut self,
_llfn: Self::Value,
_args: &[Self::Value],
_funclet: Option<&Self::Funclet>,
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
) -> Self::Value {
todo!()
if funclet.is_some() {
panic!("TODO: Funclets are not supported");
}
let result_type = match self.lookup_type(llfn.ty) {
SpirvType::Function { return_type, .. } => return_type,
ty => panic!("Calling non-function type: {:?}", ty),
};
let args = args.iter().map(|arg| arg.def).collect::<Vec<_>>();
self.emit()
.function_call(result_type, None, llfn.def, args)
.unwrap()
.with_type(result_type)
}
fn zext(&mut self, _val: Self::Value, _dest_ty: Self::Type) -> Self::Value {

View File

@ -125,14 +125,14 @@ impl<'a, 'spv, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'spv, 'tcx> {
todo!()
}
fn arg_memory_ty(&self, _arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type {
todo!()
fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type {
self.trans_type(arg_abi.layout)
}
}
impl<'a, 'spv, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'spv, 'tcx> {
fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
todo!()
// TODO: Implement this?
}
fn get_param(&self, index: usize) -> Self::Value {
@ -143,14 +143,14 @@ impl<'a, 'spv, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'spv, 'tcx> {
impl<'a, 'spv, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'spv, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
_instance: Instance<'tcx>,
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_args: &[OperandRef<'tcx, Self::Value>],
_llresult: Self::Value,
_span: Span,
_caller_instance: Instance<'tcx>,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, Self::Value>],
llresult: Self::Value,
span: Span,
caller_instance: Instance<'tcx>,
) {
todo!()
println!("TODO: codegen_intrinsic_call unimplemented: instance={:?} fn_abi={:?} args={:?} llresult={:?} span={:?} caller_instance={:?}", instance, fn_abi, args, llresult, span, caller_instance);
}
fn is_codegen_intrinsic(
@ -160,7 +160,7 @@ impl<'a, 'spv, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'spv, 'tcx> {
_caller_instance: Instance<'tcx>,
) -> bool {
// TODO
false
true
}
fn abort(&mut self) {

View File

@ -35,7 +35,7 @@ pub struct CodegenCx<'spv, 'tcx> {
pub codegen_unit: &'tcx CodegenUnit<'tcx>,
pub spirv_module: &'spv ModuleSpirv,
pub builder: BuilderSpirv,
pub function_defs: RefCell<HashMap<Instance<'tcx>, Word>>,
pub function_defs: RefCell<HashMap<Instance<'tcx>, SpirvValue>>,
pub function_parameter_values: RefCell<HashMap<Word, Vec<SpirvValue>>>,
pub type_defs: RefCell<HashMap<Word, SpirvType>>,
}
@ -302,21 +302,30 @@ impl<'spv, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'spv, 'tcx> {
}
/// Returns the number of elements in `self` if it is a LLVM vector type.
fn vector_length(&self, _ty: Self::Type) -> usize {
todo!()
fn vector_length(&self, ty: Self::Type) -> usize {
match self.lookup_type(ty) {
SpirvType::Vector { count, .. } => count as usize,
ty => panic!("vector_length called on non-vector type: {:?}", ty),
}
}
fn float_width(&self, _ty: Self::Type) -> usize {
todo!()
fn float_width(&self, ty: Self::Type) -> usize {
match self.lookup_type(ty) {
SpirvType::Float(width) => width as usize,
ty => panic!("float_width called on non-float type: {:?}", ty),
}
}
/// Retrieves the bit width of the integer type `self`.
fn int_width(&self, _ty: Self::Type) -> u64 {
todo!()
fn int_width(&self, ty: Self::Type) -> u64 {
match self.lookup_type(ty) {
SpirvType::Integer(width, _) => width as u64,
ty => panic!("int_width called on non-integer type: {:?}", ty),
}
}
fn val_ty(&self, _v: Self::Value) -> Self::Type {
todo!()
fn val_ty(&self, v: Self::Value) -> Self::Type {
v.ty
}
}
@ -351,11 +360,11 @@ impl<'spv, 'tcx> MiscMethods<'tcx> for CodegenCx<'spv, 'tcx> {
}
fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function {
self.function_defs.borrow()[&instance]
self.function_defs.borrow()[&instance].def
}
fn get_fn_addr(&self, _instance: Instance<'tcx>) -> Self::Value {
todo!()
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value {
self.function_defs.borrow()[&instance]
}
fn eh_personality(&self) -> Self::Value {
@ -406,29 +415,51 @@ impl<'spv, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'spv, 'tcx> {
_symbol_name: &str,
) {
let fn_abi = FnAbi::of_instance(self, instance, &[]);
let mut argument_types = fn_abi
.args
.iter()
.map(|arg| match arg.mode {
let mut argument_types = Vec::new();
for arg in fn_abi.args {
let arg_type = match arg.mode {
PassMode::Ignore => panic!(
"TODO: Argument PassMode::Ignore not supported yet: {:?}",
arg
),
PassMode::Direct(_arg_attributes) => self.trans_type(arg.layout),
PassMode::Pair(_arg_attributes_1, _arg_attributes_2) => self.trans_type(arg.layout),
PassMode::Pair(_arg_attributes_1, _arg_attributes_2) => {
// TODO: Make this more efficient, don't generate struct
let tuple = self.lookup_type(self.trans_type(arg.layout));
let (left, right) = match tuple {
SpirvType::Adt { ref field_types } => {
if let [left, right] = *field_types.as_slice() {
(left, right)
} else {
panic!("PassMode::Pair did not produce tuple: {:?}", tuple)
}
}
_ => panic!("PassMode::Pair did not produce tuple: {:?}", tuple),
};
argument_types.push(left);
argument_types.push(right);
continue;
}
PassMode::Cast(_cast_target) => self.trans_type(arg.layout),
// TODO: Deal with wide ptr?
PassMode::Indirect(_arg_attributes, _wide_ptr_attrs) => {
let pointee = self.trans_type(arg.layout);
self.emit_global()
.type_pointer(None, StorageClass::Generic, pointee)
let ptr_type =
self.emit_global()
.type_pointer(None, StorageClass::Generic, pointee);
self.def_type(ptr_type, SpirvType::Pointer { pointee });
ptr_type
}
})
.collect::<Vec<_>>();
// TODO: Do we register types created here in the type tracker?
};
argument_types.push(arg_type);
}
// TODO: Other modes
let return_type = match fn_abi.ret.mode {
PassMode::Ignore => self.emit_global().type_void(),
PassMode::Ignore => {
let void = self.emit_global().type_void();
self.def_type(void, SpirvType::Void);
void
}
PassMode::Direct(_arg_attributes) => self.trans_type(fn_abi.ret.layout),
PassMode::Pair(_arg_attributes_1, _arg_attributes_2) => {
self.trans_type(fn_abi.ret.layout)
@ -438,12 +469,14 @@ impl<'spv, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'spv, 'tcx> {
// TODO: Deal with wide ptr?
PassMode::Indirect(_arg_attributes, _wide_ptr_attrs) => {
let pointee = self.trans_type(fn_abi.ret.layout);
argument_types.push(self.emit_global().type_pointer(
None,
StorageClass::Generic,
pointee,
));
self.emit_global().type_void()
let pointer = self
.emit_global()
.type_pointer(None, StorageClass::Generic, pointee);
self.def_type(pointer, SpirvType::Pointer { pointee });
argument_types.push(pointer);
let void = self.emit_global().type_void();
self.def_type(void, SpirvType::Void);
void
}
};
let mut emit = self.emit_global();
@ -460,10 +493,19 @@ impl<'spv, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'spv, 'tcx> {
.collect::<Vec<_>>();
emit.end_function().unwrap();
self.function_defs.borrow_mut().insert(instance, fn_id);
self.function_defs
.borrow_mut()
.insert(instance, fn_id.with_type(function_type));
self.function_parameter_values
.borrow_mut()
.insert(fn_id, parameter_values);
self.def_type(
function_type,
SpirvType::Function {
return_type,
arguments: argument_types,
},
);
}
}

View File

@ -41,8 +41,9 @@ use rustc_data_structures::sync::MetadataRef;
use rustc_errors::{ErrorReported, FatalError, Handler};
use rustc_middle::dep_graph::{DepGraph, WorkProduct};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{Instance, TyCtxt};
use rustc_session::config::{OptLevel, OutputFilenames, OutputType};
use rustc_session::Session;
use rustc_span::Symbol;
@ -52,14 +53,12 @@ use std::path::Path;
use std::{fs::File, io::Write, sync::Arc};
use things::{SpirvModuleBuffer, SprivThinBuffer};
/*
fn dump_mir<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
let mut mir = ::std::io::Cursor::new(Vec::new());
rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut mir).unwrap();
let s = String::from_utf8(mir.into_inner()).unwrap();
println!("{}", s);
}
*/
struct NoLlvmMetadataLoader;
@ -279,19 +278,16 @@ impl ExtraBackendMethods for SsaBackend {
let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
for &(mono_item, (linkage, visibility)) in &mono_items {
// if let MonoItem::Fn(instance) = mono_item {
// dump_mir(tcx, instance);
// }
mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
}
println!("Done predefining");
// ... and now that we have everything pre-defined, fill out those definitions.
for &(mono_item, _) in &mono_items {
// if let MonoItem::Fn(instance) = mono_item {
// dump_mir(tcx, instance);
// }
if option_env!("DUMP_MIR").is_some() {
if let MonoItem::Fn(instance) = mono_item {
dump_mir(tcx, instance);
}
}
mono_item.define::<Builder<'_, '_, '_>>(&cx);
}