mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Auto merge of #113508 - matthiaskrgr:rollup-xzrp4nt, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #111618 (Always name the return place.) - #113247 (Add Tests for native wasm exceptions) - #113273 (Use String or Int to set the opt level) - #113469 (Remove `default_free_fn` feature) - #113493 (additional io::copy specializations) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a9eba8d793
@ -328,8 +328,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
|
||||
let local_ref = &self.locals[local];
|
||||
|
||||
// FIXME Should the return place be named?
|
||||
let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE {
|
||||
let name = if bx.sess().fewer_names() {
|
||||
None
|
||||
} else {
|
||||
Some(match whole_local_var.or(fallback_var.clone()) {
|
||||
|
@ -400,10 +400,20 @@ changelog-seen = 2
|
||||
# =============================================================================
|
||||
[rust]
|
||||
|
||||
# Whether or not to optimize the compiler and standard library.
|
||||
# Whether or not to optimize when compiling the compiler and standard library,
|
||||
# and what level of optimization to use.
|
||||
# WARNING: Building with optimize = false is NOT SUPPORTED. Due to bootstrapping,
|
||||
# building without optimizations takes much longer than optimizing. Further, some platforms
|
||||
# fail to build without this optimization (c.f. #65352).
|
||||
# The valid options are:
|
||||
# true - Enable optimizations.
|
||||
# false - Disable optimizations.
|
||||
# 0 - Disable optimizations.
|
||||
# 1 - Basic optimizations.
|
||||
# 2 - Some optimizations.
|
||||
# 3 - All optimizations.
|
||||
# "s" - Optimize for binary size.
|
||||
# "z" - Optimize for binary size, but also turn off loop vectorization.
|
||||
#optimize = true
|
||||
|
||||
# Indicates that the build should be configured for debugging Rust. A
|
||||
@ -757,7 +767,7 @@ changelog-seen = 2
|
||||
# This option will override the same option under [build] section.
|
||||
#profiler = build.profiler (bool)
|
||||
|
||||
# This option supports enable `rpath` in each target independently,
|
||||
# This option supports enable `rpath` in each target independently,
|
||||
# and will override the same option under [rust] section. It only works on Unix platforms
|
||||
#rpath = rust.rpath (bool)
|
||||
|
||||
|
@ -133,51 +133,6 @@ pub trait Default: Sized {
|
||||
fn default() -> Self;
|
||||
}
|
||||
|
||||
/// Return the default value of a type according to the `Default` trait.
|
||||
///
|
||||
/// The type to return is inferred from context; this is equivalent to
|
||||
/// `Default::default()` but shorter to type.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// #![feature(default_free_fn)]
|
||||
///
|
||||
/// use std::default::default;
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct AppConfig {
|
||||
/// foo: FooConfig,
|
||||
/// bar: BarConfig,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct FooConfig {
|
||||
/// foo: i32,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct BarConfig {
|
||||
/// bar: f32,
|
||||
/// baz: u8,
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let options = AppConfig {
|
||||
/// foo: default(),
|
||||
/// bar: BarConfig {
|
||||
/// bar: 10.1,
|
||||
/// ..default()
|
||||
/// },
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "default_free_fn", issue = "73014")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn default<T: Default>() -> T {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Default`.
|
||||
#[rustc_builtin_macro(Default, attributes(default))]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
|
@ -1,4 +1,8 @@
|
||||
use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
|
||||
use crate::alloc::Allocator;
|
||||
use crate::cmp;
|
||||
use crate::collections::VecDeque;
|
||||
use crate::io::IoSlice;
|
||||
use crate::mem::MaybeUninit;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -86,7 +90,7 @@ where
|
||||
|
||||
/// Specialization of the read-write loop that reuses the internal
|
||||
/// buffer of a BufReader. If there's no buffer then the writer side
|
||||
/// should be used intead.
|
||||
/// should be used instead.
|
||||
trait BufferedReaderSpec {
|
||||
fn buffer_size(&self) -> usize;
|
||||
|
||||
@ -104,7 +108,39 @@ where
|
||||
}
|
||||
|
||||
default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result<u64> {
|
||||
unimplemented!("only called from specializations");
|
||||
unreachable!("only called from specializations")
|
||||
}
|
||||
}
|
||||
|
||||
impl BufferedReaderSpec for &[u8] {
|
||||
fn buffer_size(&self) -> usize {
|
||||
// prefer this specialization since the source "buffer" is all we'll ever need,
|
||||
// even if it's small
|
||||
usize::MAX
|
||||
}
|
||||
|
||||
fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
|
||||
let len = self.len();
|
||||
to.write_all(self)?;
|
||||
*self = &self[len..];
|
||||
Ok(len as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Allocator> BufferedReaderSpec for VecDeque<u8, A> {
|
||||
fn buffer_size(&self) -> usize {
|
||||
// prefer this specialization since the source "buffer" is all we'll ever need,
|
||||
// even if it's small
|
||||
usize::MAX
|
||||
}
|
||||
|
||||
fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
|
||||
let len = self.len();
|
||||
let (front, back) = self.as_slices();
|
||||
let bufs = &mut [IoSlice::new(front), IoSlice::new(back)];
|
||||
to.write_all_vectored(bufs)?;
|
||||
self.clear();
|
||||
Ok(len as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,6 +254,47 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> {
|
||||
fn buffer_size(&self) -> usize {
|
||||
cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len())
|
||||
}
|
||||
|
||||
fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
|
||||
let mut bytes = 0;
|
||||
|
||||
// avoid allocating before we have determined that there's anything to read
|
||||
if self.capacity() == 0 {
|
||||
bytes = stack_buffer_copy(&mut reader.take(DEFAULT_BUF_SIZE as u64), self)?;
|
||||
if bytes == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
self.reserve(DEFAULT_BUF_SIZE);
|
||||
let mut buf: BorrowedBuf<'_> = self.spare_capacity_mut().into();
|
||||
match reader.read_buf(buf.unfilled()) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let read = buf.filled().len();
|
||||
if read == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
// SAFETY: BorrowedBuf guarantees all of its filled bytes are init
|
||||
// and the number of read bytes can't exceed the spare capacity since
|
||||
// that's what the buffer is borrowing from.
|
||||
unsafe { self.set_len(self.len() + read) };
|
||||
bytes += read as u64;
|
||||
}
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
|
||||
reader: &mut R,
|
||||
writer: &mut W,
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::cmp::{max, min};
|
||||
use crate::collections::VecDeque;
|
||||
use crate::io;
|
||||
use crate::io::*;
|
||||
|
||||
#[test]
|
||||
@ -19,7 +21,7 @@ struct ShortReader {
|
||||
|
||||
impl Read for ShortReader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let bytes = min(self.cap, self.read_size);
|
||||
let bytes = min(self.cap, self.read_size).min(buf.len());
|
||||
self.cap -= bytes;
|
||||
self.observed_buffer = max(self.observed_buffer, buf.len());
|
||||
Ok(bytes)
|
||||
@ -78,6 +80,40 @@ fn copy_specializes_bufreader() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_specializes_to_vec() {
|
||||
let cap = 123456;
|
||||
let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
|
||||
let mut sink = Vec::new();
|
||||
assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap());
|
||||
assert!(
|
||||
source.observed_buffer > DEFAULT_BUF_SIZE,
|
||||
"expected a large buffer to be provided to the reader"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_specializes_from_vecdeque() {
|
||||
let mut source = VecDeque::with_capacity(100 * 1024);
|
||||
for _ in 0..20 * 1024 {
|
||||
source.push_front(0);
|
||||
}
|
||||
for _ in 0..20 * 1024 {
|
||||
source.push_back(0);
|
||||
}
|
||||
let mut sink = WriteObserver { observed_buffer: 0 };
|
||||
assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
|
||||
assert_eq!(20 * 1024, sink.observed_buffer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_specializes_from_slice() {
|
||||
let mut source = [1; 60 * 1024].as_slice();
|
||||
let mut sink = WriteObserver { observed_buffer: 0 };
|
||||
assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
|
||||
assert_eq!(60 * 1024, sink.observed_buffer);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod io_benches {
|
||||
use crate::fs::File;
|
||||
|
@ -875,11 +875,10 @@ impl Default for StringOrBool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum RustOptimize {
|
||||
#[serde(deserialize_with = "deserialize_and_validate_opt_level")]
|
||||
String(String),
|
||||
Int(u8),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
@ -889,26 +888,74 @@ impl Default for RustOptimize {
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_and_validate_opt_level<'de, D>(d: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let v = String::deserialize(d)?;
|
||||
if ["0", "1", "2", "3", "s", "z"].iter().find(|x| **x == v).is_some() {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(format!(r#"unrecognized option for rust optimize: "{}", expected one of "0", "1", "2", "3", "s", "z""#, v)).map_err(serde::de::Error::custom)
|
||||
impl<'de> Deserialize<'de> for RustOptimize {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(OptimizeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct OptimizeVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for OptimizeVisitor {
|
||||
type Value = RustOptimize;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if ["s", "z"].iter().find(|x| **x == value).is_some() {
|
||||
Ok(RustOptimize::String(value.to_string()))
|
||||
} else {
|
||||
Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if matches!(value, 0..=3) {
|
||||
Ok(RustOptimize::Int(value as u8))
|
||||
} else {
|
||||
Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(RustOptimize::Bool(value))
|
||||
}
|
||||
}
|
||||
|
||||
fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
|
||||
format!(
|
||||
r#"unrecognized option for rust optimize: "{}", expected one of 0, 1, 2, 3, "s", "z", true, false"#,
|
||||
v
|
||||
)
|
||||
}
|
||||
|
||||
impl RustOptimize {
|
||||
pub(crate) fn is_release(&self) -> bool {
|
||||
if let RustOptimize::Bool(true) | RustOptimize::String(_) = &self { true } else { false }
|
||||
match &self {
|
||||
RustOptimize::Bool(true) | RustOptimize::String(_) => true,
|
||||
RustOptimize::Int(i) => *i > 0,
|
||||
RustOptimize::Bool(false) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_opt_level(&self) -> Option<String> {
|
||||
match &self {
|
||||
RustOptimize::String(s) => Some(s.clone()),
|
||||
RustOptimize::Int(i) => Some(i.to_string()),
|
||||
RustOptimize::Bool(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,10 @@ fn rust_optimize() {
|
||||
assert_eq!(parse("").rust_optimize.is_release(), true);
|
||||
assert_eq!(parse("rust.optimize = false").rust_optimize.is_release(), false);
|
||||
assert_eq!(parse("rust.optimize = true").rust_optimize.is_release(), true);
|
||||
assert_eq!(parse("rust.optimize = \"1\"").rust_optimize.get_opt_level(), Some("1".to_string()));
|
||||
assert_eq!(parse("rust.optimize = 0").rust_optimize.is_release(), false);
|
||||
assert_eq!(parse("rust.optimize = 1").rust_optimize.is_release(), true);
|
||||
assert_eq!(parse("rust.optimize = 1").rust_optimize.get_opt_level(), Some("1".to_string()));
|
||||
assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.is_release(), true);
|
||||
assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string()));
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
|
||||
qemu-system-x86 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
|
||||
RUN curl -sL https://nodejs.org/dist/v18.12.0/node-v18.12.0-linux-x64.tar.xz | \
|
||||
tar -xJ
|
||||
|
||||
# Install 32-bit OVMF files for the i686-unknown-uefi test. This package
|
||||
@ -42,7 +42,7 @@ RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--musl-root-x86_64=/usr/local/x86_64-linux-musl \
|
||||
--set build.nodejs=/node-v15.14.0-linux-x64/bin/node \
|
||||
--set build.nodejs=/node-v18.12.0-linux-x64/bin/node \
|
||||
--set rust.lld
|
||||
|
||||
# Some run-make tests have assertions about code size, and enabling debug
|
||||
@ -58,6 +58,8 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T
|
||||
tests/ui \
|
||||
tests/mir-opt \
|
||||
tests/codegen-units \
|
||||
tests/codegen \
|
||||
tests/assembly \
|
||||
library/core
|
||||
|
||||
ENV NVPTX_TARGETS=nvptx64-nvidia-cuda
|
||||
|
@ -1,47 +0,0 @@
|
||||
# `default_free_fn`
|
||||
|
||||
The tracking issue for this feature is: [#73014]
|
||||
|
||||
[#73014]: https://github.com/rust-lang/rust/issues/73014
|
||||
|
||||
------------------------
|
||||
|
||||
Adds a free `default()` function to the `std::default` module. This function
|
||||
just forwards to [`Default::default()`], but may remove repetition of the word
|
||||
"default" from the call site.
|
||||
|
||||
[`Default::default()`]: ../../std/default/trait.Default.html#tymethod.default
|
||||
|
||||
Here is an example:
|
||||
|
||||
```rust
|
||||
#![feature(default_free_fn)]
|
||||
use std::default::default;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AppConfig {
|
||||
foo: FooConfig,
|
||||
bar: BarConfig,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FooConfig {
|
||||
foo: i32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BarConfig {
|
||||
bar: f32,
|
||||
baz: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let options = AppConfig {
|
||||
foo: default(),
|
||||
bar: BarConfig {
|
||||
bar: 10.1,
|
||||
..default()
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
@ -3,6 +3,7 @@
|
||||
// ignore-macos slightly different policy on stack protection of arrays
|
||||
// ignore-windows stack check code uses different function names
|
||||
// ignore-nvptx64 stack protector is not supported
|
||||
// ignore-wasm32-bare
|
||||
// [all] compile-flags: -Z stack-protector=all
|
||||
// [strong] compile-flags: -Z stack-protector=strong
|
||||
// [basic] compile-flags: -Z stack-protector=basic
|
||||
|
60
tests/assembly/wasm_exceptions.rs
Normal file
60
tests/assembly/wasm_exceptions.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// only-wasm32-bare
|
||||
// assembly-output: emit-asm
|
||||
// compile-flags: -C target-feature=+exception-handling
|
||||
// compile-flags: -C panic=unwind
|
||||
// compile-flags: -C llvm-args=-wasm-enable-eh
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
extern {
|
||||
fn may_panic();
|
||||
|
||||
#[rustc_nounwind]
|
||||
fn log_number(number: usize);
|
||||
}
|
||||
|
||||
struct LogOnDrop;
|
||||
|
||||
impl Drop for LogOnDrop {
|
||||
fn drop(&mut self) {
|
||||
unsafe { log_number(0); }
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_cleanup:
|
||||
#[no_mangle]
|
||||
pub fn test_cleanup() {
|
||||
let _log_on_drop = LogOnDrop;
|
||||
unsafe { may_panic(); }
|
||||
|
||||
// CHECK-NOT: call
|
||||
// CHECK: try
|
||||
// CHECK: call may_panic
|
||||
// CHECK: catch_all
|
||||
// CHECK: rethrow
|
||||
// CHECK: end_try
|
||||
}
|
||||
|
||||
// CHECK-LABEL: test_rtry:
|
||||
#[no_mangle]
|
||||
pub fn test_rtry() {
|
||||
unsafe {
|
||||
core::intrinsics::r#try(|_| {
|
||||
may_panic();
|
||||
}, core::ptr::null_mut(), |data, exception| {
|
||||
log_number(data as usize);
|
||||
log_number(exception as usize);
|
||||
});
|
||||
}
|
||||
|
||||
// CHECK-NOT: call
|
||||
// CHECK: try
|
||||
// CHECK: call may_panic
|
||||
// CHECK: catch
|
||||
// CHECK: call log_number
|
||||
// CHECK: call log_number
|
||||
// CHECK-NOT: rethrow
|
||||
// CHECK: end_try
|
||||
}
|
@ -6,10 +6,10 @@
|
||||
// CHECK-LABEL: @array_load
|
||||
#[no_mangle]
|
||||
pub fn array_load(a: &[u8; 4]) -> [u8; 4] {
|
||||
// CHECK: %0 = alloca [4 x i8], align 1
|
||||
// CHECK: %_0 = alloca [4 x i8], align 1
|
||||
// CHECK: %[[TEMP1:.+]] = load <4 x i8>, ptr %a, align 1
|
||||
// CHECK: store <4 x i8> %[[TEMP1]], ptr %0, align 1
|
||||
// CHECK: %[[TEMP2:.+]] = load i32, ptr %0, align 1
|
||||
// CHECK: store <4 x i8> %[[TEMP1]], ptr %_0, align 1
|
||||
// CHECK: %[[TEMP2:.+]] = load i32, ptr %_0, align 1
|
||||
// CHECK: ret i32 %[[TEMP2]]
|
||||
*a
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ pub enum Either<T, U> { A(T), B(U) }
|
||||
// with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
|
||||
// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
|
||||
|
||||
// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x)
|
||||
// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%_0, {{.+\*|ptr}}{{.+}}%x)
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
|
||||
|
@ -1,4 +1,5 @@
|
||||
// compile-flags: -C no-prepopulate-passes
|
||||
// min-llvm-version: 15.0 (for opaque pointers)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
@ -42,7 +43,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
|
||||
#[no_mangle]
|
||||
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: memcpy.{{.+}}({{i8\*|ptr}} align 2 %{{[0-9]+}}, {{i8\*|ptr}} align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
|
||||
// CHECK: memcpy.{{.+}}(ptr align 2 %_0, ptr align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
|
||||
*&E::A(0)
|
||||
}
|
||||
|
||||
@ -50,6 +51,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
#[no_mangle]
|
||||
pub fn high_align_const() -> E<i16, i32> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
|
||||
// CHECK: memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false)
|
||||
*&E::A(0)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub enum Enum0 {
|
||||
// CHECK-NEXT: start:
|
||||
// CHECK-NEXT: %1 = icmp eq i8 %0, 2
|
||||
// CHECK-NEXT: %2 = and i8 %0, 1
|
||||
// CHECK-NEXT: %.0 = select i1 %1, i8 13, i8 %2
|
||||
// CHECK-NEXT: %_0.0 = select i1 %1, i8 13, i8 %2
|
||||
#[no_mangle]
|
||||
pub fn match0(e: Enum0) -> u8 {
|
||||
use Enum0::*;
|
||||
|
@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 {
|
||||
|
||||
// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
|
||||
// NO-NEXT: start:
|
||||
// NO-NEXT: %0 = add i32 %y, %x
|
||||
// NO-NEXT: ret i32 %0
|
||||
// NO-NEXT: %z = add i32 %y, %x
|
||||
// NO-NEXT: ret i32 %z
|
||||
let z = x + y;
|
||||
z
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
|
||||
f(x)
|
||||
}
|
||||
|
||||
// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %x)
|
||||
// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %x)
|
||||
#[no_mangle]
|
||||
pub fn struct_(x: S) -> S {
|
||||
x
|
||||
@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S {
|
||||
// CHECK-LABEL: @struct_call
|
||||
#[no_mangle]
|
||||
pub fn struct_call(x: S, f: fn(S) -> S) -> S {
|
||||
// CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %{{.+}})
|
||||
// CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %{{.+}})
|
||||
f(x)
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
||||
x
|
||||
}
|
||||
|
||||
// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
|
||||
// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %_0)?}})
|
||||
#[no_mangle]
|
||||
pub fn struct_return() -> S {
|
||||
S {
|
||||
|
@ -169,16 +169,16 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
|
||||
// CHECK-LABEL: @check_bool_to_ordering(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
|
||||
// CHECK: %0 = zext i1 %x to i8
|
||||
// OPT: %1 = icmp ule i8 %0, 1
|
||||
// OPT: call void @llvm.assume(i1 %1)
|
||||
// OPT: %2 = icmp uge i8 %0, -1
|
||||
// OPT: %3 = icmp ule i8 %0, 1
|
||||
// OPT: %4 = or i1 %2, %3
|
||||
// OPT: call void @llvm.assume(i1 %4)
|
||||
// CHECK: %_0 = zext i1 %x to i8
|
||||
// OPT: %0 = icmp ule i8 %_0, 1
|
||||
// OPT: call void @llvm.assume(i1 %0)
|
||||
// OPT: %1 = icmp uge i8 %_0, -1
|
||||
// OPT: %2 = icmp ule i8 %_0, 1
|
||||
// OPT: %3 = or i1 %1, %2
|
||||
// OPT: call void @llvm.assume(i1 %3)
|
||||
// DBG-NOT: icmp
|
||||
// DBG-NOT: assume
|
||||
// CHECK: ret i8 %0
|
||||
// CHECK: ret i8 %_0
|
||||
|
||||
transmute(x)
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ use std::mem::transmute;
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %1 = load <4 x float>, ptr %x, align 16
|
||||
// CHECK: store <4 x float> %1, ptr %0, align 16
|
||||
// CHECK: %0 = load <4 x float>, ptr %x, align 16
|
||||
// CHECK: store <4 x float> %0, ptr %_0, align 16
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -20,8 +20,8 @@ pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %1 = load <4 x i64>, ptr %x, align 16
|
||||
// CHECK: store <4 x i64> %1, ptr %0, align 32
|
||||
// CHECK: %0 = load <4 x i64>, ptr %x, align 16
|
||||
// CHECK: store <4 x i64> %0, ptr %_0, align 32
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %1 = load <4 x i64>, ptr %x, align 32
|
||||
// CHECK: store <4 x i64> %1, ptr %0, align 16
|
||||
// CHECK: %0 = load <4 x i64>, ptr %x, align 32
|
||||
// CHECK: store <4 x i64> %0, ptr %_0, align 16
|
||||
transmute(x)
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
#![feature(inline_const)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
use std::intrinsics::{transmute, transmute_unchecked};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
// Some of these need custom MIR to not get removed by MIR optimizations.
|
||||
use std::intrinsics::mir::*;
|
||||
@ -63,7 +63,7 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] {
|
||||
// CHECK-NOT: trap
|
||||
// CHECK: call void @llvm.trap
|
||||
// CHECK-NOT: trap
|
||||
mir!{
|
||||
mir! {
|
||||
{
|
||||
RET = CastTransmute(x);
|
||||
Return()
|
||||
@ -78,7 +78,7 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] {
|
||||
// CHECK-NOT: trap
|
||||
// CHECK: call void @llvm.trap
|
||||
// CHECK-NOT: trap
|
||||
mir!{
|
||||
mir! {
|
||||
{
|
||||
RET = CastTransmute(x);
|
||||
Return()
|
||||
@ -93,7 +93,7 @@ pub unsafe fn check_to_uninhabited(x: u16) {
|
||||
// CHECK-NOT: trap
|
||||
// CHECK: call void @llvm.trap
|
||||
// CHECK-NOT: trap
|
||||
mir!{
|
||||
mir! {
|
||||
let temp: BigNever;
|
||||
{
|
||||
temp = CastTransmute(x);
|
||||
@ -107,7 +107,7 @@ pub unsafe fn check_to_uninhabited(x: u16) {
|
||||
#[custom_mir(dialect = "runtime", phase = "optimized")]
|
||||
pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
|
||||
// CHECK: ret i16 poison
|
||||
mir!{
|
||||
mir! {
|
||||
{
|
||||
RET = CastTransmute(x);
|
||||
Return()
|
||||
@ -122,9 +122,7 @@ pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 {
|
||||
// CHECK: %[[TMP:.+]] = add i32 1, %x
|
||||
// CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1
|
||||
// CHECK: ret i32 %[[RET]]
|
||||
unsafe {
|
||||
transmute::<u32, i32>(1 + x) + 1
|
||||
}
|
||||
unsafe { transmute::<u32, i32>(1 + x) + 1 }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @check_nop_pair(
|
||||
@ -134,9 +132,7 @@ pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) {
|
||||
// CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0
|
||||
// CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1
|
||||
// CHECK: ret { i8, i8 } %1
|
||||
unsafe {
|
||||
transmute(x)
|
||||
}
|
||||
unsafe { transmute(x) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @check_to_newtype(
|
||||
@ -168,9 +164,9 @@ pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool {
|
||||
// CHECK-LABEL: @check_aggregate_from_bool(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 {
|
||||
// CHECK: %0 = alloca %Aggregate8, align 1
|
||||
// CHECK: %_0 = alloca %Aggregate8, align 1
|
||||
// CHECK: %[[BYTE:.+]] = zext i1 %x to i8
|
||||
// CHECK: store i8 %[[BYTE]], ptr %0, align 1
|
||||
// CHECK: store i8 %[[BYTE]], ptr %_0, align 1
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -195,8 +191,8 @@ pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
|
||||
// CHECK-LABEL: @check_to_pair(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
|
||||
// CHECK: %0 = alloca { i32, i32 }, align 4
|
||||
// CHECK: store i64 %x, ptr %0, align 4
|
||||
// CHECK: %_0 = alloca { i32, i32 }, align 4
|
||||
// CHECK: store i64 %x, ptr %_0, align 4
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -207,11 +203,11 @@ pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
|
||||
// immediates so we can write using the destination alloca's alignment.
|
||||
const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
|
||||
|
||||
// CHECK: %0 = alloca i64, align 8
|
||||
// CHECK: store i32 %x.0, ptr %1, align 8
|
||||
// CHECK: store i32 %x.1, ptr %2, align 4
|
||||
// CHECK: %3 = load i64, ptr %0, align 8
|
||||
// CHECK: ret i64 %3
|
||||
// CHECK: %_0 = alloca i64, align 8
|
||||
// CHECK: store i32 %x.0, ptr %0, align 8
|
||||
// CHECK: store i32 %x.1, ptr %1, align 4
|
||||
// CHECK: %2 = load i64, ptr %_0, align 8
|
||||
// CHECK: ret i64 %2
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -219,8 +215,8 @@ pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_to_float(x: u32) -> f32 {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %0 = bitcast i32 %x to float
|
||||
// CHECK: ret float %0
|
||||
// CHECK: %_0 = bitcast i32 %x to float
|
||||
// CHECK: ret float %_0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -228,16 +224,16 @@ pub unsafe fn check_to_float(x: u32) -> f32 {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_from_float(x: f32) -> u32 {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %0 = bitcast float %x to i32
|
||||
// CHECK: ret i32 %0
|
||||
// CHECK: %_0 = bitcast float %x to i32
|
||||
// CHECK: ret i32 %_0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @check_to_bytes(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
|
||||
// CHECK: %0 = alloca [4 x i8], align 1
|
||||
// CHECK: store i32 %x, ptr %0, align 1
|
||||
// CHECK: %_0 = alloca [4 x i8], align 1
|
||||
// CHECK: store i32 %x, ptr %_0, align 1
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -253,10 +249,10 @@ pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
|
||||
// CHECK-LABEL: @check_to_aggregate(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
|
||||
// CHECK: %0 = alloca %Aggregate64, align 4
|
||||
// CHECK: store i64 %x, ptr %0, align 4
|
||||
// CHECK: %1 = load i64, ptr %0, align 4
|
||||
// CHECK: ret i64 %1
|
||||
// CHECK: %_0 = alloca %Aggregate64, align 4
|
||||
// CHECK: store i64 %x, ptr %_0, align 4
|
||||
// CHECK: %0 = load i64, ptr %_0, align 4
|
||||
// CHECK: ret i64 %0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -273,7 +269,7 @@ pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] {
|
||||
// CHECK-NEXT: start
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false)
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %_0, ptr align 8 %x, i64 800, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
transmute(x)
|
||||
}
|
||||
@ -282,7 +278,7 @@ pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] {
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
|
||||
// CHECK-NEXT: start
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false)
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %_0, ptr align 1 %x, i64 100, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
transmute(x)
|
||||
}
|
||||
@ -301,8 +297,8 @@ pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) {
|
||||
pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %0 = bitcast double %x to i64
|
||||
// CHECK: %1 = inttoptr i64 %0 to ptr
|
||||
// CHECK: ret ptr %1
|
||||
// CHECK: %_0 = inttoptr i64 %0 to ptr
|
||||
// CHECK: ret ptr %_0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -311,8 +307,8 @@ pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
|
||||
pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %0 = ptrtoint ptr %x to i64
|
||||
// CHECK: %1 = bitcast i64 %0 to double
|
||||
// CHECK: ret double %1
|
||||
// CHECK: %_0 = bitcast i64 %0 to double
|
||||
// CHECK: ret double %_0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -376,10 +372,10 @@ pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option<Box<[u8]>> {
|
||||
// CHECK-LABEL: @check_pair_to_dst_ref(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
|
||||
// CHECK: %0 = inttoptr i64 %x.0 to ptr
|
||||
// CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %0, 0
|
||||
// CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1
|
||||
// CHECK: ret { ptr, i64 } %2
|
||||
// CHECK: %_0.0 = inttoptr i64 %x.0 to ptr
|
||||
// CHECK: %0 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0
|
||||
// CHECK: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1
|
||||
// CHECK: ret { ptr, i64 } %1
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
@ -391,7 +387,7 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
|
||||
|
||||
// CHECK: start
|
||||
// CHECK-NEXT: ret void
|
||||
mir!{
|
||||
mir! {
|
||||
{
|
||||
RET = CastTransmute(x);
|
||||
Return()
|
||||
@ -408,7 +404,7 @@ pub unsafe fn check_unit_to_never(x: ()) {
|
||||
// CHECK-NOT: trap
|
||||
// CHECK: call void @llvm.trap
|
||||
// CHECK-NOT: trap
|
||||
mir!{
|
||||
mir! {
|
||||
let temp: ZstNever;
|
||||
{
|
||||
temp = CastTransmute(x);
|
||||
@ -425,7 +421,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () {
|
||||
|
||||
// CHECK: start
|
||||
// CHECK-NEXT: ret void
|
||||
mir!{
|
||||
mir! {
|
||||
{
|
||||
RET = CastTransmute(x);
|
||||
Return()
|
||||
@ -457,10 +453,10 @@ pub struct HighAlignScalar(u8);
|
||||
// CHECK-LABEL: @check_to_overalign(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar {
|
||||
// CHECK: %0 = alloca %HighAlignScalar, align 8
|
||||
// CHECK: store i64 %x, ptr %0, align 8
|
||||
// CHECK: %1 = load i64, ptr %0, align 8
|
||||
// CHECK: ret i64 %1
|
||||
// CHECK: %_0 = alloca %HighAlignScalar, align 8
|
||||
// CHECK: store i64 %x, ptr %_0, align 8
|
||||
// CHECK: %0 = load i64, ptr %_0, align 8
|
||||
// CHECK: ret i64 %0
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
|
@ -20,13 +20,13 @@ pub fn exhaustive_match(e: E) -> u8 {
|
||||
// CHECK-NEXT: unreachable
|
||||
//
|
||||
// CHECK: [[A]]:
|
||||
// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %1, align 1
|
||||
// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %_0, align 1
|
||||
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
|
||||
// CHECK: [[B]]:
|
||||
// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %1, align 1
|
||||
// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %_0, align 1
|
||||
// CHECK-NEXT: br label %[[EXIT]]
|
||||
// CHECK: [[C]]:
|
||||
// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %1, align 1
|
||||
// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %_0, align 1
|
||||
// CHECK-NEXT: br label %[[EXIT]]
|
||||
match e {
|
||||
E::A => 0,
|
||||
|
@ -25,7 +25,7 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big {
|
||||
// For a large type, we expect exactly three `memcpy`s
|
||||
// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big)
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %0, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false)
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %result, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false)
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %dest, {{i8\*|ptr}} align 8 %src, i{{.*}} 56, i1 false)
|
||||
// CHECK-NOT: call void @llvm.memcpy
|
||||
|
@ -38,7 +38,7 @@ pub fn replace_ref_str<'a>(r: &mut &'a str, v: &'a str) -> &'a str {
|
||||
pub fn replace_short_array(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] {
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK: %[[R:.+]] = load <3 x i32>, ptr %r, align 4
|
||||
// CHECK: store <3 x i32> %[[R]], ptr %0
|
||||
// CHECK: store <3 x i32> %[[R]], ptr %result
|
||||
// CHECK: %[[V:.+]] = load <3 x i32>, ptr %v, align 4
|
||||
// CHECK: store <3 x i32> %[[V]], ptr %r
|
||||
std::mem::replace(r, v)
|
||||
|
@ -8,13 +8,13 @@ use std::iter;
|
||||
// CHECK-LABEL: @repeat_take_collect
|
||||
#[no_mangle]
|
||||
pub fn repeat_take_collect() -> Vec<u8> {
|
||||
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false)
|
||||
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false)
|
||||
iter::repeat(42).take(100000).collect()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @repeat_with_take_collect
|
||||
#[no_mangle]
|
||||
pub fn repeat_with_take_collect() -> Vec<u8> {
|
||||
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 13, i{{[0-9]+}} 12345, i1 false)
|
||||
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false)
|
||||
iter::repeat_with(|| 13).take(12345).collect()
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
// ignore-s390x
|
||||
// ignore-windows
|
||||
// ignore-loongarch64
|
||||
// ignore-wasm32-bare
|
||||
// See repr-transparent.rs
|
||||
|
||||
#![feature(transparent_unions)]
|
||||
|
@ -152,7 +152,7 @@ pub extern "C" fn f_scalar_stack_1(
|
||||
) {
|
||||
}
|
||||
|
||||
// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 noundef %a, i128 %1, i128 %2, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
|
||||
// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
|
||||
#[no_mangle]
|
||||
pub extern "C" fn f_scalar_stack_2(
|
||||
a: u64,
|
||||
|
@ -116,150 +116,150 @@ extern "platform-intrinsic" {
|
||||
fn simd_saturating_sub<T>(x: T, y: T) -> T;
|
||||
}
|
||||
|
||||
// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM)
|
||||
// NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM)
|
||||
// SIMD vectors are passed directly, resulting in `%x` being a vector,
|
||||
// while on others they're passed indirectly, resulting in `%x` being
|
||||
// a pointer to a vector, and `%1` a vector loaded from that pointer.
|
||||
// a pointer to a vector, and `%0` a vector loaded from that pointer.
|
||||
// This is controlled by the target spec option `simd_types_indirect`.
|
||||
// The same applies to `%{{y|2}}` as well.
|
||||
// The same applies to `%{{y|1}}` as well.
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i8x64
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 {
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i16x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i16x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i16x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i16x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i16x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i128x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @sadd_i128x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
@ -268,140 +268,140 @@ pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
|
||||
// CHECK-LABEL: @uadd_u8x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u8x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u8x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u8x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u8x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u8x64
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 {
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u16x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u16x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u16x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u16x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u16x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u128x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @uadd_u128x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
|
||||
simd_saturating_add(x, y)
|
||||
}
|
||||
|
||||
@ -412,140 +412,140 @@ pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
|
||||
// CHECK-LABEL: @ssub_i8x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i8x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i8x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i8x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i8x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i8x64
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 {
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i16x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i16x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i16x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i16x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i16x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i128x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ssub_i128x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
@ -554,139 +554,139 @@ pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
|
||||
// CHECK-LABEL: @usub_u8x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u8x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u8x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u8x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u8x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u8x64
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 {
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u16x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u16x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u16x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u16x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u16x32
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 {
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 {
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 {
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u128x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 {
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @usub_u128x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 {
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}})
|
||||
// CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}})
|
||||
simd_saturating_sub(x, y)
|
||||
}
|
||||
|
@ -35,13 +35,13 @@ pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 {
|
||||
// CHECK-LABEL: @insert_m
|
||||
#[no_mangle]
|
||||
pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M {
|
||||
// CHECK: insertelement <4 x float> %{{v|1|2}}, float %j, i32 %i
|
||||
// CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
|
||||
simd_insert(v, i, j)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @insert_s
|
||||
#[no_mangle]
|
||||
pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> {
|
||||
// CHECK: insertelement <4 x float> %{{v|1|2}}, float %j, i32 %i
|
||||
// CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i
|
||||
simd_insert(v, i, j)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// compile-flags: -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
#![feature(inline_const)]
|
||||
@ -44,7 +43,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> {
|
||||
#[no_mangle]
|
||||
pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
|
||||
// CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
unsafe { std::mem::transmute(x) }
|
||||
}
|
||||
|
||||
@ -59,7 +58,7 @@ pub fn build_array_t(x: [f32; 4]) -> T {
|
||||
#[no_mangle]
|
||||
pub fn build_array_transmute_t(x: [f32; 4]) -> T {
|
||||
// CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
unsafe { std::mem::transmute(x) }
|
||||
}
|
||||
|
||||
@ -78,6 +77,6 @@ pub fn build_array_u(x: [f32; 4]) -> U {
|
||||
#[no_mangle]
|
||||
pub fn build_array_transmute_u(x: [f32; 4]) -> U {
|
||||
// CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
// CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
|
||||
unsafe { std::mem::transmute(x) }
|
||||
}
|
||||
|
@ -21,6 +21,6 @@ pub struct Simd<T, const LANES: usize>([T; LANES]);
|
||||
// CHECK-LABEL: smoke
|
||||
#[no_mangle]
|
||||
pub fn smoke(ptrs: SimdConstPtr<u8, 8>, offsets: Simd<usize, 8>) -> SimdConstPtr<u8, 8> {
|
||||
// CHECK: getelementptr i8, <8 x {{i8\*|ptr}}> %1, <8 x i64> %2
|
||||
// CHECK: getelementptr i8, <8 x {{i8\*|ptr}}> %0, <8 x i64> %1
|
||||
unsafe { simd_arith_offset(ptrs, offsets) }
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ type Demo = [u8; 3];
|
||||
#[no_mangle]
|
||||
pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
|
||||
// CHECK-NOT: sub
|
||||
// CHECK: %2 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
|
||||
// CHECK: ret i1 %2
|
||||
// CHECK: %_0 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
|
||||
// CHECK: ret i1 %_0
|
||||
y.len() == 0
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ pub fn array_into_iter_len_eq_zero(y: std::array::IntoIter<Demo, 123>) -> bool {
|
||||
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: sub
|
||||
// CHECK: %1 = icmp eq {{i16|i32|i64}}
|
||||
// CHECK: ret i1 %1
|
||||
// CHECK: %_0 = icmp eq {{i16|i32|i64}}
|
||||
// CHECK: ret i1 %_0
|
||||
y.len() == 0
|
||||
}
|
||||
|
@ -11,24 +11,24 @@
|
||||
// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`.
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x)
|
||||
// CHECK: %0 = bitcast float %x to i32
|
||||
// CHECK-NEXT: ret i32 %0
|
||||
// CHECK: %_0 = bitcast float %x to i32
|
||||
// CHECK-NEXT: ret i32 %_0
|
||||
#[no_mangle]
|
||||
pub fn f32_to_bits(x: f32) -> u32 {
|
||||
unsafe { std::mem::transmute(x) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
|
||||
// CHECK: %0 = zext i1 %b to i8
|
||||
// CHECK-NEXT: ret i8 %0
|
||||
// CHECK: %_0 = zext i1 %b to i8
|
||||
// CHECK-NEXT: ret i8 %_0
|
||||
#[no_mangle]
|
||||
pub fn bool_to_byte(b: bool) -> u8 {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte)
|
||||
// CHECK: %0 = trunc i8 %byte to i1
|
||||
// CHECK-NEXT: ret i1 %0
|
||||
// CHECK: %_0 = trunc i8 %byte to i1
|
||||
// CHECK-NEXT: ret i1 %_0
|
||||
#[no_mangle]
|
||||
pub unsafe fn byte_to_bool(byte: u8) -> bool {
|
||||
std::mem::transmute(byte)
|
||||
@ -42,16 +42,16 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
|
||||
// CHECK: %0 = ptrtoint ptr %p to [[USIZE]]
|
||||
// CHECK-NEXT: ret [[USIZE]] %0
|
||||
// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]]
|
||||
// CHECK-NEXT: ret [[USIZE]] %_0
|
||||
#[no_mangle]
|
||||
pub fn ptr_to_int(p: *mut u16) -> usize {
|
||||
unsafe { std::mem::transmute(p) }
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
|
||||
// CHECK: %0 = inttoptr [[USIZE]] %i to ptr
|
||||
// CHECK-NEXT: ret ptr %0
|
||||
// CHECK: %_0 = inttoptr [[USIZE]] %i to ptr
|
||||
// CHECK-NEXT: ret ptr %_0
|
||||
#[no_mangle]
|
||||
pub fn int_to_ptr(i: usize) -> *mut u16 {
|
||||
unsafe { std::mem::transmute(i) }
|
||||
|
@ -1,4 +1,5 @@
|
||||
// compile-flags: -C no-prepopulate-passes
|
||||
// min-llvm-version: 15.0 (for opaque pointers)
|
||||
|
||||
// Check that we use undef (and not zero) for uninitialized bytes in constants.
|
||||
|
||||
@ -8,7 +9,7 @@ use std::mem::MaybeUninit;
|
||||
|
||||
pub struct PartiallyUninit {
|
||||
x: u32,
|
||||
y: MaybeUninit<[u8; 10]>
|
||||
y: MaybeUninit<[u8; 10]>,
|
||||
}
|
||||
|
||||
// CHECK: [[FULLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [10 x i8] }> undef
|
||||
@ -25,7 +26,7 @@ pub struct PartiallyUninit {
|
||||
#[no_mangle]
|
||||
pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> {
|
||||
const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit();
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{[0-9]+}}, {{i8\*|ptr}} align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false)
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %_0, ptr align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false)
|
||||
M
|
||||
}
|
||||
|
||||
@ -33,7 +34,7 @@ pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> {
|
||||
#[no_mangle]
|
||||
pub const fn partially_uninit() -> PartiallyUninit {
|
||||
const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeef, y: MaybeUninit::uninit() };
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false)
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false)
|
||||
X
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ pub const fn partially_uninit() -> PartiallyUninit {
|
||||
#[no_mangle]
|
||||
pub const fn uninit_padding_huge() -> [(u32, u8); 4096] {
|
||||
const X: [(u32, u8); 4096] = [(123, 45); 4096];
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false)
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false)
|
||||
X
|
||||
}
|
||||
|
||||
@ -49,6 +50,6 @@ pub const fn uninit_padding_huge() -> [(u32, u8); 4096] {
|
||||
#[no_mangle]
|
||||
pub const fn fully_uninit_huge() -> MaybeUninit<[u32; 4096]> {
|
||||
const F: MaybeUninit<[u32; 4096]> = MaybeUninit::uninit();
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false)
|
||||
// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false)
|
||||
F
|
||||
}
|
||||
|
@ -73,4 +73,4 @@ pub union UnionBool { b:bool }
|
||||
// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b)
|
||||
#[no_mangle]
|
||||
pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } }
|
||||
// CHECK: %0 = trunc i8 %b to i1
|
||||
// CHECK: %_0 = trunc i8 %b to i1
|
||||
|
@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 {
|
||||
// CHECK: %c = add i32 %a, %b
|
||||
let d = c;
|
||||
let e = d * a;
|
||||
// CHECK-NEXT: %0 = mul i32 %c, %a
|
||||
// CHECK-NEXT: %e = mul i32 %c, %a
|
||||
e
|
||||
// CHECK-NEXT: ret i32 %0
|
||||
// CHECK-NEXT: ret i32 %e
|
||||
}
|
||||
|
51
tests/codegen/wasm_exceptions.rs
Normal file
51
tests/codegen/wasm_exceptions.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// only-wasm32-bare
|
||||
// compile-flags: -C panic=unwind
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
extern {
|
||||
fn may_panic();
|
||||
|
||||
#[rustc_nounwind]
|
||||
fn log_number(number: usize);
|
||||
}
|
||||
|
||||
struct LogOnDrop;
|
||||
|
||||
impl Drop for LogOnDrop {
|
||||
fn drop(&mut self) {
|
||||
unsafe { log_number(0); }
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0
|
||||
#[no_mangle]
|
||||
pub fn test_cleanup() {
|
||||
let _log_on_drop = LogOnDrop;
|
||||
unsafe { may_panic(); }
|
||||
|
||||
// CHECK-NOT: call
|
||||
// CHECK: invoke void @may_panic()
|
||||
// CHECK: %cleanuppad = cleanuppad within none []
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0
|
||||
#[no_mangle]
|
||||
pub fn test_rtry() {
|
||||
unsafe {
|
||||
core::intrinsics::r#try(|_| {
|
||||
may_panic();
|
||||
}, core::ptr::null_mut(), |data, exception| {
|
||||
log_number(data as usize);
|
||||
log_number(exception as usize);
|
||||
});
|
||||
}
|
||||
|
||||
// CHECK-NOT: call
|
||||
// CHECK: invoke void @may_panic()
|
||||
// CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller
|
||||
// CHECK: {{.*}} = catchpad within {{.*}} [ptr null]
|
||||
// CHECK: catchret
|
||||
}
|
12
tests/run-make/wasm-exceptions-nostd/Makefile
Normal file
12
tests/run-make/wasm-exceptions-nostd/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
include ../tools.mk
|
||||
|
||||
# only-wasm32-bare
|
||||
|
||||
# Add a few command line args to make exceptions work
|
||||
RUSTC := $(RUSTC) -C llvm-args=-wasm-enable-eh
|
||||
RUSTC := $(RUSTC) -C target-feature=+exception-handling
|
||||
RUSTC := $(RUSTC) -C panic=unwind
|
||||
|
||||
all:
|
||||
$(RUSTC) src/lib.rs --target wasm32-unknown-unknown
|
||||
$(NODE) verify.mjs $(TMPDIR)/lib.wasm
|
67
tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs
Normal file
67
tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
|
||||
|
||||
/// Very simple allocator which never deallocates memory
|
||||
///
|
||||
/// Based on the example from
|
||||
/// https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html
|
||||
pub struct ArenaAllocator {
|
||||
arena: UnsafeCell<Arena>,
|
||||
}
|
||||
|
||||
impl ArenaAllocator {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
arena: UnsafeCell::new(Arena::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe because we are singlethreaded
|
||||
unsafe impl Sync for ArenaAllocator {}
|
||||
|
||||
unsafe impl GlobalAlloc for ArenaAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let arena = &mut *self.arena.get();
|
||||
arena.alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
||||
}
|
||||
|
||||
const ARENA_SIZE: usize = 64 * 1024; // more than enough
|
||||
|
||||
#[repr(C, align(4096))]
|
||||
struct Arena {
|
||||
buf: [u8; ARENA_SIZE], // aligned at 4096
|
||||
allocated: usize,
|
||||
}
|
||||
|
||||
impl Arena {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
buf: [0x55; ARENA_SIZE],
|
||||
allocated: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() > 4096 || layout.size() > ARENA_SIZE {
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
|
||||
let align_minus_one = layout.align() - 1;
|
||||
let start = (self.allocated + align_minus_one) & !align_minus_one; // round up
|
||||
let new_cursor = start + layout.size();
|
||||
|
||||
if new_cursor >= ARENA_SIZE {
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
|
||||
self.allocated = new_cursor;
|
||||
self.buf.as_mut_ptr().add(start)
|
||||
}
|
||||
}
|
60
tests/run-make/wasm-exceptions-nostd/src/lib.rs
Normal file
60
tests/run-make/wasm-exceptions-nostd/src/lib.rs
Normal file
@ -0,0 +1,60 @@
|
||||
#![no_std]
|
||||
#![crate_type = "cdylib"]
|
||||
|
||||
// Allow a few unstable features because we create a panic
|
||||
// runtime for native wasm exceptions from scratch
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(panic_info_message)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
/// This module allows us to use `Box`, `String`, ... even in no-std
|
||||
mod arena_alloc;
|
||||
|
||||
/// This module allows logging text, even in no-std
|
||||
mod logging;
|
||||
|
||||
/// This module allows exceptions, even in no-std
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod panicking;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
|
||||
struct LogOnDrop;
|
||||
|
||||
impl Drop for LogOnDrop {
|
||||
fn drop(&mut self) {
|
||||
logging::log_str("Dropped");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
#[allow(unconditional_panic)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn start() -> usize {
|
||||
let data = 0x1234usize as *mut u8; // Something to recognize
|
||||
|
||||
unsafe {
|
||||
core::intrinsics::r#try(|data: *mut u8| {
|
||||
let _log_on_drop = LogOnDrop;
|
||||
|
||||
logging::log_str(&alloc::format!("`r#try` called with ptr {:?}", data));
|
||||
let x = [12];
|
||||
let _ = x[4]; // should panic
|
||||
|
||||
logging::log_str("This line should not be visible! :(");
|
||||
}, data, |data, exception| {
|
||||
let exception = *Box::from_raw(exception as *mut String);
|
||||
logging::log_str("Caught something!");
|
||||
logging::log_str(&alloc::format!(" data : {:?}", data));
|
||||
logging::log_str(&alloc::format!(" exception: {:?}", exception));
|
||||
});
|
||||
}
|
||||
|
||||
logging::log_str("This program terminates correctly.");
|
||||
0
|
||||
}
|
9
tests/run-make/wasm-exceptions-nostd/src/logging.rs
Normal file
9
tests/run-make/wasm-exceptions-nostd/src/logging.rs
Normal file
@ -0,0 +1,9 @@
|
||||
extern "C" {
|
||||
fn __log_utf8(ptr: *const u8, size: usize);
|
||||
}
|
||||
|
||||
pub fn log_str(text: &str) {
|
||||
unsafe {
|
||||
__log_utf8(text.as_ptr(), text.len());
|
||||
}
|
||||
}
|
29
tests/run-make/wasm-exceptions-nostd/src/panicking.rs
Normal file
29
tests/run-make/wasm-exceptions-nostd/src/panicking.rs
Normal file
@ -0,0 +1,29 @@
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {}
|
||||
|
||||
mod internal {
|
||||
extern "C" {
|
||||
#[link_name = "llvm.wasm.throw"]
|
||||
pub fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn wasm_throw(ptr: *mut u8) -> ! {
|
||||
internal::wasm_throw(0, ptr);
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
|
||||
let msg = info
|
||||
.message()
|
||||
.map(|msg| msg.to_string())
|
||||
.unwrap_or("(no message)".to_string());
|
||||
let exception = Box::new(msg.to_string());
|
||||
unsafe {
|
||||
let exception_raw = Box::into_raw(exception);
|
||||
wasm_throw(exception_raw as *mut u8);
|
||||
}
|
||||
}
|
75
tests/run-make/wasm-exceptions-nostd/verify.mjs
Normal file
75
tests/run-make/wasm-exceptions-nostd/verify.mjs
Normal file
@ -0,0 +1,75 @@
|
||||
import fs from 'fs';
|
||||
|
||||
const dec = new TextDecoder("utf-8");
|
||||
|
||||
if (process.argv.length != 3) {
|
||||
console.log("Usage: node verify.mjs <wasm-file>");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const wasmfile = process.argv[2];
|
||||
if (!fs.existsSync(wasmfile)) {
|
||||
console.log("Error: File not found:", wasmfile);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const wasmBuffer = fs.readFileSync(wasmfile);
|
||||
|
||||
async function main() {
|
||||
|
||||
let memory = new ArrayBuffer(0) // will be changed after instantiate
|
||||
|
||||
const captured_output = [];
|
||||
|
||||
const imports = {
|
||||
env: {
|
||||
__log_utf8: (ptr, size) => {
|
||||
const str = dec.decode(new DataView(memory, ptr, size));
|
||||
captured_output.push(str);
|
||||
console.log(str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const wasmModule = await WebAssembly.instantiate(wasmBuffer, imports);
|
||||
memory = wasmModule.instance.exports.memory.buffer;
|
||||
|
||||
const start = wasmModule.instance.exports.start;
|
||||
const return_code = start();
|
||||
|
||||
console.log("Return-Code:", return_code);
|
||||
|
||||
if (return_code !== 0) {
|
||||
console.error("Expected return code 0");
|
||||
process.exit(return_code);
|
||||
}
|
||||
|
||||
const expected_output = [
|
||||
'`r#try` called with ptr 0x1234',
|
||||
'Dropped',
|
||||
'Caught something!',
|
||||
' data : 0x1234',
|
||||
' exception: "index out of bounds: the len is 1 but the index is 4"',
|
||||
'This program terminates correctly.',
|
||||
];
|
||||
|
||||
assert_equal(captured_output, expected_output);
|
||||
}
|
||||
|
||||
function assert_equal(captured_output, expected_output) {
|
||||
if (captured_output.length != expected_output.length) {
|
||||
console.error("Unexpected number of output lines. Got", captured_output.length, "but expected", expected_output.length);
|
||||
process.exit(1); // exit with error
|
||||
}
|
||||
|
||||
for (let idx = 0; idx < expected_output.length; ++idx) {
|
||||
if (captured_output[idx] !== expected_output[idx]) {
|
||||
console.error("Unexpected output");
|
||||
console.error("[got] ", captured_output[idx]);
|
||||
console.error("[expected]", expected_output[idx]);
|
||||
process.exit(2); // exit with error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await main();
|
@ -1,18 +1,3 @@
|
||||
error[E0425]: cannot find function `default` in this scope
|
||||
--> $DIR/issue-2356.rs:31:5
|
||||
|
|
||||
LL | default();
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: you might have meant to call the associated function
|
||||
|
|
||||
LL | Self::default();
|
||||
| ~~~~~~~~~~~~~
|
||||
help: consider importing this function
|
||||
|
|
||||
LL + use std::default::default;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `whiskers` in this scope
|
||||
--> $DIR/issue-2356.rs:39:5
|
||||
|
|
||||
@ -64,6 +49,12 @@ error[E0425]: cannot find function `clone` in this scope
|
||||
LL | clone();
|
||||
| ^^^^^ help: you might have meant to call the method: `self.clone`
|
||||
|
||||
error[E0425]: cannot find function `default` in this scope
|
||||
--> $DIR/issue-2356.rs:31:5
|
||||
|
|
||||
LL | default();
|
||||
| ^^^^^^^ help: you might have meant to call the associated function: `Self::default`
|
||||
|
||||
error[E0425]: cannot find function `shave` in this scope
|
||||
--> $DIR/issue-2356.rs:41:5
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user