aboutsummaryrefslogtreecommitdiff
path: root/src/arch/wasm/CodeGen.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-06-06 19:01:39 -0400
committerGitHub <noreply@github.com>2022-06-06 19:01:39 -0400
commitd1bfc83774ffaeeb7646f3003038bc4e4e94f143 (patch)
treecef9979f6d0034dcc3f99567bf12e0b7f3b643c1 /src/arch/wasm/CodeGen.zig
parentbe639eecc209d8039176c9750f28e8c960400fb2 (diff)
parent8ca6dc33d1523061f198474c84a68330085d6667 (diff)
downloadzig-d1bfc83774ffaeeb7646f3003038bc4e4e94f143.tar.gz
zig-d1bfc83774ffaeeb7646f3003038bc4e4e94f143.zip
Merge pull request #11783 from ziglang/stage2-try
introduce a "try" ZIR and AIR instruction
Diffstat (limited to 'src/arch/wasm/CodeGen.zig')
-rw-r--r--src/arch/wasm/CodeGen.zig68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 00907a03c0..da4e84b587 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1490,6 +1490,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.int_to_float => self.airIntToFloat(inst),
.get_union_tag => self.airGetUnionTag(inst),
+ .@"try" => self.airTry(inst),
+ .try_ptr => self.airTryPtr(inst),
+
// TODO
.dbg_inline_begin,
.dbg_inline_end,
@@ -4623,3 +4626,68 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !WValue {
} });
return WValue{ .none = {} };
}
+
+fn airTry(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const err_union = try self.resolveInst(pl_op.operand);
+ const extra = self.air.extraData(Air.Try, pl_op.payload);
+ const body = self.air.extra[extra.end..][0..extra.data.body_len];
+ const err_union_ty = self.air.typeOf(pl_op.operand);
+ return lowerTry(self, err_union, body, err_union_ty, false);
+}
+
+fn airTryPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
+ const err_union_ptr = try self.resolveInst(extra.data.ptr);
+ const body = self.air.extra[extra.end..][0..extra.data.body_len];
+ const err_union_ty = self.air.typeOf(extra.data.ptr).childType();
+ return lowerTry(self, err_union_ptr, body, err_union_ty, true);
+}
+
+fn lowerTry(
+ self: *Self,
+ err_union: WValue,
+ body: []const Air.Inst.Index,
+ err_union_ty: Type,
+ operand_is_ptr: bool,
+) InnerError!WValue {
+ if (operand_is_ptr) {
+ return self.fail("TODO: lowerTry for pointers", .{});
+ }
+
+ if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ return err_union;
+ }
+
+ const pl_ty = err_union_ty.errorUnionPayload();
+ const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime();
+
+ // Block we can jump out of when error is not set
+ try self.startBlock(.block, wasm.block_empty);
+
+ // check if the error tag is set for the error union.
+ try self.emitWValue(err_union);
+ if (pl_has_bits) {
+ const err_offset = @intCast(u32, errUnionErrorOffset(pl_ty, self.target));
+ try self.addMemArg(.i32_load16_u, .{
+ .offset = err_union.offset() + err_offset,
+ .alignment = Type.anyerror.abiAlignment(self.target),
+ });
+ }
+ try self.addTag(.i32_eqz);
+ try self.addLabel(.br_if, 0); // jump out of block when error is '0'
+ try self.genBody(body);
+ try self.endBlock();
+
+ // if we reach here it means error was not set, and we want the payload
+ if (!pl_has_bits) {
+ return WValue{ .none = {} };
+ }
+
+ const pl_offset = @intCast(u32, errUnionPayloadOffset(pl_ty, self.target));
+ if (isByRef(pl_ty, self.target)) {
+ return buildPointerOffset(self, err_union, pl_offset, .new);
+ }
+ return self.load(err_union, pl_ty, pl_offset);
+}