Wasm inline assembly miscompilation.
Zig Version
b316c25cc6f5b1703d7912da16c5c987f4406451
Steps to Reproduce
zig build-lib main.zig -OReleaseSmall -dynamic -target wasm32-freestanding -mcpu=generic+reference_types:
comptime {
asm (
\\.functype createElement (externref) -> (externref)
\\.import_module document, document
\\.import_name __createElement, createElement
\\
\\refs:
\\ .globl refs
\\ .tabletype refs, externref, 2
\\ .import_module glue, glue
\\ .import_name refs, refs
);
}
const std = @import("std");
const ExternRef = *anyopaque;
fn readString(str: []const u8) ExternRef {
return glue.readString(str.ptr, str.len);
}
const glue = struct {
extern "glue" fn readString(ptr: [*]const u8, len: usize) ExternRef;
};
const document = struct {
pub fn createElement(name: []const u8) ExternRef {
const ref = readString(name);
asm volatile (
\\local.get %[ref]
\\local.get %[ref]
\\table.get refs
\\call __createElement
\\table.set refs
:
: [ref] "r" (ref),
);
return ref;
}
};
export fn foo() ExternRef {
return document.createElement("h1");
}
Expected Behavior
Created by modifying the actual behavior to resemble the expected behavior:
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (result i32)))
(type (;2;) (func (param externref) (result externref)))
(import "glue" "readString" (func $readString (type 0)))
(import "document" "createElement" (func $createElement (type 2)))
(func $foo (type 1) (result i32)
(local i32)
i32.const 1048576
i32.const 2
call $readString
local.set 0
local.get 0
local.get 0
table.get 0
call $createElement
table.set 0
local.get 0)
(table (;0;) 2 externref)
(memory (;0;) 17)
(global $__stack_pointer (mut i32) (i32.const 1048576))
(export "memory" (memory 0))
(export "foo" (func $foo))
(data $.rodata (i32.const 1048576) "h1\00"))
Actual Behavior
Generated via wabt's wasm2wat --no-check main.wasm:
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (result i32)))
(import "glue" "readString" (func $readString (type 0)))
(func $foo (type 1) (result i32)
(local i32)
i32.const 1048576
i32.const 2
call $readString
local.set 0
local.get 0
local.get 0
table.get 0
call $readString
table.set 0
local.get 0)
(table (;0;) 2 externref)
(memory (;0;) 17)
(global $__stack_pointer (mut i32) (i32.const 1048576))
(export "memory" (memory 0))
(export "foo" (func $foo))
(data $.rodata (i32.const 1048576) "h1\00"))
I realized it wasn't terrible obvious... The miscompilation is the second call $readString in the foo function. It should be call $__createElement and have an import for that function.
The .functype in the module level assembly has the wrong symbol in my original code. Correcting it, causes a segfault. Maybe related to #13129.
Either way, it seems to be a miscompilation that it changed the unknown symbol __createElement into a reference to the readString function.