Skip to content

Commit

Permalink
Add new handling for SPIR-V targets
Browse files Browse the repository at this point in the history
  • Loading branch information
XAMPPRocky committed Apr 9, 2021
1 parent 8c89b49 commit 45e9561
Show file tree
Hide file tree
Showing 19 changed files with 277 additions and 203 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ cargo_test_no_features examples/runners/cpu
cargo_test_no_features examples/shaders/sky-shader
cargo_test_no_features examples/shaders/simplest-shader

cargo compiletest --target-env unknown,vulkan1.1,spv1.3
cargo compiletest --target-env vulkan1.1,spv1.3
4 changes: 2 additions & 2 deletions crates/rustc_codegen_spirv/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ fn trans_scalar<'tcx>(

match scalar.value {
Primitive::Int(width, mut signedness) => {
if cx.kernel_mode {
if cx.target.is_kernel() {
signedness = false;
}
SpirvType::Integer(width.size().bits() as u32, signedness).def(span, cx)
Expand Down Expand Up @@ -644,7 +644,7 @@ pub fn auto_struct_layout<'tcx>(
fn trans_struct<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>) -> Word {
if let TyKind::Foreign(_) = ty.ty.kind() {
// "An unsized FFI type that is opaque to Rust", `extern type A;` (currently unstable)
if cx.kernel_mode {
if cx.target.is_kernel() {
// TODO: This should use the name of the struct as the name. However, names are not stable across crates,
// e.g. core::fmt::Opaque in one crate and fmt::Opaque in core.
return SpirvType::Opaque {
Expand Down
6 changes: 3 additions & 3 deletions crates/rustc_codegen_spirv/src/builder/ext_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct ExtInst {

impl ExtInst {
pub fn import_glsl<'a, 'tcx>(&mut self, bx: &Builder<'a, 'tcx>) -> Word {
assert!(!bx.kernel_mode);
assert!(!bx.target.is_kernel());
match self.glsl {
Some(id) => id,
None => {
Expand All @@ -29,7 +29,7 @@ impl ExtInst {
}

pub fn import_opencl<'a, 'tcx>(&mut self, bx: &Builder<'a, 'tcx>) -> Word {
assert!(bx.kernel_mode);
assert!(bx.target.is_kernel());
match self.opencl {
Some(id) => id,
None => {
Expand All @@ -42,7 +42,7 @@ impl ExtInst {

pub fn import_integer_functions_2_intel<'tcx>(&mut self, cx: &CodegenCx<'tcx>) {
if !self.integer_functions_2_intel {
assert!(!cx.kernel_mode);
assert!(!cx.target.is_kernel());
self.integer_functions_2_intel = true;
cx.emit_global()
.extension("SPV_INTEL_shader_integer_functions2");
Expand Down
44 changes: 22 additions & 22 deletions crates/rustc_codegen_spirv/src/builder/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {

// TODO: Configure these to be ocl vs. gl ext instructions, etc.
sym::sqrtf32 | sym::sqrtf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::sqrt, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Sqrt, ret_ty, [args[0].immediate()])
}
}
sym::powif32 | sym::powif64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::pown,
ret_ty,
Expand All @@ -173,21 +173,21 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::sinf32 | sym::sinf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::sin, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Sin, ret_ty, [args[0].immediate()])
}
}
sym::cosf32 | sym::cosf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::cos, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Cos, ret_ty, [args[0].immediate()])
}
}
sym::powf32 | sym::powf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::pow,
ret_ty,
Expand All @@ -202,35 +202,35 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::expf32 | sym::expf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::exp, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Exp, ret_ty, [args[0].immediate()])
}
}
sym::exp2f32 | sym::exp2f64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::exp2, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Exp2, ret_ty, [args[0].immediate()])
}
}
sym::logf32 | sym::logf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::log, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Log, ret_ty, [args[0].immediate()])
}
}
sym::log2f32 | sym::log2f64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::log2, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Log2, ret_ty, [args[0].immediate()])
}
}
sym::log10f32 | sym::log10f64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::log10, ret_ty, [args[0].immediate()])
} else {
// spir-v glsl doesn't have log10, so,
Expand All @@ -241,7 +241,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::fmaf32 | sym::fmaf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::fma,
ret_ty,
Expand All @@ -264,14 +264,14 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::fabsf32 | sym::fabsf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::fabs, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::FAbs, ret_ty, [args[0].immediate()])
}
}
sym::minnumf32 | sym::minnumf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::fmin,
ret_ty,
Expand All @@ -286,7 +286,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::maxnumf32 | sym::maxnumf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::fmax,
ret_ty,
Expand All @@ -301,7 +301,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::copysignf32 | sym::copysignf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(
CLOp::copysign,
ret_ty,
Expand All @@ -314,36 +314,36 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::floorf32 | sym::floorf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::floor, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Floor, ret_ty, [args[0].immediate()])
}
}
sym::ceilf32 | sym::ceilf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::ceil, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Ceil, ret_ty, [args[0].immediate()])
}
}
sym::truncf32 | sym::truncf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::trunc, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Trunc, ret_ty, [args[0].immediate()])
}
}
// TODO: Correctness of all these rounds
sym::rintf32 | sym::rintf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::rint, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Round, ret_ty, [args[0].immediate()])
}
}
sym::nearbyintf32 | sym::nearbyintf64 | sym::roundf32 | sym::roundf64 => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::round, ret_ty, [args[0].immediate()])
} else {
self.gl_op(GLOp::Round, ret_ty, [args[0].immediate()])
Expand All @@ -359,7 +359,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {

// TODO: Do we want to manually implement these instead of using intel instructions?
sym::ctlz | sym::ctlz_nonzero => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::clz, ret_ty, [args[0].immediate()])
} else {
self.ext_inst
Expand All @@ -376,7 +376,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}
}
sym::cttz | sym::cttz_nonzero => {
if self.kernel_mode {
if self.target.is_kernel() {
self.cl_op(CLOp::ctz, ret_ty, [args[0].immediate()])
} else {
self.ext_inst
Expand Down
29 changes: 16 additions & 13 deletions crates/rustc_codegen_spirv/src/builder_spirv.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::builder;
use crate::codegen_cx::CodegenCx;
use crate::spirv_type::SpirvType;
use crate::target::SpirvTarget;
use bimap::BiHashMap;
use rspirv::dr::{Block, Builder, Module, Operand};
use rspirv::spirv::{AddressingModel, Capability, MemoryModel, Op, Word};
Expand Down Expand Up @@ -218,17 +219,14 @@ pub struct BuilderSpirv {
}

impl BuilderSpirv {
pub fn new(
version: Option<(u8, u8)>,
memory_model: Option<MemoryModel>,
kernel_mode: bool,
) -> Self {
pub fn new(target: &SpirvTarget) -> Self {
let version = target.spirv_version();
let memory_model = target.memory_model();

let mut builder = Builder::new();
// Default to spir-v 1.3
let version = version.unwrap_or((1, 3));
builder.set_version(version.0, version.1);
let memory_model = memory_model.unwrap_or(MemoryModel::Vulkan);
if kernel_mode {

if target.is_kernel() {
builder.capability(Capability::Kernel);
} else {
builder.capability(Capability::Shader);
Expand All @@ -243,18 +241,23 @@ impl BuilderSpirv {
builder.extension("SPV_KHR_variable_pointers");
}
}

// The linker will always be ran on this module
builder.capability(Capability::Linkage);
builder.capability(Capability::Int8);
builder.capability(Capability::Int16);
builder.capability(Capability::Int64);
builder.capability(Capability::Float64);
if kernel_mode {

let addressing_model = if target.is_kernel() {
builder.capability(Capability::Addresses);
builder.memory_model(AddressingModel::Physical32, MemoryModel::OpenCL);
AddressingModel::Physical32
} else {
builder.memory_model(AddressingModel::Logical, memory_model);
}
AddressingModel::Logical
};

builder.memory_model(addressing_model, memory_model);

Self {
builder: RefCell::new(builder),
constants: Default::default(),
Expand Down
4 changes: 2 additions & 2 deletions crates/rustc_codegen_spirv/src/codegen_cx/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl<'tcx> CodegenCx<'tcx> {
}

pub fn constant_i32(&self, span: Span, val: i32) -> SpirvValue {
let ty = SpirvType::Integer(32, !self.kernel_mode).def(span, self);
let ty = SpirvType::Integer(32, self.target.is_kernel()).def(span, self);
self.builder.def_constant(SpirvConst::U32(ty, val as u32))
}

Expand Down Expand Up @@ -213,7 +213,7 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> {
Primitive::Int(int_size, int_signedness) => match self.lookup_type(ty) {
SpirvType::Integer(width, spirv_signedness) => {
assert_eq!(width as u64, int_size.size().bits());
if !self.kernel_mode {
if !self.target.is_kernel() {
assert_eq!(spirv_signedness, int_signedness);
}
self.constant_int(ty, data as u64)
Expand Down
41 changes: 11 additions & 30 deletions crates/rustc_codegen_spirv/src/codegen_cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ use crate::decorations::{
};
use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache};
use crate::symbols::Symbols;
use crate::target::SpirvTarget;

use rspirv::dr::{Module, Operand};
use rspirv::spirv::{AddressingModel, Decoration, LinkageType, MemoryModel, StorageClass, Word};
use rspirv::spirv::{AddressingModel, Decoration, LinkageType, StorageClass, Word};
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{
AsmMethods, BackendTypes, CoverageInfoMethods, DebugInfoMethods, MiscMethods,
Expand Down Expand Up @@ -55,7 +57,6 @@ pub struct CodegenCx<'tcx> {
/// get `LoopControl::UNROLL` applied to all of their loops' `OpLoopMerge`
/// instructions, during structuralization.
unroll_loops_decorations: RefCell<FxHashMap<Word, UnrollLoopsDecoration>>,
pub kernel_mode: bool,
/// Cache of all the builtin symbols we need
pub sym: Rc<Symbols>,
pub instruction_table: InstructionTable,
Expand All @@ -72,52 +73,32 @@ pub struct CodegenCx<'tcx> {
pub i8_i16_atomics_allowed: bool,

pub codegen_args: CodegenArgs,

/// Information about the SPIR-V target.
pub target: SpirvTarget,
}

impl<'tcx> CodegenCx<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>) -> Self {
let sym = Symbols::get();
let mut spirv_version = None;
let mut memory_model = None;
let mut kernel_mode = false;
for &feature in &tcx.sess.target_features {
if feature == sym.kernel {
kernel_mode = true;
} else if feature == sym.spirv10 {
spirv_version = Some((1, 0));
} else if feature == sym.spirv11 {
spirv_version = Some((1, 1));
} else if feature == sym.spirv12 {
spirv_version = Some((1, 2));
} else if feature == sym.spirv13 {
spirv_version = Some((1, 3));
} else if feature == sym.spirv14 {
spirv_version = Some((1, 4));
} else if feature == sym.spirv15 {
spirv_version = Some((1, 5));
} else if feature == sym.simple {
memory_model = Some(MemoryModel::Simple);
} else if feature == sym.vulkan {
memory_model = Some(MemoryModel::Vulkan);
} else if feature == sym.glsl450 {
memory_model = Some(MemoryModel::GLSL450);
} else {
tcx.sess.err(&format!("Unknown feature {}", feature));
}
tcx.sess.err(&format!("Unknown feature {}", feature));
}
let codegen_args = CodegenArgs::from_session(tcx.sess);
let target = tcx.sess.target.llvm_target.parse().unwrap();

Self {
tcx,
codegen_unit,
builder: BuilderSpirv::new(spirv_version, memory_model, kernel_mode),
builder: BuilderSpirv::new(&target),
instances: Default::default(),
function_parameter_values: Default::default(),
type_cache: Default::default(),
vtables: Default::default(),
ext_inst: Default::default(),
zombie_decorations: Default::default(),
unroll_loops_decorations: Default::default(),
kernel_mode,
target,
sym,
instruction_table: InstructionTable::new(),
zombie_undefs_for_system_fn_addrs: Default::default(),
Expand Down
Loading

0 comments on commit 45e9561

Please sign in to comment.