authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-07 21:12:45+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 13:53:10-07:00
log684b81f366566353aeca18a7431f8df3304f439b
tree97199116a696b6a081482c8b146d16e7c85e549c
parent557f396f613a416e81116f85c080af8b976fe8cf

wasm: Implement fpext

This implements initial support for floating-point promotion for bitsizes <= 64

4 files changed, 39 insertions(+), 10 deletions(-)

src/arch/wasm/CodeGen.zig+36-9
...@@ -212,7 +212,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode {...@@ -212,7 +212,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode {
212 16 => switch (args.valtype1.?) {212 16 => switch (args.valtype1.?) {
213 .i32 => if (args.signedness.? == .signed) return .i32_load16_s else return .i32_load16_u,213 .i32 => if (args.signedness.? == .signed) return .i32_load16_s else return .i32_load16_u,
214 .i64 => if (args.signedness.? == .signed) return .i64_load16_s else return .i64_load16_u,214 .i64 => if (args.signedness.? == .signed) return .i64_load16_s else return .i64_load16_u,
215 .f32, .f64 => unreachable,215 .f32 => return .f32_load,
216 .f64 => unreachable,
216 },217 },
217 32 => switch (args.valtype1.?) {218 32 => switch (args.valtype1.?) {
218 .i64 => if (args.signedness.? == .signed) return .i64_load32_s else return .i64_load32_u,219 .i64 => if (args.signedness.? == .signed) return .i64_load32_s else return .i64_load32_u,
...@@ -242,7 +243,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode {...@@ -242,7 +243,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode {
242 16 => switch (args.valtype1.?) {243 16 => switch (args.valtype1.?) {
243 .i32 => return .i32_store16,244 .i32 => return .i32_store16,
244 .i64 => return .i64_store16,245 .i64 => return .i64_store16,
245 .f32, .f64 => unreachable,246 .f32 => return .f32_store,
247 .f64 => unreachable,
246 },248 },
247 32 => switch (args.valtype1.?) {249 32 => switch (args.valtype1.?) {
248 .i64 => return .i64_store32,250 .i64 => return .i64_store32,
...@@ -1064,7 +1066,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1064,7 +1066,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue {
1064}1066}
10651067
1066/// From given zig bitsize, returns the wasm bitsize1068/// From given zig bitsize, returns the wasm bitsize
1067fn toWasmIntBits(bits: u16) ?u16 {1069fn toWasmBits(bits: u16) ?u16 {
1068 return for ([_]u16{ 32, 64 }) |wasm_bits| {1070 return for ([_]u16{ 32, 64 }) |wasm_bits| {
1069 if (bits <= wasm_bits) return wasm_bits;1071 if (bits <= wasm_bits) return wasm_bits;
1070 } else null;1072 } else null;
...@@ -1120,11 +1122,11 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1120,11 +1122,11 @@ fn isByRef(ty: Type, target: std.Target) bool {
1120 .ErrorSet,1122 .ErrorSet,
1121 .Fn,1123 .Fn,
1122 .Enum,1124 .Enum,
1123 .Vector,
1124 .AnyFrame,1125 .AnyFrame,
1125 => return false,1126 => return false,
11261127
1127 .Array,1128 .Array,
1129 .Vector,
1128 .Struct,1130 .Struct,
1129 .Frame,1131 .Frame,
1130 .Union,1132 .Union,
...@@ -1218,6 +1220,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1218,6 +1220,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1218 .cond_br => self.airCondBr(inst),1220 .cond_br => self.airCondBr(inst),
1219 .dbg_stmt => WValue.none,1221 .dbg_stmt => WValue.none,
1220 .intcast => self.airIntcast(inst),1222 .intcast => self.airIntcast(inst),
1223 .fpext => self.airFpext(inst),
1221 .float_to_int => self.airFloatToInt(inst),1224 .float_to_int => self.airFloatToInt(inst),
1222 .get_union_tag => self.airGetUnionTag(inst),1225 .get_union_tag => self.airGetUnionTag(inst),
12231226
...@@ -1298,7 +1301,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1298,7 +1301,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1298 .is_err_ptr,1301 .is_err_ptr,
1299 .is_non_err_ptr,1302 .is_non_err_ptr,
1300 .fptrunc,1303 .fptrunc,
1301 .fpext,
1302 .unwrap_errunion_payload_ptr,1304 .unwrap_errunion_payload_ptr,
1303 .unwrap_errunion_err_ptr,1305 .unwrap_errunion_err_ptr,
13041306
...@@ -1513,7 +1515,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1513,7 +1515,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
15131515
1514 return self.memCopy(ty, lhs, rhs);1516 return self.memCopy(ty, lhs, rhs);
1515 },1517 },
1516 .Struct, .Array, .Union => {1518 .Struct, .Array, .Union, .Vector => {
1517 return self.memCopy(ty, lhs, rhs);1519 return self.memCopy(ty, lhs, rhs);
1518 },1520 },
1519 .Pointer => {1521 .Pointer => {
...@@ -2408,9 +2410,9 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2408,9 +2410,9 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2408 const ref_info = ref_ty.intInfo(self.target);2410 const ref_info = ref_ty.intInfo(self.target);
2409 const wanted_info = ty.intInfo(self.target);2411 const wanted_info = ty.intInfo(self.target);
24102412
2411 const op_bits = toWasmIntBits(ref_info.bits) orelse2413 const op_bits = toWasmBits(ref_info.bits) orelse
2412 return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{ref_info.bits});2414 return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{ref_info.bits});
2413 const wanted_bits = toWasmIntBits(wanted_info.bits) orelse2415 const wanted_bits = toWasmBits(wanted_info.bits) orelse
2414 return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{wanted_info.bits});2416 return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{wanted_info.bits});
24152417
2416 // hot path2418 // hot path
...@@ -2651,7 +2653,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2651,7 +2653,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2651 const result = try self.allocLocal(self.air.getRefType(ty_op.ty));2653 const result = try self.allocLocal(self.air.getRefType(ty_op.ty));
2652 const op_bits = op_ty.intInfo(self.target).bits;2654 const op_bits = op_ty.intInfo(self.target).bits;
26532655
2654 const wasm_bits = toWasmIntBits(wanted_bits) orelse2656 const wasm_bits = toWasmBits(wanted_bits) orelse
2655 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{wanted_bits});2657 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{wanted_bits});
26562658
2657 // Use wasm's instruction to wrap from 64bit to 32bit integer when possible2659 // Use wasm's instruction to wrap from 64bit to 32bit integer when possible
...@@ -3182,3 +3184,28 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3182,3 +3184,28 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3182 } else @as(u32, 0);3184 } else @as(u32, 0);
3183 return self.load(operand, tag_ty, offset);3185 return self.load(operand, tag_ty, offset);
3184}3186}
3187
3188fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3189 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3190
3191 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3192 const ty = self.air.typeOfIndex(inst);
3193 const wanted_bits = ty.floatBits(self.target);
3194 const have_bits = self.air.typeOf(ty_op.operand).floatBits(self.target);
3195 const operand = try self.resolveInst(ty_op.operand);
3196
3197 const have = toWasmBits(have_bits) orelse {
3198 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{have_bits});
3199 };
3200 const wanted = toWasmBits(wanted_bits) orelse {
3201 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});
3202 };
3203 if (have == wanted) return operand;
3204
3205 assert(have < wanted);
3206 const result = try self.allocLocal(ty);
3207 try self.emitWValue(operand);
3208 try self.addTag(.f64_promote_f32);
3209 try self.addLabel(.local_set, result.local);
3210 return result;
3211}
src/arch/wasm/Emit.zig+1
...@@ -161,6 +161,7 @@ pub fn emitMir(emit: *Emit) InnerError!void {...@@ -161,6 +161,7 @@ pub fn emitMir(emit: *Emit) InnerError!void {
161 .i64_extend8_s => try emit.emitTag(tag),161 .i64_extend8_s => try emit.emitTag(tag),
162 .i64_extend16_s => try emit.emitTag(tag),162 .i64_extend16_s => try emit.emitTag(tag),
163 .i64_extend32_s => try emit.emitTag(tag),163 .i64_extend32_s => try emit.emitTag(tag),
164 .f64_promote_f32 => try emit.emitTag(tag),
164 .i32_reinterpret_f32 => try emit.emitTag(tag),165 .i32_reinterpret_f32 => try emit.emitTag(tag),
165 .i64_reinterpret_f64 => try emit.emitTag(tag),166 .i64_reinterpret_f64 => try emit.emitTag(tag),
166 .f32_reinterpret_i32 => try emit.emitTag(tag),167 .f32_reinterpret_i32 => try emit.emitTag(tag),
src/arch/wasm/Mir.zig+2
...@@ -391,6 +391,8 @@ pub const Inst = struct {...@@ -391,6 +391,8 @@ pub const Inst = struct {
391 /// Uses `tag`391 /// Uses `tag`
392 i64_trunc_f64_u = 0xB1,392 i64_trunc_f64_u = 0xB1,
393 /// Uses `tag`393 /// Uses `tag`
394 f64_promote_f32 = 0xBB,
395 /// Uses `tag`
394 i32_reinterpret_f32 = 0xBC,396 i32_reinterpret_f32 = 0xBC,
395 /// Uses `tag`397 /// Uses `tag`
396 i64_reinterpret_f64 = 0xBD,398 i64_reinterpret_f64 = 0xBD,
test/behavior/switch.zig-1
...@@ -122,7 +122,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {...@@ -122,7 +122,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
122}122}
123123
124test "switching on booleans" {124test "switching on booleans" {
125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
128127