aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-08-11 22:45:15 +0300
committerVeikka Tuominen <git@vexu.eu>2022-08-12 11:40:37 +0300
commit7c9979a02e830a4383995e66ff623a7d07cac091 (patch)
tree81d0cc15b1c60eaf618ea0d3660f7ca81b7b39de /src/codegen
parentfa50e179f7f8d523ff00be4cac90bf7659394140 (diff)
downloadzig-7c9979a02e830a4383995e66ff623a7d07cac091.tar.gz
zig-7c9979a02e830a4383995e66ff623a7d07cac091.zip
stage2: generate a switch for `@errSetCast` safety
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig1
-rw-r--r--src/codegen/llvm.zig48
2 files changed, 49 insertions, 0 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 74e4404bce..81a892183f 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1954,6 +1954,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
=> return f.fail("TODO implement optimized float mode", .{}),
.is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}),
+ .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
// zig fmt: on
};
switch (result_value) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 38f7d285ae..5da3e7e327 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -4247,6 +4247,7 @@ pub const FuncGen = struct {
.prefetch => try self.airPrefetch(inst),
.is_named_enum_value => try self.airIsNamedEnumValue(inst),
+ .error_set_has_value => try self.airErrorSetHasValue(inst),
.reduce => try self.airReduce(inst, false),
.reduce_optimized => try self.airReduce(inst, true),
@@ -7983,6 +7984,53 @@ pub const FuncGen = struct {
}
}
+ fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = try self.resolveInst(ty_op.operand);
+ const error_set_ty = self.air.getRefType(ty_op.ty);
+
+ const names = error_set_ty.errorSetNames();
+ const valid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Valid");
+ const invalid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Invalid");
+ const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
+ const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len));
+
+ for (names) |name| {
+ const err_int = self.dg.module.global_error_set.get(name).?;
+ const this_tag_int_value = int: {
+ var tag_val_payload: Value.Payload.U64 = .{
+ .base = .{ .tag = .int_u64 },
+ .data = err_int,
+ };
+ break :int try self.dg.lowerValue(.{
+ .ty = Type.u16,
+ .val = Value.initPayload(&tag_val_payload.base),
+ });
+ };
+ switch_instr.addCase(this_tag_int_value, valid_block);
+ }
+ self.builder.positionBuilderAtEnd(valid_block);
+ _ = self.builder.buildBr(end_block);
+
+ self.builder.positionBuilderAtEnd(invalid_block);
+ _ = self.builder.buildBr(end_block);
+
+ self.builder.positionBuilderAtEnd(end_block);
+
+ const llvm_type = self.dg.context.intType(1);
+ const incoming_values: [2]*const llvm.Value = .{
+ llvm_type.constInt(1, .False), llvm_type.constInt(0, .False),
+ };
+ const incoming_blocks: [2]*const llvm.BasicBlock = .{
+ valid_block, invalid_block,
+ };
+ const phi_node = self.builder.buildPhi(llvm_type, "");
+ phi_node.addIncoming(&incoming_values, &incoming_blocks, 2);
+ return phi_node;
+ }
+
fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null;