diff --git a/rustc_codegen_spirv/build_libcore_test.sh b/rustc_codegen_spirv/build_libcore_test.sh index 51d3acd1d6..693c5766d6 100755 --- a/rustc_codegen_spirv/build_libcore_test.sh +++ b/rustc_codegen_spirv/build_libcore_test.sh @@ -12,5 +12,5 @@ pushd build_libcore_test # Use wasm32 because it's a relatively simple platform - if the x86 libcore is used, there's all sorts of "feature sse2 # not found" and the like, and our spirv backend is never reached. With wasm32, it at least gets reached. # (We probably want to add our own target eventually) -xargo build --target wasm32-unknown-unknown -Ccodegen-units=1 +xargo build --target wasm32-unknown-unknown popd diff --git a/rustc_codegen_spirv/build_libcore_test/.gitignore b/rustc_codegen_spirv/build_libcore_test/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/rustc_codegen_spirv/build_libcore_test/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/rustc_codegen_spirv/build_libcore_test/src/lib.rs b/rustc_codegen_spirv/build_libcore_test/src/lib.rs new file mode 100644 index 0000000000..8113da277b --- /dev/null +++ b/rustc_codegen_spirv/build_libcore_test/src/lib.rs @@ -0,0 +1,10 @@ +#![no_std] + +use core::panic::PanicInfo; + +pub fn screaming_bananans() {} + +#[panic_handler] +fn panic(_: &PanicInfo) -> ! { + loop {} +} diff --git a/rustc_codegen_spirv/build_libcore_test/src/main.rs b/rustc_codegen_spirv/build_libcore_test/src/main.rs deleted file mode 100644 index f328e4d9d0..0000000000 --- a/rustc_codegen_spirv/build_libcore_test/src/main.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() {} diff --git a/rustc_codegen_spirv/src/builder/ext_inst.rs b/rustc_codegen_spirv/src/builder/ext_inst.rs new file mode 100644 index 0000000000..17638c39cc --- /dev/null +++ b/rustc_codegen_spirv/src/builder/ext_inst.rs @@ -0,0 +1,42 @@ +use super::Builder; +use crate::builder_spirv::{SpirvValue, SpirvValueExt}; +use rspirv::dr::Operand; +use rspirv::spirv::{GLOp, Word}; + +const GLSL_STD_450: &str = "GLSL.std.450"; + +/// Manager for OpExtInst/OpExtImport instructions +#[derive(Default)] +pub struct ExtInst { + glsl: Option, +} + +impl ExtInst { + pub fn import_glsl<'a, 'tcx>(&mut self, bx: &Builder<'a, 'tcx>) -> Word { + match self.glsl { + Some(id) => id, + None => { + let id = bx.emit_global().ext_inst_import(GLSL_STD_450); + self.glsl = Some(id); + id + } + } + } +} + +impl<'a, 'tcx> Builder<'a, 'tcx> { + pub fn gl_op(&mut self, op: GLOp, args: impl AsRef<[SpirvValue]>) -> SpirvValue { + let args = args.as_ref(); + let glsl = self.ext_inst.borrow_mut().import_glsl(self); + self.emit() + .ext_inst( + args[0].ty, + None, + glsl, + op as u32, + args.iter().map(|a| Operand::IdRef(a.def)), + ) + .unwrap() + .with_type(args[0].ty) + } +} diff --git a/rustc_codegen_spirv/src/builder/intrinsics.rs b/rustc_codegen_spirv/src/builder/intrinsics.rs index 3eabf239c3..59c42fde87 100644 --- a/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -3,6 +3,7 @@ use crate::abi::ConvSpirvType; use crate::builder_spirv::SpirvValueExt; use crate::codegen_cx::CodegenCx; use crate::spirv_type::SpirvType; +use rspirv::spirv::GLOp; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::glue; @@ -455,6 +456,45 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { } } + // TODO: Configure these to be ocl vs. gl ext instructions, etc. + sym::sqrtf32 | sym::sqrtf64 => self.gl_op(GLOp::Sqrt, [args[0].immediate()]), + sym::powif32 | sym::powif64 => { + let float = self.sitofp(args[1].immediate(), args[0].immediate().ty); + self.gl_op(GLOp::Pow, [args[0].immediate(), float]) + } + sym::sinf32 | sym::sinf64 => self.gl_op(GLOp::Sin, [args[0].immediate()]), + sym::cosf32 | sym::cosf64 => self.gl_op(GLOp::Cos, [args[0].immediate()]), + sym::powf32 | sym::powf64 => { + self.gl_op(GLOp::Pow, [args[0].immediate(), args[1].immediate()]) + } + sym::expf32 | sym::expf64 => self.gl_op(GLOp::Exp, [args[0].immediate()]), + sym::exp2f32 | sym::exp2f64 => self.gl_op(GLOp::Exp2, [args[0].immediate()]), + sym::logf32 | sym::logf64 => self.gl_op(GLOp::Log, [args[0].immediate()]), + sym::log2f32 | sym::log2f64 => self.gl_op(GLOp::Log2, [args[0].immediate()]), + sym::log10f32 | sym::log10f64 => { + // spir-v doesn't have log10, so, + // log10(x) == (1 / ln(10)) * ln(x) + let mul = self.constant_float(args[0].immediate().ty, 1.0 / 10.0f64.ln()); + let ln = self.gl_op(GLOp::Log, [args[0].immediate()]); + self.mul(mul, ln) + } + sym::fmaf32 | sym::fmaf64 => self.gl_op(GLOp::Fma, [args[0].immediate()]), + sym::fabsf32 | sym::fabsf64 => self.gl_op(GLOp::FAbs, [args[0].immediate()]), + sym::minnumf32 | sym::minnumf64 => self.gl_op(GLOp::FMin, [args[0].immediate()]), + sym::maxnumf32 | sym::maxnumf64 => self.gl_op(GLOp::FMax, [args[0].immediate()]), + // sym::copysignf32 => "llvm.copysign.f32", + // sym::copysignf64 => "llvm.copysign.f64", + sym::floorf32 | sym::floorf64 => self.gl_op(GLOp::Floor, [args[0].immediate()]), + sym::ceilf32 | sym::ceilf64 => self.gl_op(GLOp::Ceil, [args[0].immediate()]), + sym::truncf32 | sym::truncf64 => self.gl_op(GLOp::Trunc, [args[0].immediate()]), + // TODO: Correctness of round + sym::rintf32 + | sym::rintf64 + | sym::nearbyintf32 + | sym::nearbyintf64 + | sym::roundf32 + | sym::roundf64 => self.gl_op(GLOp::Round, [args[1].immediate()]), + sym::float_to_int_unchecked => { if float_type_width(arg_tys[0]).is_none() { span_invalid_monomorphization_error( diff --git a/rustc_codegen_spirv/src/builder/mod.rs b/rustc_codegen_spirv/src/builder/mod.rs index e227e16028..0cc31d7744 100644 --- a/rustc_codegen_spirv/src/builder/mod.rs +++ b/rustc_codegen_spirv/src/builder/mod.rs @@ -1,6 +1,9 @@ mod builder_methods; +mod ext_inst; mod intrinsics; +pub use ext_inst::ExtInst; + use crate::abi::ConvSpirvType; use crate::builder_spirv::{BuilderCursor, SpirvValue, SpirvValueExt}; use crate::codegen_cx::CodegenCx; diff --git a/rustc_codegen_spirv/src/codegen_cx.rs b/rustc_codegen_spirv/src/codegen_cx.rs index 085fc9c88a..3307a29323 100644 --- a/rustc_codegen_spirv/src/codegen_cx.rs +++ b/rustc_codegen_spirv/src/codegen_cx.rs @@ -1,4 +1,5 @@ use crate::abi::ConvSpirvType; +use crate::builder::ExtInst; use crate::builder_spirv::{BuilderCursor, BuilderSpirv, SpirvValue, SpirvValueExt}; use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache}; use rspirv::dr::{Module, Operand}; @@ -63,6 +64,7 @@ pub struct CodegenCx<'tcx> { pub type_cache: TypeCache<'tcx>, /// Cache generated vtables pub vtables: RefCell, Option>), SpirvValue>>, + pub ext_inst: RefCell, } impl<'tcx> CodegenCx<'tcx> { @@ -76,6 +78,7 @@ impl<'tcx> CodegenCx<'tcx> { function_parameter_values: RefCell::new(HashMap::new()), type_cache: Default::default(), vtables: RefCell::new(Default::default()), + ext_inst: Default::default(), } } @@ -184,6 +187,14 @@ impl<'tcx> CodegenCx<'tcx> { self.builder.constant_f64(ty, val).with_type(ty) } + pub fn constant_float(&self, ty: Word, val: f64) -> SpirvValue { + match self.lookup_type(ty) { + SpirvType::Float(32) => self.builder.constant_f32(ty, val as f32).with_type(ty), + SpirvType::Float(64) => self.builder.constant_f64(ty, val).with_type(ty), + other => panic!("constant_float invalid on type {}", other.debug(ty, self)), + } + } + #[allow(dead_code)] pub fn set_linkage_export(&self, target: Word, name: String) { self.emit_global().decorate(