Refactor validation tests to use compiletest (#464)

* Refactor validation tests to use compiletest

* Update tests/ui/lang/core/ptr/allocate_const_scalar.rs
This commit is contained in:
XAMPPRocky 2021-03-18 18:16:21 +01:00 committed by GitHub
parent 144a447f30
commit 27eb1d1413
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 1313 additions and 1545 deletions

View File

@ -2,3 +2,6 @@
# Currently there's an issue where the Example CPU runner fails without # Currently there's an issue where the Example CPU runner fails without
# `-C prefer-dynamic`. # `-C prefer-dynamic`.
rustflags = "-C prefer-dynamic" rustflags = "-C prefer-dynamic"
[alias]
compiletest = "run --release --manifest-path=tests/Cargo.toml"

1
.gitattributes vendored
View File

@ -1,2 +1,3 @@
# configure GitHub linguist (language bar) https://github.com/github/linguist#overrides # configure GitHub linguist (language bar) https://github.com/github/linguist#overrides
docs/* linguist-documentation docs/* linguist-documentation
* text=auto eol=lf

View File

@ -51,3 +51,5 @@ cargo_test examples/runners/wgpu
cargo_test_no_features examples/runners/cpu cargo_test_no_features examples/runners/cpu
cargo_test_no_features examples/shaders/sky-shader cargo_test_no_features examples/shaders/sky-shader
cargo_test_no_features examples/shaders/simplest-shader cargo_test_no_features examples/shaders/simplest-shader
cargo compiletest

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
target/ target/
.vscode/ .vscode/
tests/Cargo.lock

146
Cargo.lock generated
View File

@ -54,6 +54,12 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "anyhow"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.5.2" version = "0.5.2"
@ -324,6 +330,35 @@ dependencies = [
"objc", "objc",
] ]
[[package]]
name = "compiletest_rs"
version = "0.6.0"
source = "git+https://github.com/Manishearth/compiletest-rs.git?rev=1f4a4c4#1f4a4c40e06ba36fef63909ddfaa76edcb2ac620"
dependencies = [
"diff",
"filetime",
"getopts",
"lazy_static",
"libc",
"log",
"miow 0.3.6",
"regex",
"rustfix",
"serde",
"serde_derive",
"serde_json",
"tester",
"winapi 0.3.9",
]
[[package]]
name = "compiletests"
version = "0.0.0"
dependencies = [
"compiletest_rs",
"rustc_codegen_spirv",
]
[[package]] [[package]]
name = "compute-shader" name = "compute-shader"
version = "0.4.0-alpha.0" version = "0.4.0-alpha.0"
@ -572,12 +607,39 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]] [[package]]
name = "difference" name = "difference"
version = "2.0.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if 1.0.0",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "dispatch" name = "dispatch"
version = "0.2.0" version = "0.2.0"
@ -844,6 +906,15 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.2" version = "0.2.2"
@ -1295,7 +1366,7 @@ dependencies = [
"kernel32-sys", "kernel32-sys",
"libc", "libc",
"log", "log",
"miow", "miow 0.2.2",
"net2", "net2",
"slab", "slab",
"winapi 0.2.8", "winapi 0.2.8",
@ -1325,6 +1396,16 @@ dependencies = [
"ws2_32-sys", "ws2_32-sys",
] ]
[[package]]
name = "miow"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
"socket2",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "mouse-shader" name = "mouse-shader"
version = "0.1.0" version = "0.1.0"
@ -1834,6 +1915,16 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall 0.2.5",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.4.5" version = "1.4.5"
@ -1912,6 +2003,18 @@ dependencies = [
"topological-sort", "topological-sort",
] ]
[[package]]
name = "rustfix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e"
dependencies = [
"anyhow",
"log",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "rusttype" name = "rusttype"
version = "0.9.2" version = "0.9.2"
@ -1922,6 +2025,12 @@ dependencies = [
"owned_ttf_parser", "owned_ttf_parser",
] ]
[[package]]
name = "rustversion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@ -2081,6 +2190,17 @@ dependencies = [
"wayland-protocols 0.28.5", "wayland-protocols 0.28.5",
] ]
[[package]]
name = "socket2"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
"cfg-if 1.0.0",
"libc",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "spirv-builder" name = "spirv-builder"
version = "0.4.0-alpha.0" version = "0.4.0-alpha.0"
@ -2269,6 +2389,17 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.2"
@ -2278,6 +2409,19 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "tester"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb"
dependencies = [
"cfg-if 1.0.0",
"getopts",
"libc",
"num_cpus",
"term",
]
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.11.0"

View File

@ -1,4 +1,5 @@
[workspace] [workspace]
exclude = ["target/"]
members = [ members = [
"examples/runners/cpu", "examples/runners/cpu",
"examples/runners/ash", "examples/runners/ash",
@ -11,6 +12,8 @@ members = [
"crates/rustc_codegen_spirv", "crates/rustc_codegen_spirv",
"crates/spirv-builder", "crates/spirv-builder",
"crates/spirv-std", "crates/spirv-std",
"tests",
] ]
# Compile build-dependencies in release mode with # Compile build-dependencies in release mode with
@ -23,3 +26,6 @@ codegen-units = 16
spirv-std = { path = "./crates/spirv-std" } spirv-std = { path = "./crates/spirv-std" }
spirv-std-macros = { path = "./crates/spirv-std-macros" } spirv-std-macros = { path = "./crates/spirv-std-macros" }
glam = { git = "https://github.com/bitshifter/glam-rs.git", rev ="b3e94fb" } glam = { git = "https://github.com/bitshifter/glam-rs.git", rev ="b3e94fb" }
# TODO: Needed for handling SPIR-V extension across platforms. Remove once
# next version is released.
compiletest_rs= { git = "https://github.com/Manishearth/compiletest-rs.git", rev = "1f4a4c4" }

View File

@ -1,304 +0,0 @@
use super::val;
#[test]
fn any() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let vector = glam::BVec2::new(true, false);
assert!(arch::any(vector));
}
"#);
}
#[test]
fn all() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let vector = glam::BVec2::new(true, true);
assert!(spirv_std::arch::all(vector));
}
"#);
}
#[test]
fn s_negate() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let operand: i32 = -5;
let vector = glam::IVec2::new(-5, -0);
assert!(arch::s_negate_vector(vector) == glam::IVec2::new(5, 0));
}
"#);
}
#[test]
fn f_negate() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let operand: f32 = -5.0;
let vector = glam::Vec2::new(-5.0, -0.0);
assert!(arch::f_negate_vector(vector) == glam::Vec2::new(5.0, 0.0));
}
"#);
}
#[test]
fn i_add() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 2;
let vx = glam::IVec2::new(2, 5);
let vy = glam::IVec2::new(5, 2);
assert!(arch::i_add_vector(vx, vy) == glam::IVec2::new(7, 7));
}
"#);
}
#[test]
fn f_add() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 2.0;
let vx = glam::Vec2::new(2.0, 5.0);
let vy = glam::Vec2::new(5.0, 2.0);
assert!(arch::f_add_vector(vx, vy) == glam::Vec2::new(7.0, 7.0));
}
"#);
}
#[test]
fn i_sub() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 5;
let vx = glam::IVec2::new(5, 7);
let vy = glam::IVec2::new(5, 7);
assert!(arch::i_sub_vector(vx, vy) == glam::IVec2::new(0, 0));
}
"#);
}
#[test]
fn f_sub() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 5.0;
let vx = glam::Vec2::new(5.0, 7.0);
let vy = glam::Vec2::new(5.0, 7.0);
assert!(arch::f_sub_vector(vx, vy) == glam::Vec2::new(0.0, 0.0));
}
"#);
}
#[test]
fn i_mul() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 2;
let vx = glam::IVec2::new(5, 2);
let vy = glam::IVec2::new(2, 5);
assert!(arch::i_mul_vector(vx, vy) == glam::IVec2::new(10, 10));
}
"#);
}
#[test]
fn f_mul() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 2.0;
let vx = glam::Vec2::new(5.0, 2.0);
let vy = glam::Vec2::new(2.0, 5.0);
assert!(arch::f_mul_vector(vx, vy) == glam::Vec2::new(10.0, 10.0));
}
"#);
}
#[test]
fn s_div() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 10;
let y = 2;
let vx = glam::IVec2::new(10, 10);
let vy = glam::IVec2::new(2, 2);
assert!(arch::s_div_vector(vx, vy) == glam::IVec2::new(5, 5));
}
"#);
}
#[test]
fn u_div() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x: u32 = 10;
let y = 2;
let vx = glam::UVec2::new(10, 10);
let vy = glam::UVec2::new(2, 2);
assert!(arch::u_div_vector(vx, vy) == glam::UVec2::new(5, 5));
}
"#);
}
#[test]
fn f_div() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 10.0;
let y = 2.0;
let vx = glam::Vec2::new(10.0, 10.0);
let vy = glam::Vec2::new(2.0, 2.0);
assert!(arch::f_div_vector(vx, vy) == glam::Vec2::new(5.0, 5.0));
}
"#);
}
#[test]
fn u_mod() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x: u32 = 10;
let y = 2;
let vx = glam::UVec2::new(10, 10);
let vy = glam::UVec2::new(2, 2);
assert!(arch::u_mod_vector(vx, vy) == glam::UVec2::new(0, 0));
}
"#);
}
#[test]
fn s_mod() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 10;
let y = 2;
let vx = glam::IVec2::new(10, 10);
let vy = glam::IVec2::new(2, 2);
assert!(arch::s_mod_vector(vx, vy) == glam::IVec2::new(0, 0));
}
"#);
}
#[test]
fn s_rem() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = -10;
let y = -2;
let vx = glam::IVec2::new(-10, -10);
let vy = glam::IVec2::new(-2, -2);
assert!(arch::s_rem_vector(vx, vy) == glam::IVec2::new(-0, -0));
}
"#);
}
#[test]
fn f_mod() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = 10.0;
let y = 2.0;
let vx = glam::Vec2::new(10.0, 10.0);
let vy = glam::Vec2::new(2.0, 2.0);
assert!(arch::f_mod_vector(vx, vy) == glam::Vec2::new(0.0, 0.0));
}
"#);
}
#[test]
fn f_rem() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let x = -10.0;
let y = -2.0;
let vx = glam::Vec2::new(-10.0, -10.0);
let vy = glam::Vec2::new(-2.0, -2.0);
assert!(arch::f_mod_vector(vx, vy) == glam::Vec2::new(-0.0, -0.0));
}
"#);
}
#[test]
fn vector_times_scalar() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(10.0, 10.0);
let scalar = 2.0;
assert!(arch::vector_times_scalar(vector, scalar) == glam::Vec2::new(20.0, 20.0));
}
"#);
}
#[test]
fn vector_extract_dynamic() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let element = unsafe { spirv_std::arch::vector_extract_dynamic(vector, 1) };
assert!(2.0 == element);
}
"#);
}
#[test]
fn vector_insert_dynamic() {
val(r#"
#[allow(unused_attributes)]
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let expected = glam::Vec2::new(1.0, 3.0);
let new_vector = unsafe { spirv_std::arch::vector_insert_dynamic(vector, 1, 3.0) };
assert!(new_vector == expected);
}
"#);
}

View File

@ -19,15 +19,6 @@ impl<'a> Drop for SetEnvVar<'a> {
} }
} }
#[test]
fn hello_world() {
val(r#"
#[spirv(fragment)]
pub fn main() {
}
"#);
}
#[test] #[test]
fn custom_entry_point() { fn custom_entry_point() {
dis_globals( dis_globals(
@ -209,95 +200,6 @@ OpDecorate %4 Binding 0
); );
} }
#[test]
fn asm_const_arg() {
val(r#"
fn asm() {
unsafe {
const N: usize = 3;
asm!(
"%int = OpTypeInt 32 0",
"%type = OpTypeVector %int {len}",
len = const N,
);
}
}
#[spirv(fragment)]
pub fn main() {
asm();
}
"#);
}
#[test]
fn logical_and() {
val(r#"
fn f(x: bool, y: bool) -> bool {
x && y
}
#[spirv(fragment)]
pub fn main() {
f(false, true);
}"#);
}
#[test]
fn panic() {
val(r#"
#[spirv(fragment)]
pub fn main() {
panic!("aaa");
}
"#);
}
#[test]
fn panic_builtin() {
val(r#"
fn int_div(x: usize) -> usize {
1 / x
}
#[spirv(fragment)]
pub fn main() {
int_div(0);
}
"#);
}
#[test]
fn panic_builtin_bounds_check() {
val(r#"
fn array_bounds_check(x: [u32; 4], i: usize) -> u32 {
x[i]
}
#[spirv(fragment)]
pub fn main() {
array_bounds_check([0, 1, 2, 3], 5);
}
"#);
}
// NOTE(eddyb) this won't pass Vulkan validation (see `push_constant_vulkan`),
// but should still pass the basline SPIR-V validation.
#[test]
fn push_constant() {
val(r#"
#[derive(Copy, Clone)]
pub struct ShaderConstants {
pub width: u32,
pub height: u32,
pub time: f32,
}
#[spirv(fragment)]
pub fn main(constants: PushConstant<ShaderConstants>) {
let _constants = *constants;
}
"#);
}
// NOTE(eddyb) we specifically run Vulkan validation here, as the default // NOTE(eddyb) we specifically run Vulkan validation here, as the default
// validation rules are more lax and don't require a `Block` decoration // validation rules are more lax and don't require a `Block` decoration
// (`#[spirv(block)]` here) on `struct ShaderConstants`. // (`#[spirv(block)]` here) on `struct ShaderConstants`.
@ -321,15 +223,6 @@ pub fn main(constants: PushConstant<ShaderConstants>) {
); );
} }
#[test]
fn infinite_loop() {
val(r#"
#[spirv(fragment)]
pub fn main() {
loop {}
}"#);
}
#[test] #[test]
fn unroll_loops() { fn unroll_loops() {
dis_fn( dis_fn(
@ -390,115 +283,6 @@ OpFunctionEnd"#,
); );
} }
#[test]
fn signum() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<f32>, mut o: Output<f32>) {
*o = i.signum();
}"#);
}
#[test]
// Doesn't work, only worked before because I think it got optimized away before hitting the
// backend.
#[ignore]
fn allocate_const_scalar_pointer() {
val(r#"
use core::ptr::Unique;
const POINTER: Unique<[u8;4]> = Unique::<[u8; 4]>::dangling();
#[spirv(fragment)]
pub fn main() {
let _pointer = POINTER;
}"#);
}
#[test]
fn allocate_vec_like_pointer() {
val(r#"
use core::ptr::Unique;
const VEC_LIKE: (Unique<usize>, usize, usize) = (Unique::<usize>::dangling(), 0, 0);
pub fn assign_vec_like() {
let _vec_like = VEC_LIKE;
}
#[spirv(fragment)]
pub fn main() {}"#);
}
#[test]
fn allocate_null_pointer() {
val(r#"
use core::ptr::null;
const NULL_PTR: *const i32 = null();
#[spirv(fragment)]
pub fn main() {
let _null_ptr = NULL_PTR;
}"#);
}
#[test]
fn create_uninitialized_memory() {
val(r#"
use core::mem::MaybeUninit;
const MAYBEI32: MaybeUninit<&i32> = MaybeUninit::<&i32>::uninit();
pub fn create_uninit_and_write() {
let mut maybei32 = MAYBEI32;
unsafe { maybei32.as_mut_ptr().write(&0); }
let _maybei32 = unsafe { maybei32.assume_init() };
}
#[spirv(fragment)]
pub fn main() {}"#);
}
#[test]
fn vector_extract_dynamic() {
val(r#"
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let element = unsafe { spirv_std::arch::vector_extract_dynamic(vector, 1) };
assert!(2.0 == element);
let uvector = glam::UVec2::new(1, 2);
let element: u32 = unsafe { spirv_std::arch::vector_extract_dynamic(uvector, 1) };
assert!(2 == element);
}
"#);
}
#[test]
fn vector_insert_dynamic() {
val(r#"
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let expected = glam::Vec2::new(1.0, 3.0);
let new_vector = unsafe { spirv_std::arch::vector_insert_dynamic(vector, 1, 3.0) };
assert!(new_vector == expected);
let uvector = glam::UVec2::new(1, 2);
let uexpected = glam::UVec2::new(1, 3);
let new_vector = unsafe { spirv_std::arch::vector_insert_dynamic(uvector, 1, 3) };
assert!(new_vector == uexpected);
}
"#);
}
#[test]
fn mat3_vec3_multiply() {
val(r#"
#[spirv(fragment)]
pub fn main(input: Input<glam::Mat3>, mut output: Output<glam::Vec3>) {
let input = *input;
let vector = input * glam::Vec3::new(1.0, 2.0, 3.0);
*output = vector;
}
"#);
}
#[test] #[test]
fn complex_image_sample_inst() { fn complex_image_sample_inst() {
dis_fn( dis_fn(
@ -570,41 +354,6 @@ OpFunctionEnd",
); );
} }
#[test]
fn image_read() {
val(r#"
#[spirv(fragment)]
pub fn main(image: UniformConstant<StorageImage2d>, mut output: Output<glam::Vec2>) {
let coords = image.read(glam::IVec2::new(0, 1));
*output = coords;
}
"#);
}
#[test]
fn image_write() {
val(r#"
#[spirv(fragment)]
pub fn main(input: Input<glam::Vec2>, image: UniformConstant<StorageImage2d>) {
let texels = *input;
unsafe {
image.write(glam::UVec2::new(0, 1), texels);
}
}
"#);
}
#[test]
fn image_fetch() {
val(r#"
#[spirv(fragment)]
pub fn main(image: UniformConstant<Image2d>, mut output: Output<glam::Vec4>) {
let texel = image.fetch(glam::IVec2::new(0, 1));
*output = texel;
}
"#);
}
/// Helper to generate all of the `ptr_*` tests below, which test that the various /// Helper to generate all of the `ptr_*` tests below, which test that the various
/// ways to use raw pointer `read`/`write`/`copy`, to copy a single value, work, /// ways to use raw pointer `read`/`write`/`copy`, to copy a single value, work,
/// and that the resulting SPIR-V uses either a pair of `OpLoad` and `OpStore`, /// and that the resulting SPIR-V uses either a pair of `OpLoad` and `OpStore`,

View File

@ -1,423 +0,0 @@
use super::val;
#[test]
fn cf_while() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
}
}
"#);
}
#[test]
fn cf_while_while() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
}
}
}
"#);
}
#[test]
fn cf_while_while_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
break;
}
}
}
"#);
}
#[test]
fn cf_while_while_if_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
if *i > 10 {
break;
}
}
}
}
"#);
}
#[test]
fn cf_while_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
break;
}
}
"#);
}
#[test]
fn cf_while_if_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
}
}
}
"#);
}
#[test]
fn cf_while_if_break_else_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
} else {
break;
}
}
}
"#);
}
#[test]
fn cf_while_if_break_if_break() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
}
if *i == 1 {
break;
}
}
}
"#);
}
#[test]
fn cf_while_while_continue() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
continue;
}
}
}
"#);
}
#[test]
fn cf_while_while_if_continue() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
if *i > 5 {
continue;
}
}
}
}
"#);
}
#[test]
fn cf_while_continue() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
continue;
}
}
"#);
}
#[test]
fn cf_while_if_continue() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
continue;
}
}
}
"#);
}
#[test]
fn cf_while_if_continue_else_continue() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
continue;
} else {
continue;
}
}
}
"#);
}
#[test]
fn cf_while_return() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
return;
}
}
"#);
}
#[test]
fn cf_if_return_else() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i < 10 {
return;
} else {
}
}
"#);
}
#[test]
fn cf_if_return_else_return() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i < 10 {
return;
} else {
return;
}
}
"#);
}
#[test]
fn cf_if_while() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i == 0 {
while *i < 10 {
}
}
}
"#);
}
#[test]
fn cf_if() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
}
}
"#);
}
#[test]
fn cf_ifx2() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
}
if *i > 1 {
}
}
"#);
}
#[test]
fn cf_if_else() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
} else {
}
}
"#);
}
#[test]
fn cf_if_elseif_else() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
} else if *i < 0 {
} else {
}
}
"#);
}
#[test]
fn cf_if_if() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
if *i < 10 {
}
}
}
"#);
}
#[test]
fn cf_defer() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 32 {
let current_position = 0;
if *i < current_position {
break;
}
if *i < current_position {
break;
}
}
}
"#);
}
#[test]
fn issue_283() {
// version of issue 283 with loop uncommented and warnings fixed
// https://github.com/EmbarkStudios/rust-gpu/issues/283
val(r#"
use glam::*;
fn sphere_sdf(p: Vec3) -> f32 {
p.length() - 1.0
}
// Global scene to render
fn scene_sdf(p: Vec3) -> f32 {
sphere_sdf(p)
}
fn render(eye: Vec3, dir: Vec3, start: f32, end: f32) -> f32 {
let max_marching_steps: i32 = 255;
let epsilon: f32 = 0.0001;
let mut depth = start;
let mut i = 0;
loop {
if i < max_marching_steps {
break;
}
let dist = scene_sdf(eye + depth * dir);
if dist < epsilon {
return depth;
}
depth += dist;
if depth >= end {
return end;
}
i += 1;
}
end
}
#[spirv(fragment)]
pub fn main() {
let v = Vec3::new(1.0, 1.0, 1.0);
render(v, v, 1.0, 2.0);
}"#);
}
// NOTE(eddyb) this tests `for` loop desugaring (with its call to `Iterator::next`
// and matching on the resulting `Option`), without relying on a `Range` iterator.
// More precisely, `Range` used to not compile, due to it using `mem::replace`,
// which, before https://github.com/rust-lang/rust/pull/83022, used to just call
// `mem::swap` (which has a block-wise optimization that can't work on SPIR-V).
#[test]
fn cf_for_with_custom_range_iter() {
val(r#"
use num_traits::Num;
use core::ops::Range;
struct RangeIter<T>(Range<T>);
impl<T: Num + Ord + Copy> Iterator for RangeIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let x = self.0.start;
if x >= self.0.end {
None
} else {
self.0.start = x + T::one();
Some(x)
}
}
}
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
for _ in RangeIter(0..*i) {
}
}
"#);
}
#[test]
fn cf_for_range() {
val(r#"
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
for _ in 0..*i {
}
}
"#);
}

View File

@ -1,5 +1,4 @@
mod basic; mod basic;
mod control_flow;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rustc_codegen_spirv::rspirv; use rustc_codegen_spirv::rspirv;

View File

@ -1,8 +1,9 @@
# Summary # Summary
- [Introduction](./introduction.md) - [Introduction](./introduction.md)
- [Contributing]() - [Contributing to Rust-GPU]()
- [Building Rust-GPU](./building-rust-gpu.md) - [Building](./building-rust-gpu.md)
- [Testing](./testing.md)
- [Minimizing bugs in SPIR-V](./spirv-minimization.md) - [Minimizing bugs in SPIR-V](./spirv-minimization.md)
- [Platform Support](./platform-support.md) - [Platform Support](./platform-support.md)
- [Writing Shader Crates](./writing-shader-crates.md) - [Writing Shader Crates](./writing-shader-crates.md)

39
docs/src/testing.md Normal file
View File

@ -0,0 +1,39 @@
# Testing Rust-GPU
Rust-GPU has a couple of different kinds of tests, most can be ran through
`cargo test`, however Rust-GPU also has end-to-end tests for compiling Rust and
validating its SPIR-V output, which can ran by running `cargo compiletest`.
```bash
cargo test && cargo compiletest
```
## Adding Tests
Rust-GPU's end-to-end test's use an external version of the [`compiletest`] tool
as a testing framework. Be sure to check out the [repository][`compiletest`] and
the [rustc Dev-Guide][rustc-dev-guide] for more information about how it works,
how to configure it, and add new tests.
### Blessing Tests
You will occassionally need to "bless" the output from UI tests to update the
normalised output, you can do this by passing a `--bless` flag to
`cargo compiletest`.
``
cargo compiletest -- --bless
``
### Caching Tests
`cargo compiletest` by default caches the build output for dependencies of test
cases such as `spirv-std` and `glam`. If you need to compile from a fresh source
you can pass the `--clean` flag to build from scratch.
``
cargo compiletest -- --clean
``
[`compiletest`]: https://github.com/laumann/compiletest-rs
[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/tests/intro.html

563
tests/Cargo.lock generated
View File

@ -1,563 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bimap"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92b72b8f03128773278bf74418b9205f3d2a12c39a61f92395f47af390c32bf"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "compiletest-suite"
version = "0.0.0"
dependencies = [
"compiletest_rs",
"rustc_codegen_spirv",
]
[[package]]
name = "compiletest_rs"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb"
dependencies = [
"diff",
"filetime",
"getopts",
"lazy_static",
"libc",
"log",
"miow",
"regex",
"rustfix",
"serde",
"serde_derive",
"serde_json",
"tester",
"winapi",
]
[[package]]
name = "derive_more"
version = "0.99.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "filetime"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "jobserver"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "miow"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
dependencies = [
"socket2",
"winapi",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea78b9742c52ac729753c1590e9adc5248ea9bdaf974597efd46c74cfaa5fb54"
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall",
]
[[package]]
name = "regex"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rspirv"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/rspirv.git?rev=ee1e913#ee1e9135845409b2a096d880286c865c4e2ac3d6"
dependencies = [
"derive_more",
"fxhash",
"num-traits",
"spirv_headers",
]
[[package]]
name = "rustc-demangle"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
[[package]]
name = "rustc_codegen_spirv"
version = "0.3.0-alpha.0"
dependencies = [
"bimap",
"indexmap",
"rspirv",
"rustc-demangle",
"serde",
"serde_json",
"smallvec",
"spirv-tools",
"tar",
"topological-sort",
]
[[package]]
name = "rustfix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e"
dependencies = [
"anyhow",
"log",
"serde",
"serde_json",
]
[[package]]
name = "rustversion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "socket2"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
"cfg-if",
"libc",
"winapi",
]
[[package]]
name = "spirv-tools"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "148f3d945efac91764e0000290017ec65674f34633cfad1d2c038b3bedd794e8"
dependencies = [
"spirv-tools-sys",
]
[[package]]
name = "spirv-tools-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5c5e3026e72f862ac788d9f9bf703ae133045694e83a5bef102f6289fd62824"
dependencies = [
"cc",
]
[[package]]
name = "spirv_headers"
version = "1.5.0"
source = "git+https://github.com/gfx-rs/rspirv.git?rev=ee1e913#ee1e9135845409b2a096d880286c865c4e2ac3d6"
dependencies = [
"bitflags",
"num-traits",
]
[[package]]
name = "syn"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tar"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]]
name = "tester"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb"
dependencies = [
"cfg-if",
"getopts",
"libc",
"num_cpus",
"term",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "topological-sort"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
dependencies = [
"libc",
]

11
tests/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "compiletests"
version = "0.0.0"
authors = ["Embark <opensource@embark-studios.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
publish = false
[dependencies]
compiletest = { version = "0.6.0", package = "compiletest_rs" }
rustc_codegen_spirv = { path = "../crates/rustc_codegen_spirv" }

295
tests/src/main.rs Normal file
View File

@ -0,0 +1,295 @@
use std::{
env,
io::{Error, ErrorKind, Result},
path::{Path, PathBuf},
};
const TARGET: &str = "spirv-unknown-unknown";
const TARGET_DIR: &str = "target/compiletest";
const TEST_DEPS_PATH: &str = "target/compiletest/test-deps";
const TEST_DEPS_TOML_PATH: &str = "target/compiletest/test-deps/Cargo.toml";
const SPIRV_STD_TARGET: &str = "target/compiletest/spirv-std";
const SPIRV_STD_HOST_DEPS: &str = "target/compiletest/spirv-std/debug/deps";
const SPIRV_STD_TARGET_DEPS: &str = "target/compiletest/spirv-std/spirv-unknown-unknown/debug/deps";
const CARGO_TOML: &str = r#"[package]
name = "test-deps"
version = "0.1.0"
description = "Shared dependencies of all the tests"
authors = ["Embark <opensource@embark-studios.com>"]
edition = "2018"
[dependencies]
spirv-std = { path = "../../../crates/spirv-std", features=["const-generics"] }
[dependencies.glam]
git = "https://github.com/bitshifter/glam-rs.git"
rev="b3e94fb"
default-features=false
features = ["libm", "scalar-math"]
# Patch glam's dependency on spirv-std with our local version.
[patch.crates-io]
spirv-std-macros = { path = "../../../crates/spirv-std-macros" }
spirv-std = { path = "../../../crates/spirv-std" }
[workspace]
"#;
fn main() {
let manifest_dir = PathBuf::from("./");
std::env::set_var("CARGO_MANIFEST_DIR", &manifest_dir);
// Pull in rustc_codegen_spirv as a dynamic library in the same way
// spirv-builder does.
let codegen_backend_path = find_rustc_codegen_spirv();
let libs = build_spirv_std(&manifest_dir, &codegen_backend_path);
run_mode("ui", &codegen_backend_path, &libs);
}
/// Runs the given `mode` on the directory that matches that name, using the
/// backend provided by `codegen_backend_path`.
fn run_mode(mode: &'static str, codegen_backend_path: &Path, libs: &TestDeps) {
let mut config = compiletest::Config::default();
/// RUSTFLAGS passed to all test files.
fn test_rustc_flags(codegen_backend_path: &Path, deps: &TestDeps, libs: &[&Path]) -> String {
[
&*rust_flags(codegen_backend_path),
&*libs
.iter()
.map(|p| format!("-L {}", p.display()))
.fold(String::new(), |a, b| b + " " + &a),
"--edition 2018",
&*format!("--extern noprelude:core={}", deps.core.display()),
&*format!(
"--extern noprelude:compiler_builtins={}",
deps.compiler_builtins.display()
),
&*format!(
"--extern spirv_std_macros={}",
deps.spirv_std_macros.display()
),
&*format!("--extern spirv_std={}", deps.spirv_std.display()),
&*format!("--extern glam={}", deps.glam.display()),
"--crate-type dylib",
"-Zunstable-options",
"-Zcrate-attr=no_std",
"-Zcrate-attr=feature(register_attr,asm)",
"-Zcrate-attr=register_attr(spirv)",
]
.join(" ")
}
let flags = test_rustc_flags(
codegen_backend_path,
libs,
&[
&PathBuf::from(format!("dependency={}", SPIRV_STD_TARGET_DEPS)),
&PathBuf::from(format!("dependency={}", SPIRV_STD_HOST_DEPS)),
],
);
config.target_rustcflags = Some(flags);
config.mode = mode.parse().expect("Invalid mode");
config.target = String::from(TARGET);
config.src_base = PathBuf::from(format!("./tests/{}", mode));
config.build_base = PathBuf::from(format!("./{}-results", TARGET_DIR));
config.bless = std::env::args().any(|a| a == "--bless");
config.clean_rmeta();
compiletest::run_tests(&config);
}
/// Runs the processes needed to build `spirv-std`.
fn build_spirv_std(manifest_dir: &Path, codegen_backend_path: &Path) -> TestDeps {
let target_dir = format!("--target-dir={}", SPIRV_STD_TARGET);
// Create a new test-deps project.
if std::fs::metadata(TEST_DEPS_PATH).is_err() {
std::process::Command::new("cargo")
.args(&["new", "-q", "--lib", TEST_DEPS_PATH])
.current_dir(manifest_dir)
.stderr(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.status()
.and_then(map_status_to_result)
.unwrap();
std::fs::write(TEST_DEPS_TOML_PATH, CARGO_TOML.as_bytes()).unwrap();
std::fs::write(PathBuf::from(TEST_DEPS_PATH).join("src/lib.rs"), "").unwrap();
}
// Build test-deps
std::process::Command::new("cargo")
.args(&[
"build",
&*format!("--manifest-path={}", TEST_DEPS_TOML_PATH),
"-Zbuild-std=core",
&*format!("--target={}", TARGET),
&*target_dir,
])
.env(
"RUSTFLAGS",
rust_flags(&codegen_backend_path) + " -Zcrate-attr=no_std",
)
.env("CARGO_MANIFEST_DIR", manifest_dir)
.current_dir(manifest_dir)
.stderr(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.status()
.and_then(map_status_to_result)
.unwrap();
let compiler_builtins = find_lib(SPIRV_STD_TARGET_DEPS, "libcompiler_builtins", false).unwrap();
let core = find_lib(SPIRV_STD_TARGET_DEPS, "libcore", false).unwrap();
let spirv_std = find_lib(SPIRV_STD_TARGET_DEPS, "libspirv_std", false).unwrap();
let glam = find_lib(SPIRV_STD_TARGET_DEPS, "libglam", false).unwrap();
let spirv_std_macros = find_lib(SPIRV_STD_HOST_DEPS, "spirv_std_macros", true).unwrap();
if [
&compiler_builtins,
&core,
&spirv_std,
&glam,
&spirv_std_macros,
]
.iter()
.any(|o| o.is_none())
{
clean_project(manifest_dir);
build_spirv_std(manifest_dir, codegen_backend_path)
} else {
TestDeps {
core: core.unwrap(),
glam: glam.unwrap(),
compiler_builtins: compiler_builtins.unwrap(),
spirv_std: spirv_std.unwrap(),
spirv_std_macros: spirv_std_macros.unwrap(),
}
}
}
fn clean_project(manifest_dir: &Path) {
std::process::Command::new("cargo")
.args(&["clean", &*format!("--target-dir={}", TARGET_DIR)])
.current_dir(manifest_dir)
.stderr(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.status()
.and_then(map_status_to_result)
.unwrap();
}
/// Attempt find the rlib that matches `base`, if multiple rlibs are found
/// then a clean build is required and `None` is returned.
fn find_lib(
dir: impl AsRef<Path>,
base: impl AsRef<Path>,
dynamic: bool,
) -> Result<Option<PathBuf>> {
let base = base.as_ref();
let expected_name = if dynamic {
format!("{}{}", env::consts::DLL_PREFIX, base.display())
} else {
base.display().to_string()
};
let paths = std::fs::read_dir(dir.as_ref())?
.filter_map(Result::ok)
.map(|entry| entry.path())
.filter(|path| {
let name = {
let name = path.file_name();
if name.is_none() {
return false;
}
name.unwrap()
};
let name_matches = name.to_str().unwrap().starts_with(&expected_name);
let extension_matches = path.extension().map_or(false, |ext| {
if dynamic {
ext == env::consts::DLL_EXTENSION
} else {
ext == "rlib"
}
});
name_matches && extension_matches
})
.collect::<Vec<_>>();
Ok(if paths.len() > 1 {
None
} else {
paths.into_iter().next()
})
}
/// Paths to all of the library artifacts of dependencies needed to compile tests.
struct TestDeps {
core: PathBuf,
compiler_builtins: PathBuf,
spirv_std: PathBuf,
spirv_std_macros: PathBuf,
glam: PathBuf,
}
/// The RUSTFLAGS passed to all SPIR-V builds.
fn rust_flags(codegen_backend_path: &Path) -> String {
[
&*format!("-Zcodegen-backend={}", codegen_backend_path.display()),
"-Coverflow-checks=off",
"-Cdebug-assertions=off",
"-Cdebuginfo=2",
"-Cembed-bitcode=no",
]
.join(" ")
}
/// Convience function to map process failure to results in Rust.
fn map_status_to_result(status: std::process::ExitStatus) -> Result<()> {
match status.success() {
true => Ok(()),
false => Err(Error::new(
ErrorKind::Other,
format!(
"process terminated with non-zero code: {}",
status.code().unwrap_or(0)
),
)),
}
}
// https://github.com/rust-lang/cargo/blob/1857880b5124580c4aeb4e8bc5f1198f491d61b1/src/cargo/util/paths.rs#L29-L52
fn dylib_path_envvar() -> &'static str {
if cfg!(windows) {
"PATH"
} else if cfg!(target_os = "macos") {
"DYLD_FALLBACK_LIBRARY_PATH"
} else {
"LD_LIBRARY_PATH"
}
}
fn dylib_path() -> Vec<PathBuf> {
match env::var_os(dylib_path_envvar()) {
Some(var) => env::split_paths(&var).collect(),
None => Vec::new(),
}
}
fn find_rustc_codegen_spirv() -> PathBuf {
let filename = format!(
"{}rustc_codegen_spirv{}",
env::consts::DLL_PREFIX,
env::consts::DLL_SUFFIX
);
for mut path in dylib_path() {
path.push(&filename);
if path.is_file() {
return path;
}
}
panic!("Could not find {} in library path", filename);
}

7
tests/ui/arch/all.rs Normal file
View File

@ -0,0 +1,7 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let vector = glam::BVec2::new(true, true);
assert!(spirv_std::arch::all(vector));
}

7
tests/ui/arch/any.rs Normal file
View File

@ -0,0 +1,7 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let vector = glam::BVec2::new(true, false);
assert!(spirv_std::arch::any(vector));
}

10
tests/ui/arch/f_add.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 2.0;
let vx = glam::Vec2::new(2.0, 5.0);
let vy = glam::Vec2::new(5.0, 2.0);
assert!(spirv_std::arch::f_add_vector(vx, vy) == glam::Vec2::new(7.0, 7.0));
}

10
tests/ui/arch/f_div.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 10.0;
let y = 2.0;
let vx = glam::Vec2::new(10.0, 10.0);
let vy = glam::Vec2::new(2.0, 2.0);
assert!(spirv_std::arch::f_div_vector(vx, vy) == glam::Vec2::new(5.0, 5.0));
}

10
tests/ui/arch/f_mod.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 10.0;
let y = 2.0;
let vx = glam::Vec2::new(10.0, 10.0);
let vy = glam::Vec2::new(2.0, 2.0);
assert!(spirv_std::arch::f_mod_vector(vx, vy) == glam::Vec2::new(0.0, 0.0));
}

10
tests/ui/arch/f_mul.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 2.0;
let vx = glam::Vec2::new(5.0, 2.0);
let vy = glam::Vec2::new(2.0, 5.0);
assert!(spirv_std::arch::f_mul_vector(vx, vy) == glam::Vec2::new(10.0, 10.0));
}

View File

@ -0,0 +1,8 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let operand: f32 = -5.0;
let vector = glam::Vec2::new(-5.0, -0.0);
assert!(spirv_std::arch::f_negate_vector(vector) == glam::Vec2::new(5.0, 0.0));
}

10
tests/ui/arch/f_rem.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = -10.0;
let y = -2.0;
let vx = glam::Vec2::new(-10.0, -10.0);
let vy = glam::Vec2::new(-2.0, -2.0);
assert!(spirv_std::arch::f_mod_vector(vx, vy) == glam::Vec2::new(-0.0, -0.0));
}

10
tests/ui/arch/f_sub.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5.0;
let y = 5.0;
let vx = glam::Vec2::new(5.0, 7.0);
let vy = glam::Vec2::new(5.0, 7.0);
assert!(spirv_std::arch::f_sub_vector(vx, vy) == glam::Vec2::new(0.0, 0.0));
}

10
tests/ui/arch/i_add.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 2;
let vx = glam::IVec2::new(2, 5);
let vy = glam::IVec2::new(5, 2);
assert!(unsafe { spirv_std::arch::i_add_vector(vx, vy) } == glam::IVec2::new(7, 7));
}

10
tests/ui/arch/i_mul.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 2;
let vx = glam::IVec2::new(5, 2);
let vy = glam::IVec2::new(2, 5);
assert!(spirv_std::arch::i_mul_vector(vx, vy) == glam::IVec2::new(10, 10));
}

10
tests/ui/arch/i_sub.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 5;
let y = 5;
let vx = glam::IVec2::new(5, 7);
let vy = glam::IVec2::new(5, 7);
assert!(spirv_std::arch::i_sub_vector(vx, vy) == glam::IVec2::new(0, 0));
}

10
tests/ui/arch/s_div.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 10;
let y = 2;
let vx = glam::IVec2::new(10, 10);
let vy = glam::IVec2::new(2, 2);
assert!(unsafe { spirv_std::arch::s_div_vector(vx, vy) } == glam::IVec2::new(5, 5));
}

10
tests/ui/arch/s_mod.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = 10;
let y = 2;
let vx = glam::IVec2::new(10, 10);
let vy = glam::IVec2::new(2, 2);
assert!(spirv_std::arch::s_mod_vector(vx, vy) == glam::IVec2::new(0, 0));
}

View File

@ -0,0 +1,8 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let operand: i32 = -5;
let vector = glam::IVec2::new(-5, -0);
assert!(spirv_std::arch::s_negate_vector(vector) == glam::IVec2::new(5, 0));
}

10
tests/ui/arch/s_rem.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x = -10;
let y = -2;
let vx = glam::IVec2::new(-10, -10);
let vy = glam::IVec2::new(-2, -2);
assert!(spirv_std::arch::s_rem_vector(vx, vy) == glam::IVec2::new(-0, -0));
}

10
tests/ui/arch/u_div.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x: u32 = 10;
let y = 2;
let vx = glam::UVec2::new(10, 10);
let vy = glam::UVec2::new(2, 2);
assert!(unsafe { spirv_std::arch::u_div_vector(vx, vy) } == glam::UVec2::new(5, 5));
}

10
tests/ui/arch/u_mod.rs Normal file
View File

@ -0,0 +1,10 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let x: u32 = 10;
let y = 2;
let vx = glam::UVec2::new(10, 10);
let vy = glam::UVec2::new(2, 2);
assert!(spirv_std::arch::u_mod_vector(vx, vy) == glam::UVec2::new(0, 0));
}

View File

@ -0,0 +1,14 @@
// Test `OpVectorExtractDynamic`
// build-pass
use spirv_std::arch;
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let element = unsafe { arch::vector_extract_dynamic(vector, 1) };
assert!(2.0 == element);
let uvector = glam::UVec2::new(1, 2);
let uelement = unsafe { arch::vector_extract_dynamic(uvector, 1) };
assert!(2 == uelement);
}

View File

@ -0,0 +1,16 @@
// Test `OpVectorInsertDynamic`
// build-pass
use spirv_std::arch;
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let expected = glam::Vec2::new(1.0, 3.0);
let new_vector = unsafe { arch::vector_insert_dynamic(vector, 1, 3.0) };
assert!(new_vector == expected);
let uvector = glam::UVec2::new(1, 2);
let uexpected = glam::UVec2::new(1, 3);
let unew_vector = unsafe { arch::vector_insert_dynamic(uvector, 1, 3) };
assert!(unew_vector == uexpected);
}

View File

@ -0,0 +1,8 @@
// build-pass
#[spirv(fragment)]
pub fn main() {
let vector = glam::Vec2::new(10.0, 10.0);
let scalar = 2.0;
assert!(spirv_std::arch::vector_times_scalar(vector, scalar) == glam::Vec2::new(20.0, 20.0));
}

View File

@ -0,0 +1,11 @@
// Tests muiltplying a `Mat3` by a `Vec3`.
// build-pass
use spirv_std::storage_class::{Input, Output};
#[spirv(fragment)]
pub fn main(input: Input<glam::Mat3>, mut output: Output<glam::Vec3>) {
let input = *input;
let vector = input * glam::Vec3::new(1.0, 2.0, 3.0);
*output = vector;
}

8
tests/ui/hello_world.rs Normal file
View File

@ -0,0 +1,8 @@
// Simple single entrypoint function test.
// build-pass
use spirv_std as _;
#[spirv(fragment)]
pub fn main() {
}

9
tests/ui/image/fetch.rs Normal file
View File

@ -0,0 +1,9 @@
// build-pass
use spirv_std::{arch, storage_class::{Output, UniformConstant}, Image2d};
#[spirv(fragment)]
pub fn main(image: UniformConstant<Image2d>, mut output: Output<glam::Vec4>) {
let texel = image.fetch(glam::IVec2::new(0, 1));
*output = texel;
}

10
tests/ui/image/read.rs Normal file
View File

@ -0,0 +1,10 @@
// Test `OpImageRead`
// build-pass
use spirv_std::{arch, storage_class::{Output, UniformConstant}, StorageImage2d};
#[spirv(fragment)]
pub fn main(image: UniformConstant<StorageImage2d>, mut output: Output<glam::Vec2>) {
let coords = image.read(glam::IVec2::new(0, 1));
*output = coords;
}

12
tests/ui/image/write.rs Normal file
View File

@ -0,0 +1,12 @@
// Test `OpImageWrite`
// build-pass
use spirv_std::{arch, storage_class::{Input, Output, UniformConstant}, StorageImage2d};
#[spirv(fragment)]
pub fn main(input: Input<glam::Vec2>, image: UniformConstant<StorageImage2d>) {
let texels = *input;
unsafe {
image.write(glam::UVec2::new(0, 1), texels);
}
}

View File

@ -0,0 +1,20 @@
// Tests using `asm!` with a const argument.
// build-pass
use spirv_std as _;
fn asm() {
unsafe {
const N: usize = 3;
asm!(
"%int = OpTypeInt 32 0",
"%type = OpTypeVector %int {len}",
len = const N,
);
}
}
#[spirv(fragment)]
pub fn main() {
asm();
}

View File

@ -0,0 +1,16 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 32 {
let current_position = 0;
if *i < current_position {
break;
}
if *i < current_position {
break;
}
}
}

View File

@ -0,0 +1,9 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
for _ in 0..*i {
}
}

View File

@ -0,0 +1,32 @@
// NOTE(eddyb) this tests `for` loop desugaring (with its call to `Iterator::next`
// and matching on the resulting `Option`), without relying on a `Range` iterator.
// More precisely, `Range` used to not compile, due to it using `mem::replace`,
// which, before https://github.com/rust-lang/rust/pull/83022, used to just call
// `mem::swap` (which has a block-wise optimization that can't work on SPIR-V).
// build-pass
use spirv_std::{num_traits::Num, storage_class::Input};
use core::ops::Range;
struct RangeIter<T>(Range<T>);
impl<T: Num + Ord + Copy> Iterator for RangeIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let x = self.0.start;
if x >= self.0.end {
None
} else {
self.0.start = x + T::one();
Some(x)
}
}
}
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
for _ in RangeIter(0..*i) {
}
}

View File

@ -0,0 +1,10 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
} else {
}
}

View File

@ -0,0 +1,14 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
} else if *i < 0 {
} else {
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
if *i < 10 {
}
}
}

View File

@ -0,0 +1,11 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i < 10 {
return;
} else {
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i < 10 {
return;
} else {
return;
}
}

View File

@ -0,0 +1,11 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i == 0 {
while *i < 10 {
}
}
}

View File

@ -0,0 +1,13 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
if *i > 0 {
}
if *i > 1 {
}
}

View File

@ -0,0 +1,48 @@
// build-pass
use glam::*;
fn sphere_sdf(p: Vec3) -> f32 {
p.length() - 1.0
}
// Global scene to render
fn scene_sdf(p: Vec3) -> f32 {
sphere_sdf(p)
}
fn render(eye: Vec3, dir: Vec3, start: f32, end: f32) -> f32 {
let max_marching_steps: i32 = 255;
let epsilon: f32 = 0.0001;
let mut depth = start;
let mut i = 0;
loop {
if i < max_marching_steps {
break;
}
let dist = scene_sdf(eye + depth * dir);
if dist < epsilon {
return depth;
}
depth += dist;
if depth >= end {
return end;
}
i += 1;
}
end
}
#[spirv(fragment)]
pub fn main() {
let v = Vec3::new(1.0, 1.0, 1.0);
render(v, v, 1.0, 2.0);
}

View File

@ -0,0 +1,8 @@
// build-pass
use spirv_std as _;
#[spirv(fragment)]
pub fn main() {
loop {}
}

View File

@ -0,0 +1,9 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
}
}

View File

@ -0,0 +1,10 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
break;
}
}

View File

@ -0,0 +1,10 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
continue;
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
}
}
}

View File

@ -0,0 +1,14 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
} else {
break;
}
}
}

View File

@ -0,0 +1,15 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
break;
}
if *i == 1 {
break;
}
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
continue;
}
}
}

View File

@ -0,0 +1,14 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
if *i == 0 {
continue;
} else {
continue;
}
}
}

View File

@ -0,0 +1,10 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 10 {
return;
}
}

View File

@ -0,0 +1,11 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
}
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
break;
}
}
}

View File

@ -0,0 +1,12 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
continue;
}
}
}

View File

@ -0,0 +1,14 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
if *i > 10 {
break;
}
}
}
}

View File

@ -0,0 +1,14 @@
// build-pass
use spirv_std::storage_class::Input;
#[spirv(fragment)]
pub fn main(i: Input<i32>) {
while *i < 20 {
while *i < 10 {
if *i > 5 {
continue;
}
}
}
}

View File

@ -0,0 +1,16 @@
// Test creating unitialized memory.
// build-pass
use spirv_std as _;
use core::mem::MaybeUninit;
const MAYBEI32: MaybeUninit<&i32> = MaybeUninit::<&i32>::uninit();
pub fn create_uninit_and_write() {
let mut maybei32 = MAYBEI32;
unsafe { maybei32.as_mut_ptr().write(&0); }
let _maybei32 = unsafe { maybei32.assume_init() };
}
#[spirv(fragment)]
pub fn main() {}

View File

@ -0,0 +1,13 @@
// Test using `&&` operator.
// build-pass
extern crate spirv_std;
fn f(x: bool, y: bool) -> bool {
x && y
}
#[spirv(fragment)]
pub fn main() {
f(false, true);
}

View File

@ -0,0 +1,16 @@
// Doesn't work, only worked before because I think it got optimized away before
// hitting the backend.
// build-fail
#![feature(ptr_internals)]
use spirv_std::storage_class::Output;
use core::ptr::Unique;
const POINTER: Unique<[u8;4]> = Unique::<[u8; 4]>::dangling();
#[spirv(fragment)]
pub fn main(mut output: Output<u8>) {
let _pointer = POINTER;
}

View File

@ -0,0 +1,13 @@
error: pointer has non-null integer address
|
= note: Stack:
allocate_const_scalar::main
Unnamed function ID %9
error: invalid binary:0:0 - No OpEntryPoint instruction was found. This is only allowed if the Linkage capability is being used.
|
= note: spirv-val failed
= note: module "./target/compiletest-results/lang/core/ptr/allocate_const_scalar.stage-id.spv"
error: aborting due to 2 previous errors

View File

@ -0,0 +1,12 @@
// Tests allocating a null pointer at `const` time.
// build-pass
use spirv_std as _;
use core::ptr::null;
const NULL_PTR: *const i32 = null();
#[spirv(fragment)]
pub fn main() {
let _null_ptr = NULL_PTR;
}

View File

@ -0,0 +1,16 @@
// Tests using a vector like pointer at `const` time.
// build-pass
#![feature(ptr_internals)]
use spirv_std as _;
use core::ptr::Unique;
const VEC_LIKE: (Unique<usize>, usize, usize) = (Unique::<usize>::dangling(), 0, 0);
pub fn assign_vec_like() {
let _vec_like = VEC_LIKE;
}
#[spirv(fragment)]
pub fn main() {}

View File

@ -0,0 +1,10 @@
// Test that `signum` works.
// build-pass
use spirv_std::storage_class::{Input, Output};
use spirv_std::num_traits::Float;
#[spirv(fragment)]
pub fn main(i: Input<f32>, mut o: Output<f32>) {
*o = (*i).signum();
}

View File

@ -0,0 +1,13 @@
// Test panics coming from the Rust language such as `1 / 0`.
// build-pass
use spirv_std as _;
fn int_div(x: usize) -> usize {
1 / x
}
#[spirv(fragment)]
pub fn main() {
int_div(0);
}

View File

@ -0,0 +1,13 @@
// Test that bounds checking causes panics.
// build-pass
use spirv_std as _;
fn array_bounds_check(x: [u32; 4], i: usize) -> u32 {
x[i]
}
#[spirv(fragment)]
pub fn main() {
array_bounds_check([0, 1, 2, 3], 5);
}

View File

@ -0,0 +1,9 @@
// Test that calling `panic!` works.
// build-pass
use spirv_std as _;
#[spirv(fragment)]
pub fn main() {
panic!("aaa");
}

View File

@ -0,0 +1,21 @@
// Test that using push constants work.
// NOTE(eddyb) this won't pass Vulkan validation (see `push_constant_vulkan`),
// but should still pass the baseline SPIR-V validation.
// build-pass
extern crate spirv_std;
use spirv_std::storage_class::PushConstant;
#[derive(Copy, Clone)]
pub struct ShaderConstants {
pub width: u32,
pub height: u32,
pub time: f32,
}
#[spirv(fragment)]
pub fn main(constants: PushConstant<ShaderConstants>) {
let _constants = *constants;
}