mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #22098 from alexrp/wasm-generic-baseline
`std.Target`: Use `lime1` as wasm baseline model and `mvp` as generic model
This commit is contained in:
commit
d916954bee
15
build.zig
15
build.zig
@ -594,15 +594,14 @@ pub fn build(b: *std.Build) !void {
|
||||
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
|
||||
const semver = try std.SemanticVersion.parse(version);
|
||||
|
||||
var target_query: std.Target.Query = .{
|
||||
.cpu_arch = .wasm32,
|
||||
.os_tag = .wasi,
|
||||
};
|
||||
target_query.cpu_features_add.addFeature(@intFromEnum(std.Target.wasm.Feature.bulk_memory));
|
||||
|
||||
const exe = addCompilerStep(b, .{
|
||||
.optimize = .ReleaseSmall,
|
||||
.target = b.resolveTargetQuery(target_query),
|
||||
.target = b.resolveTargetQuery(std.Target.Query.parse(.{
|
||||
.arch_os_abi = "wasm32-wasi",
|
||||
// * `extended_const` is not supported by the `wasm-opt` version in CI.
|
||||
// * `nontrapping_bulk_memory_len0` is supported by `wasm2c`.
|
||||
.cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0",
|
||||
}) catch unreachable),
|
||||
});
|
||||
|
||||
const exe_options = b.addOptions();
|
||||
@ -644,6 +643,8 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
|
||||
"wasm-opt",
|
||||
"-Oz",
|
||||
"--enable-bulk-memory",
|
||||
"--enable-mutable-globals",
|
||||
"--enable-nontrapping-float-to-int",
|
||||
"--enable-sign-ext",
|
||||
});
|
||||
run_opt.addArtifactArg(exe);
|
||||
|
||||
@ -1958,7 +1958,7 @@ pub const Cpu = struct {
|
||||
.x86_64 => &x86.cpu.x86_64,
|
||||
.nvptx, .nvptx64 => &nvptx.cpu.sm_20,
|
||||
.ve => &ve.cpu.generic,
|
||||
.wasm32, .wasm64 => &wasm.cpu.generic,
|
||||
.wasm32, .wasm64 => &wasm.cpu.mvp,
|
||||
.xcore => &xcore.cpu.generic,
|
||||
.xtensa => &xtensa.cpu.generic,
|
||||
|
||||
@ -2012,6 +2012,7 @@ pub const Cpu = struct {
|
||||
else => generic(arch),
|
||||
},
|
||||
.xcore => &xcore.cpu.xs1b_generic,
|
||||
.wasm32, .wasm64 => &wasm.cpu.lime1,
|
||||
|
||||
else => generic(arch),
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@ pub const Feature = enum {
|
||||
multimemory,
|
||||
multivalue,
|
||||
mutable_globals,
|
||||
nontrapping_bulk_memory_len0,
|
||||
nontrapping_fptoint,
|
||||
reference_types,
|
||||
relaxed_simd,
|
||||
@ -70,6 +71,13 @@ pub const all_features = blk: {
|
||||
.description = "Enable mutable globals",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.nontrapping_bulk_memory_len0)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Bulk memory operations with a zero length do not trap",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.bulk_memory,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.nontrapping_fptoint)] = .{
|
||||
.llvm_name = "nontrapping-fptoint",
|
||||
.description = "Enable non-trapping float-to-int conversion operators",
|
||||
@ -139,6 +147,18 @@ pub const cpu = struct {
|
||||
.sign_ext,
|
||||
}),
|
||||
};
|
||||
pub const lime1: CpuModel = .{
|
||||
.name = "lime1",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{
|
||||
.bulk_memory,
|
||||
.extended_const,
|
||||
.multivalue,
|
||||
.mutable_globals,
|
||||
.nontrapping_fptoint,
|
||||
.sign_ext,
|
||||
}),
|
||||
};
|
||||
pub const mvp: CpuModel = .{
|
||||
.name = "mvp",
|
||||
.llvm_name = "mvp",
|
||||
|
||||
@ -4150,14 +4150,9 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
|
||||
.os_tag = .freestanding,
|
||||
.cpu_features_add = std.Target.wasm.featureSet(&.{
|
||||
.atomics,
|
||||
.bulk_memory,
|
||||
// .extended_const, not supported by Safari
|
||||
.multivalue,
|
||||
.mutable_globals,
|
||||
.nontrapping_fptoint,
|
||||
.reference_types,
|
||||
//.relaxed_simd, not supported by Firefox or Safari
|
||||
.sign_ext,
|
||||
// observed to cause Error occured during wast conversion :
|
||||
// Unknown operator: 0xfd058 in Firefox 117
|
||||
//.simd128,
|
||||
|
||||
@ -1591,10 +1591,35 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
|
||||
// When bulk_memory is enabled, we lower it to wasm's memcpy instruction.
|
||||
// If not, we lower it ourselves manually
|
||||
if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) {
|
||||
const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0);
|
||||
|
||||
if (!len0_ok) {
|
||||
try cg.startBlock(.block, .empty);
|
||||
|
||||
// Even if `len` is zero, the spec requires an implementation to trap if `src + len` or
|
||||
// `dst + len` are out of memory bounds. This can easily happen in Zig in a case such
|
||||
// as:
|
||||
//
|
||||
// const dst: [*]u8 = undefined;
|
||||
// const src: [*]u8 = undefined;
|
||||
// var len: usize = runtime_zero();
|
||||
// @memcpy(dst[0..len], src[0..len]);
|
||||
//
|
||||
// So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design.
|
||||
try cg.emitWValue(len);
|
||||
try cg.addTag(.i32_eqz);
|
||||
try cg.addLabel(.br_if, 0);
|
||||
}
|
||||
|
||||
try cg.lowerToStack(dst);
|
||||
try cg.lowerToStack(src);
|
||||
try cg.emitWValue(len);
|
||||
try cg.addExtended(.memory_copy);
|
||||
|
||||
if (!len0_ok) {
|
||||
try cg.endBlock();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4782,10 +4807,33 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
|
||||
// When bulk_memory is enabled, we lower it to wasm's memset instruction.
|
||||
// If not, we lower it ourselves.
|
||||
if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) {
|
||||
const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0);
|
||||
|
||||
if (!len0_ok) {
|
||||
try cg.startBlock(.block, .empty);
|
||||
|
||||
// Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is
|
||||
// out of memory bounds. This can easily happen in Zig in a case such as:
|
||||
//
|
||||
// const ptr: [*]u8 = undefined;
|
||||
// var len: usize = runtime_zero();
|
||||
// @memset(ptr[0..len], 42);
|
||||
//
|
||||
// So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design.
|
||||
try cg.emitWValue(len);
|
||||
try cg.addTag(.i32_eqz);
|
||||
try cg.addLabel(.br_if, 0);
|
||||
}
|
||||
|
||||
try cg.lowerToStack(ptr);
|
||||
try cg.emitWValue(value);
|
||||
try cg.emitWValue(len);
|
||||
try cg.addExtended(.memory_fill);
|
||||
|
||||
if (!len0_ok) {
|
||||
try cg.endBlock();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -2826,6 +2826,7 @@ pub const Feature = packed struct(u8) {
|
||||
multimemory,
|
||||
multivalue,
|
||||
@"mutable-globals",
|
||||
@"nontrapping-bulk-memory-len0",
|
||||
@"nontrapping-fptoint",
|
||||
@"reference-types",
|
||||
@"relaxed-simd",
|
||||
@ -2835,14 +2836,44 @@ pub const Feature = packed struct(u8) {
|
||||
@"shared-mem",
|
||||
|
||||
pub fn fromCpuFeature(feature: std.Target.wasm.Feature) Tag {
|
||||
return @enumFromInt(@intFromEnum(feature));
|
||||
return switch (feature) {
|
||||
.atomics => .atomics,
|
||||
.bulk_memory => .@"bulk-memory",
|
||||
.exception_handling => .@"exception-handling",
|
||||
.extended_const => .@"extended-const",
|
||||
.half_precision => .@"half-precision",
|
||||
.multimemory => .multimemory,
|
||||
.multivalue => .multivalue,
|
||||
.mutable_globals => .@"mutable-globals",
|
||||
.nontrapping_bulk_memory_len0 => .@"nontrapping-bulk-memory-len0", // Zig extension.
|
||||
.nontrapping_fptoint => .@"nontrapping-fptoint",
|
||||
.reference_types => .@"reference-types",
|
||||
.relaxed_simd => .@"relaxed-simd",
|
||||
.sign_ext => .@"sign-ext",
|
||||
.simd128 => .simd128,
|
||||
.tail_call => .@"tail-call",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toCpuFeature(tag: Tag) ?std.Target.wasm.Feature {
|
||||
return if (@intFromEnum(tag) < @typeInfo(std.Target.wasm.Feature).@"enum".fields.len)
|
||||
@enumFromInt(@intFromEnum(tag))
|
||||
else
|
||||
null;
|
||||
return switch (tag) {
|
||||
.atomics => .atomics,
|
||||
.@"bulk-memory" => .bulk_memory,
|
||||
.@"exception-handling" => .exception_handling,
|
||||
.@"extended-const" => .extended_const,
|
||||
.@"half-precision" => .half_precision,
|
||||
.multimemory => .multimemory,
|
||||
.multivalue => .multivalue,
|
||||
.@"mutable-globals" => .mutable_globals,
|
||||
.@"nontrapping-bulk-memory-len0" => .nontrapping_bulk_memory_len0, // Zig extension.
|
||||
.@"nontrapping-fptoint" => .nontrapping_fptoint,
|
||||
.@"reference-types" => .reference_types,
|
||||
.@"relaxed-simd" => .relaxed_simd,
|
||||
.@"sign-ext" => .sign_ext,
|
||||
.simd128 => .simd128,
|
||||
.@"tail-call" => .tail_call,
|
||||
.@"shared-mem" => null, // Linker-only feature.
|
||||
};
|
||||
}
|
||||
|
||||
pub const format = @compileError("use @tagName instead");
|
||||
|
||||
@ -109,7 +109,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
FILE *out = fopen(argv[2], "wb");
|
||||
if (out == NULL) panic("unable to open output file");
|
||||
fputs("#include <math.h>\n"
|
||||
fputs("#include <float.h>\n"
|
||||
"#include <math.h>\n"
|
||||
"#include <stdint.h>\n"
|
||||
"#include <stdlib.h>\n"
|
||||
"#include <string.h>\n"
|
||||
@ -273,6 +274,47 @@ int main(int argc, char **argv) {
|
||||
" return dst;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static uint32_t i32_trunc_sat_f32(const float src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return (uint32_t)(signbit(src) == 0 ? INT32_MAX : INT32_MIN);\n"
|
||||
" return (uint32_t)(int32_t)src;\n"
|
||||
"}\n"
|
||||
"static uint32_t u32_trunc_sat_f32(const float src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return signbit(src) == 0 ? UINT32_MAX : 0;\n"
|
||||
" return (uint32_t)src;\n"
|
||||
"}\n"
|
||||
"static uint32_t i32_trunc_sat_f64(const double src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return (uint32_t)(signbit(src) == 0 ? INT32_MAX : INT32_MIN);\n"
|
||||
" return (uint32_t)(int32_t)src;\n"
|
||||
"}\n"
|
||||
"static uint32_t u32_trunc_sat_f64(const double src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return signbit(src) == 0 ? UINT32_MAX : 0;\n"
|
||||
" return (uint32_t)src;\n"
|
||||
"}\n"
|
||||
"static uint64_t i64_trunc_sat_f32(const float src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return (uint64_t)(signbit(src) == 0 ? INT64_MAX : INT64_MIN);\n"
|
||||
" return (uint64_t)(int64_t)src;\n"
|
||||
"}\n"
|
||||
"static uint64_t u64_trunc_sat_f32(const float src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return signbit(src) == 0 ? UINT64_MAX : 0;\n"
|
||||
" return (uint64_t)src;\n"
|
||||
"}\n"
|
||||
"static uint64_t i64_trunc_sat_f64(const double src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return (uint64_t)(signbit(src) == 0 ? INT64_MAX : INT64_MIN);\n"
|
||||
" return (uint64_t)(int64_t)src;\n"
|
||||
"}\n"
|
||||
"static uint64_t u64_trunc_sat_f64(const double src) {\n"
|
||||
" if (isnan(src)) return 0;\n"
|
||||
" if (isinf(src)) return signbit(src) == 0 ? UINT64_MAX : 0;\n"
|
||||
" return (uint64_t)src;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"
|
||||
" uint8_t *new_m = *m;\n"
|
||||
" uint32_t r = *p;\n"
|
||||
@ -2074,14 +2116,61 @@ int main(int argc, char **argv) {
|
||||
case WasmOpcode_prefixed:
|
||||
switch (InputStream_readLeb128_u32(&in)) {
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "i32_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "u32_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "i32_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f64_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "u32_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "i64_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "u64_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "i64_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f64_u:
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "u64_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmPrefixedOpcode_memory_init:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
|
||||
@ -1033,6 +1033,27 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.zig_name = "wasm",
|
||||
.llvm_name = "WebAssembly",
|
||||
.td_name = "WebAssembly.td",
|
||||
.extra_features = &.{
|
||||
.{
|
||||
.zig_name = "nontrapping_bulk_memory_len0",
|
||||
.desc = "Bulk memory operations with a zero length do not trap",
|
||||
.deps = &.{"bulk_memory"},
|
||||
},
|
||||
},
|
||||
.extra_cpus = &.{
|
||||
.{
|
||||
.llvm_name = null,
|
||||
.zig_name = "lime1",
|
||||
.features = &.{
|
||||
"bulk_memory",
|
||||
"extended_const",
|
||||
"multivalue",
|
||||
"mutable_globals",
|
||||
"nontrapping_fptoint",
|
||||
"sign_ext",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
.{
|
||||
.zig_name = "x86",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user