New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize memory-releated `std::arch::wasm32` intrinsics #56292

Open
alexcrichton opened this Issue Nov 27, 2018 · 44 comments

Comments

Projects
None yet
@alexcrichton
Member

alexcrichton commented Nov 27, 2018

This is a tracking issue where I'm going to propose that we stabilize two functions in the standard library:

These intrinsics are currently existing as memory::size and memory::grow, but I'm going to propose here that we don't do that and flatten them in the wasm32 module. As a reference, their signatures are:

fn memory_size(memory_index: u32) -> usize;
fn memory_grow(memory_index: u32, delta_pages: usize) -> isize;

Semantics

These two intrinsics represent instructions stabilized in the WebAssembly specification.

The memory.size instruction will return the current size, in WebAssembly pages, of the specified memory index. Currently only index 0 is allowed, the index is required to be a constant value, and the return value is an usize value. Note that usize is used instead of the spec's i32 for two reasons: this is more forward compatible with a possible wasm64 architecture and the return value is always an unsigned number.

The memory.grow instruction will grow the memory index specified by the given number of pages. The old size of memory, in pages, is returned. If the grow operation fails, then -1 is returned. LIke memory_size, the memory index is currently required to be 0 and must be a constant value. The delta may be a runtime value, however.

The binary encoding of these two instructions each have a reserved zero byte which is intended to be used to specify a different nonzero memory index in the future. As a recap, each WebAssembly module may have multiple "memory" instances, each assigned a unique index starting from zero. In the WebAssembly MVP, however, only at most one memory can be assigned with each wasm module, always located at index 0. (the memory may be omitted as well)

While the memory argument is currently required to be zero, it's expected that future versions of WebAssembly will no longer have this requirement and any u32 value can be specified. It's also worth noting that the zero byte in the encoding of memory.size and memory.grow may not only be exclusively used for new indices. Current proposals to WebAssembly have repurposed required zero bytes as flags fields in addition to specified more than nonzero indices. While I'm not aware of any proposal to do so, it may be possible that a future feature to WebAssembly will have more than just a memory index argument to these instructions.

Stabilization in Rust

Stabilization of these intrinsics would be a significant step for Rust on multiple axes:

  • Primarily these would be the first non-x86 intrinsics stabilized. This means it's the first architecture to have a stable std::arch module which isn't x86/x86_64.
  • Unlike x86 intrinsics, there is no prior art for how these intrinsics should be stabilized. Unlike x86/x86_64 the "vendor" (the WebAssembly specification) isn't giving us a document of functions with signatures.

Stabilization here will be paving a path forward for future stabilization of WebAssembly intrinsics, so it's good to consider conventions! It's unclear if the WebAssembly specification will, if ever, provide a document like Intel does for intrinsics with function names and function signatures for other languages to provide.

We've had some discussion on the naming of wasm intrinsics. We'd like to ensure that we match Clang (like we do for x86/x86_64), but Clang doesn't currently (AFAIK) have a naming convention beyond the __builtin_* internal defines it has today.

What I'm proposing here is basically a convention of:

  • We provide intrinsics for instructions not natively expressable in Rust. For example we don't give an i32.add intrinsic function as it's just a + b.
  • Intrinsic signatures match the effective signature of the instruction, to the best it can. Above the memory.grow and memory.size intrinsics are fairly simple.
  • Intrinsic names match the name of the wasm intstructions, with non-rust-identifier characters mapped to an underscore.

The thinking behind these set of conventions it that it should be very easy to figure out what each intrinsic does, just like it is for Intel. The Rust documentation would always link to the WebAssembly specification for stabilized intrinsics.

Additionally we won't have any sort of automatic verification of WebAssembly intrinsics just yet like we do for x86 intrinsics in the stdsimd repository. There's so few WebAssembly intrinsics it's thought that we can simply manually verify each intrinsic.

TODO items before stabilization is finalized

  • FCP (this issue)
  • Rename the intrinsics (if that's decided on)
  • Fix the "This is supported on MIPS only" message in documentation
  • Update documentation to link to WebAssembly specification
  • maybe flag functions as safe
  • Update documentation on behavior with nonzero indexes
  • Document the page size on these intrinsics.

@alexcrichton alexcrichton added the T-libs label Nov 27, 2018

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 27, 2018

Note that for alternatives of naming I'm not listing them exhaustively here as there's some discussion already at rust-lang-nursery/stdsimd#562, but if others feel that we should name them differently, it'd be good to discuss here/there!

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 27, 2018

@rfcbot fcp merge

cc @rust-lang/wg-wasm
cc @tlively

There's a good long description in the post above about the stabilization here, and now I'd like to request a sign-off

@rfcbot

This comment has been minimized.

rfcbot commented Nov 27, 2018

Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged teams:

Concerns:

Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 27, 2018

Oh sorry it's probably also worth mentioning the rationale for stabilization here. That's twofold:

  • First, this enables allocators like wee_alloc to be built on stable Rust now that they'd have access to the actual wasm instructions to allocate memory.
  • Second, this starts the process on stabilizing a convention for how to encode WebAssembly intrinsics in Rust, paving the way for future instructions like atomics and SIMD
@fitzgen

This comment has been minimized.

Member

fitzgen commented Nov 27, 2018

First: I would love to get wee_alloc on stable and anything else using these wasm instructions! +1 from me.

However, I find it very strange from a language design perspective that there is this exception to the way that functions and their arguments behave where certain functions' arguments must be "const" but that is not expressible in the type system at all. It didn't feel weird for intrinsics, since those are not normal functions, but here it does. Alex tells me that the extant arch::x86 functions already behave like this, so I suppose it isn't worth re-litigating...

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 27, 2018

Ah yes @fitzgen, an excellent point! FWIW I think it was briefly considered for arch::x86{,_64} to use traits for this, but it was quickly ruled out for that use case specifically because:

  • There are thousands of intrinsics which would require practically thousands of traits
  • We couldn't automatically generate "the most appropriate trait" for each intrinsic with good naming and such, as it wasn't programmatically specified anywhere
  • There's so much history with the existing intrinsics in C/C++ we wanted to draw from that instead of trying to pave a new set of conventions.

You might realize, though, that none of these arguments apply to WebAssembly! We're talking about a handful of possible intrinsics as well as no prior art/history/specification. We're blazing a new trail here!

The std::arch module I think is definitely open to having a per-platform conventions rather than attempting to have a cross-platform convention for all the various intrinsics here and there. In that sense I do think it's a possible legitimate alternative to have something like:

fn memory_size<T: Memory>() -> i32;
fn memory_grow<T: Memory>(delta: i32) -> i32;

trait Memory: Sealed { /* all unstable */ }
struct Memory0;

impl Memory for Memory0 { /* ... */ }

memory_size::<Memory0>(); 
// etc...

I would probably personally still be in favor of an x86/x86_64-like approach where we require, for now, arguments to be constants. It makes the functions a little weird, but is in theory something we can fix in the future and is hopefully a largely forward-compatible story. With these being such low-level intrinsics I'm also tempted to not try to add too much abstraction as it could run the risk of not being too beneficial in practice (as these are so rarely used) and also providing hindrances to usage or stabilization accidentally.

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 27, 2018

Oh one other point I can bring up as well, is that both of these intrinsics are unsafe. Neither, however, actually need to be unsafe. Unlike x86/x86_64 we don't have to worry about "what happens if a cpu executes an unknown instruction" because that's actually impossible for WebAssembly. As a result these functions can likely be safe as they don't expose any amount of inherent unsafety.

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 27, 2018

cc @rust-lang/lang I think this proposal seems fine, but as it affects intrinsics / the abstract machine, I think we'll want to look at this. :)

@eddyb

This comment has been minimized.

Member

eddyb commented Nov 27, 2018

IMO we should bring in either @rust-lang/lang and/or @rust-lang/compiler into the decision (not sure what adding T- tags will do, but we probably don't need to change the FCP?).

For myself, this change is fine, including (only for intrinsics), "required-const arguments".

cc @sunfishcode

@joshtriplett

This comment has been minimized.

Member

joshtriplett commented Nov 27, 2018

I'd like to see the low-level intrinsics match the instructions as closely as possible. We can then have higher level wrappers similar to the type system approach proposed above.

Could we please name the "memory" argument something else, though? Something that makes it less ambiguous?

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 27, 2018

@eddyb

not sure what adding T- tags will do

Nothing due to rfcbot bugs. :(

For myself, this change is fine, including (only for intrinsics), "required-const arguments".

Wait; I missed this... What exactly does #[rustc_args_required_const(n)] do? make the nth argument const X: T such that it must be evaluable at compile time? Seems this is used in a bunch of stable intrinsics for x86 right now.

@eddyb

This comment has been minimized.

Member

eddyb commented Nov 27, 2018

@Centril Yes, this would ideally be information that the compiler has about intrinsics, but it appears that infrastructure like platform-intrinsics has gone mostly unused and stdsimd relies on LLVM intrinsics directly, which is not a future/compiler-friendly approach.

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 27, 2018

OK; ummh... feels like a legitimized hack to me especially since const-only parameters in fn foo(const X: T, ...) won't unify with fn foo<const X: T>() since the latter is inferrable and the former is not and I don't know how we'll solve this for the Fn traits... What strikes me as problematic was that the language team never was in on this in rust-lang/rfcs#2325. I suppose that the change to the type system has already been done so adding it here doesn't cause any new type of problems.

@eddyb

This comment has been minimized.

Member

eddyb commented Nov 27, 2018

@Centril It's not part of the typesystem and it should (very importantly) be only done for intrinsics - they're already special in ways the typesystem can't capture (e.g. transmute).

@tlively

This comment has been minimized.

Contributor

tlively commented Nov 27, 2018

LGTM FWIW. I did notice on the documentation that it's telling me these functions are available for MIPS only, but that is an entirely separate issue.

Edit: I see this is already in the TODOs!

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Nov 28, 2018

Currently only index 0 is allowed

The doc-comments and code don’t agree on what happens if this is not the case. The former talks about a “runtime validation error of the wasm module”, but the Rust code wrapping the intrinsic calls abort().

the index is required to be a constant value

What does that mean, from a user’s point of view? What happens if I try to use it with a non-constant? What exactly is considered "constant"? Is it the same as if I copy-pasted the source expression used as the argument into a const item?

All of this is worth documenting in the respective doc-comments. (Perhaps a reference to some shared documentation of "constant argument" in some place. Perhaps in the Nomicon?)

The memory.grow instruction will grow the memory index specified by the given number of pages.

The delta argument is a i32. What happens if it is negative?

the current size, in WebAssembly pages

It seems that this API can only be useful if the size of a page is known. https://github.com/WebAssembly/design/blob/master/Semantics.md#resizing says this is currently 64 KB, but could be (optionally) larger in the future. Should there be an API to query the page size?

Unlike x86/x86_64 we don't have to worry about "what happens if a cpu executes an unknown instruction" because that's actually impossible for WebAssembly.

How is it impossible? Won’t future extensions to the WebAssembly "language" ever add new instructions? What do (older) implementations do when encountering an unknown instruction?

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 28, 2018

@SimonSapin

What does that mean, from a user’s point of view? What happens if I try to use it with a non-constant? What exactly is considered "constant"? Is it the same as if I copy-pasted the source expression used as the argument into a const item?

All of this is worth documenting in the respective doc-comments. (Perhaps a reference to some shared documentation of "constant argument" in some place. Perhaps in the Nomicon?)

From @eddyb's answer (#56292 (comment)) to my question re. rustc_args_required_const we know that the formal parameter is a const context such that the actual argument must be a constant expression, thus it must also be assignable to a const item. The reference explains what a const context/expr means and you can refer to that in the documentation.

@gnzlbg

This comment has been minimized.

Contributor

gnzlbg commented Nov 28, 2018

@SimonSapin

What exactly is considered "constant"? What does that mean, from a user’s point of view? What happens if I try to use it with a non-constant?

From a user's point of view, these arguments are const (that's what is considered "constant"). So the answer to the question "What happens if one tries to assign a const a non-constant?" is "the same thing that happens if one tries to assign a non-constant-expression to a const": one gets an error saying that the argument is not a constant expression. Playground:

error: argument 1 is required to be a constant
 --> src/main.rs:5:5
  |
5 |     foo(x);
  |     ^^^^^^

error: aborting due to previous error

The error message could be arguably a bit better, but I think it is good enough, and there is nothing blocking anyone from working on that.


@joshtriplett

Could we please name the "memory" argument something else, though? Something that makes it less ambiguous?

The technical term in the WebAssembly spec is "memory index" (http://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-memory).

AFAICT changing an argument name is not a backwards incompatible change, so we can probably do this any time.


@fitzgen

However, I find it very strange from a language design perspective that there is this exception to the way that functions and their arguments behave where certain functions' arguments must be "const" but that is not expressible in the type system at all.

Hardware has the concept of immediate mode arguments but Rust does not support these in its type system yet, so APIs for intrinsics that accept immediate mode arguments are necessarily awkward (they are something that the language cannot properly express). A couple of different alternatives were considered in the std::arch RFCs, but they all had even more downsides than this "hack".

Work on this topic is currently blocked on const-generics stabilization. But the worst case scenario that I can imagine is that afterwards we discover that this was all a bad idea and that we don't want to support these in the type system, such that we will do nothing here and these APIs will remain awkward to use, or such that we deprecate them and replace them with better APIs. Either way, this is in my opinion better than not adding these APIs (we wouldn't be able to use SIMD on stable Rust right now without these, WASM would have to continue to require nightly Rust, etc.).

@gnzlbg

This comment has been minimized.

Contributor

gnzlbg commented Nov 28, 2018

Oh one other point I can bring up as well, is that both of these intrinsics are unsafe. Neither, however, actually need to be unsafe. Unlike x86/x86_64 we don't have to worry about "what happens if a cpu executes an unknown instruction" because that's actually impossible for WebAssembly. As a result these functions can likely be safe as they don't expose any amount of inherent unsafety.

IIRC the only reason the x86/x86_64 intrinsics are unsafe is because they require target features to work correctly (and until something like RFC target_feature 1.1 is merged, we can't do any better). These functions do not require any target features to work correctly, so the only reason they would have to be unsafe is if there is anything that callers must uphold for safety.

I am not sure if this is the case:

  • memory_size(x: i32): the docs state that if x != 0 then this might produce a WASM validation error. AFAIK the WebAssembly spec requires validation to be performed, so calling memory_size with x != 0 cannot lead safe Rust code to violate any of Rust safety guarantees, and therefore, memory_size can be safe.

  • grow also takes a delta: i32 argument that represents the number of memory pages requested. The docs state that if the request cannot be satisfied, grow returns -1. From reading the spec, it is unclear to me what happens if delta < 0. Is grow guaranteed to return -1 in this case ? If so, I think it can be safe as well.

@pepyakin

This comment has been minimized.

Contributor

pepyakin commented Nov 28, 2018

I think grow should take u32, since memory.grow implicitly assumes unsigned value AFAIU.

@sunfishcode

This comment has been minimized.

Contributor

sunfishcode commented Nov 28, 2018

WebAssembly interprets all of these values as unsigned, including the delta, so there's no possibility for it to be negative.

Separately, while 64-bit linear memories aren't designed yet, it's likely that LLVM will model this as a separate architecture "wasm64", even though at the wasm level, it's still one architecture. This is why we call the current target "wasm32". So if that happens, then on wasm64, memory.grow and memory.size will want to work in terms of 64-bit types.

So I recommend Rust use usize for the return types and delta argument of memory.grow and memory.size. The memory index argument could also be unsigned, though we don't know a lot about what things would look like if there were very large numbers of linear memories.

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Nov 28, 2018

@sunfishcode These functions are in a std::arch::wasm32 module. Presumably, was64 targets will have a corresponding std::arch::wasm64 module where corresponding functions can have a different signature.

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Nov 28, 2018

It seems that at least some of the values in these signatures should be u32 instead of i32.

@rfcbot concern u32

@sunfishcode

This comment has been minimized.

Contributor

sunfishcode commented Nov 28, 2018

@SimonSapin That makes sense. Still though, these are related to memory sizes, and code intending to support both wasm32 and wasm64 will likely be using usize for related values, so using usize in these builtins would make them more convenient.

@gnzlbg

This comment has been minimized.

Contributor

gnzlbg commented Nov 28, 2018

@SimonSapin changing u32 to usize is not backwards compatible, if we were to use usize here we could re-export these as is from the wasm64 module.

Having said this, I don't know of any good reason to re-export these: they are tiny, and re-implementing them with u64 for wasm64 is zero work (this is something we do in x86/x86_64 though).

From a semantic point-of-view, usize is not only pointer sized, but is also the integer type that fixes how much a pointer can be offseted, the maximum number of elements in an array, the maximum size of a Rust object, and has the same layout as uintptr_t. I don't know which types does __builtin_wasm_memory_grow accept in clang, but in the tests these use __SIZE_TYPE__, it might be worth it to pick a type that's semantically equivalent to what the C compilers exposes. Although @alexcrichton mentioned that for clang at least this is all still pretty much in the air.

@Kimundi

This comment has been minimized.

Member

Kimundi commented Nov 28, 2018

I second the notion that using i32 in these signatures should at least be justified somehow. For reference, WebAssembly spec uses the name i32 to mean "uninterpreted 32 bit", while s32 and u32 correspond to our" i32 and u32.

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Nov 28, 2018

Regarding the page size, should we document 64 KiB in the doc-comments of these functions?

Regarding validation: if I understand correctly it happens when first "loading" a module, and rejects modules that contains unsupported instructions? Then yes, making these functions safe sounds good.

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 28, 2018

Ok thanks for the info @sunfishcode, and good find @Kimundi! In that case I'd propose...

fn memory_size(memory_index: u32) -> usize;
fn memory_grow(memory_index: u32, delta_pages: usize) -> isize;

@SimonSapin yeah I think we can document the 64KiB page size. Also correct yeah, validation always happens when loading a file, so unsupported instructions will always (as defined by the spec) prevent the entire module from being loaded.

@Kimundi

This comment has been minimized.

Member

Kimundi commented Nov 28, 2018

@SimonSapin: Correct, validation is something that you do on the final bytecode before instantiating it in the embedder, it doesn't happen as part of the compilation.

Documenting the pagesize seems sensible to avoid mistakes.

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 28, 2018

(I've updated the proposal at the top with the new signatures)

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Nov 28, 2018

@rfcbot resolve u32

@rfcbot

This comment has been minimized.

rfcbot commented Nov 28, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@sunfishcode

This comment has been minimized.

Contributor

sunfishcode commented Nov 28, 2018

As a minor detail, while the memory size is defined as a u32 today, the actual binary encoding uses a variable-length field which is compatible with larger sizes, so nothing fundamentally prevents WebAssembly from increasing the allowed size in the future. However, it doesn't seem likely that anyone would ever want anywhere near that many linear memories in a single module.

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 28, 2018

Looking through the specification and the operational semantics of WASM we have:

However; The OCaml implementation of grow is:

let grow mem delta =
  let old_size = size mem in
  let new_size = Int32.add old_size delta in
  if I32.gt_u old_size new_size then raise SizeOverflow else
  if not (within_limits new_size mem.max) then raise SizeLimit else
  let after = create new_size in
  let dim = Array1_64.dim mem.content in
  Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim);
  mem.content <- after

In particular we have: if I32.gt_u old_size new_size then raise SizeOverflow else.
Thus we can conclude that delta >= 0 or an exception is raised so this seems to be validated at runtime?

@sunfishcode

This comment has been minimized.

Contributor

sunfishcode commented Nov 28, 2018

In particular we have: if I32.gt_u old_size new_size then raise SizeOverflow else.
Thus we can conclude that delta >= 0 or an exception is raised so this seems to be validated at runtime?

That's a runtime check for overflow, not for negative deltas. If the old size is 0 and the delta is 0x80000000, that's valid here and not an overflow, because it's using an unsigned interpretation (gt_u), even though that delta value would be negative if interpreted as signed.

@fitzgen

This comment has been minimized.

Member

fitzgen commented Nov 28, 2018

@sunfishcode

As a minor detail, while the memory size is defined as a u32 today, the actual binary encoding uses a variable-length field which is compatible with larger sizes, so nothing fundamentally prevents WebAssembly from increasing the allowed size in the future.

On the rare chance we need to access memory indices that are larger than u32::MAX we can always add a memory_grow2 function. /me shrugs

@Centril

This comment has been minimized.

Contributor

Centril commented Nov 28, 2018

@sunfishcode Hmm; ok -- then the WASM specification does not, as far as I can tell, whether specify whether delta < 0 is permitted or not... Can we check what the semantics are with the folks that wrote the spec?

@rfcbot

This comment has been minimized.

rfcbot commented Dec 8, 2018

The final comment period, with a disposition to merge, as per the review above, is now complete.

alexcrichton added a commit to alexcrichton/stdsimd that referenced this issue Dec 9, 2018

Stabilize wasm32 memory-related intrinsics
This commit stabilizes the wasm32 memory-related intrinsics, as
specified in rust-lang/rust#56292. The old intrinsics were removed and
the current intrinsics were updated in place, but it's the last breaking
change!
@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Dec 9, 2018

I've opened a stabilization PR at rust-lang-nursery/stdsimd#613

alexcrichton added a commit to alexcrichton/stdsimd that referenced this issue Dec 10, 2018

Stabilize wasm32 memory-related intrinsics
This commit stabilizes the wasm32 memory-related intrinsics, as
specified in rust-lang/rust#56292. The old intrinsics were removed and
the current intrinsics were updated in place, but it's the last breaking
change!

alexcrichton added a commit to rust-lang-nursery/stdsimd that referenced this issue Dec 10, 2018

Stabilize wasm32 memory-related intrinsics (#613)
This commit stabilizes the wasm32 memory-related intrinsics, as
specified in rust-lang/rust#56292. The old intrinsics were removed and
the current intrinsics were updated in place, but it's the last breaking
change!
@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Dec 10, 2018

Ok the stdsimd implementation has been merged. I've made one final tweak suggested by @sunfishcode that the memory_grow function actually returns a usize instead of an isize. The "failed to grow" scenario is documented as "returns usize::max_value()" and now a very-large success won't have to cast into an unsigned value just afterwards.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Dec 10, 2018

Update the stdsimd submodule
Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292

@alexcrichton alexcrichton referenced a pull request that will close this issue Dec 10, 2018

Open

Update the stdsimd submodule #56682

pietroalbini added a commit to pietroalbini/rust that referenced this issue Dec 11, 2018

Rollup merge of rust-lang#56682 - alexcrichton:update-stdsimd, r=niko…
…matsakis

Update the stdsimd submodule

Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292

kennytm added a commit to kennytm/rust that referenced this issue Dec 12, 2018

Rollup merge of rust-lang#56682 - alexcrichton:update-stdsimd, r=niko…
…matsakis

Update the stdsimd submodule

Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292

pietroalbini added a commit to pietroalbini/rust that referenced this issue Dec 12, 2018

Rollup merge of rust-lang#56682 - alexcrichton:update-stdsimd, r=niko…
…matsakis

Update the stdsimd submodule

Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292

pietroalbini added a commit to pietroalbini/rust that referenced this issue Dec 13, 2018

Rollup merge of rust-lang#56682 - alexcrichton:update-stdsimd, r=niko…
…matsakis

Update the stdsimd submodule

Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292

kennytm added a commit to kennytm/rust that referenced this issue Dec 14, 2018

Rollup merge of rust-lang#56682 - alexcrichton:update-stdsimd, r=niko…
…matsakis

Update the stdsimd submodule

Includes some new stabilized intrinsics for the wasm32 target!

Closes rust-lang#56292
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment