Commit c8fb36b36c
Changed files (17)
src
arch
codegen
test
src/arch/aarch64/CodeGen.zig
@@ -504,133 +504,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
- .add, .ptr_add => try self.airAdd(inst),
- .addwrap => try self.airAddWrap(inst),
- .add_sat => try self.airAddSat(inst),
- .sub, .ptr_sub => try self.airSub(inst),
- .subwrap => try self.airSubWrap(inst),
- .sub_sat => try self.airSubSat(inst),
- .mul => try self.airMul(inst),
- .mulwrap => try self.airMulWrap(inst),
- .mul_sat => try self.airMulSat(inst),
- .rem => try self.airRem(inst),
- .mod => try self.airMod(inst),
- .shl, .shl_exact => try self.airShl(inst),
- .shl_sat => try self.airShlSat(inst),
- .min => try self.airMin(inst),
- .max => try self.airMax(inst),
- .slice => try self.airSlice(inst),
-
- .add_with_overflow => try self.airAddWithOverflow(inst),
- .sub_with_overflow => try self.airSubWithOverflow(inst),
- .mul_with_overflow => try self.airMulWithOverflow(inst),
- .shl_with_overflow => try self.airShlWithOverflow(inst),
-
- .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
-
- .cmp_lt => try self.airCmp(inst, .lt),
- .cmp_lte => try self.airCmp(inst, .lte),
- .cmp_eq => try self.airCmp(inst, .eq),
- .cmp_gte => try self.airCmp(inst, .gte),
- .cmp_gt => try self.airCmp(inst, .gt),
- .cmp_neq => try self.airCmp(inst, .neq),
-
- .bool_and => try self.airBoolOp(inst),
- .bool_or => try self.airBoolOp(inst),
- .bit_and => try self.airBitAnd(inst),
- .bit_or => try self.airBitOr(inst),
- .xor => try self.airXor(inst),
- .shr => try self.airShr(inst),
-
- .alloc => try self.airAlloc(inst),
- .ret_ptr => try self.airRetPtr(inst),
- .arg => try self.airArg(inst),
- .assembly => try self.airAsm(inst),
- .bitcast => try self.airBitCast(inst),
- .block => try self.airBlock(inst),
- .br => try self.airBr(inst),
- .breakpoint => try self.airBreakpoint(),
- .ret_addr => try self.airRetAddr(),
- .fence => try self.airFence(),
- .call => try self.airCall(inst),
- .cond_br => try self.airCondBr(inst),
- .dbg_stmt => try self.airDbgStmt(inst),
- .fptrunc => try self.airFptrunc(inst),
- .fpext => try self.airFpext(inst),
- .intcast => try self.airIntCast(inst),
- .trunc => try self.airTrunc(inst),
- .bool_to_int => try self.airBoolToInt(inst),
- .is_non_null => try self.airIsNonNull(inst),
- .is_non_null_ptr => try self.airIsNonNullPtr(inst),
- .is_null => try self.airIsNull(inst),
- .is_null_ptr => try self.airIsNullPtr(inst),
- .is_non_err => try self.airIsNonErr(inst),
- .is_non_err_ptr => try self.airIsNonErrPtr(inst),
- .is_err => try self.airIsErr(inst),
- .is_err_ptr => try self.airIsErrPtr(inst),
- .load => try self.airLoad(inst),
- .loop => try self.airLoop(inst),
- .not => try self.airNot(inst),
- .ptrtoint => try self.airPtrToInt(inst),
- .ret => try self.airRet(inst),
- .ret_load => try self.airRetLoad(inst),
- .store => try self.airStore(inst),
- .struct_field_ptr=> try self.airStructFieldPtr(inst),
- .struct_field_val=> try self.airStructFieldVal(inst),
- .array_to_slice => try self.airArrayToSlice(inst),
- .int_to_float => try self.airIntToFloat(inst),
- .float_to_int => try self.airFloatToInt(inst),
- .cmpxchg_strong => try self.airCmpxchg(inst),
- .cmpxchg_weak => try self.airCmpxchg(inst),
- .atomic_rmw => try self.airAtomicRmw(inst),
- .atomic_load => try self.airAtomicLoad(inst),
- .memcpy => try self.airMemcpy(inst),
- .memset => try self.airMemset(inst),
- .set_union_tag => try self.airSetUnionTag(inst),
- .get_union_tag => try self.airGetUnionTag(inst),
- .clz => try self.airClz(inst),
- .ctz => try self.airCtz(inst),
- .popcount => try self.airPopcount(inst),
-
- .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
- .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
- .atomic_store_release => try self.airAtomicStore(inst, .Release),
- .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
-
- .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
- .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
- .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
- .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
-
- .switch_br => try self.airSwitch(inst),
- .slice_ptr => try self.airSlicePtr(inst),
- .slice_len => try self.airSliceLen(inst),
-
- .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
- .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
-
- .array_elem_val => try self.airArrayElemVal(inst),
- .slice_elem_val => try self.airSliceElemVal(inst),
- .slice_elem_ptr => try self.airSliceElemPtr(inst),
- .ptr_elem_val => try self.airPtrElemVal(inst),
- .ptr_elem_ptr => try self.airPtrElemPtr(inst),
-
- .constant => unreachable, // excluded from function bodies
- .const_ty => unreachable, // excluded from function bodies
- .unreach => self.finishAirBookkeeping(),
-
- .optional_payload => try self.airOptionalPayload(inst),
- .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
- .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
- .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
- .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
- .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
- .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
-
- .wrap_optional => try self.airWrapOptional(inst),
- .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
- .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
- // zig fmt: on
+ .add, .ptr_add => try self.airAdd(inst),
+ .addwrap => try self.airAddWrap(inst),
+ .add_sat => try self.airAddSat(inst),
+ .sub, .ptr_sub => try self.airSub(inst),
+ .subwrap => try self.airSubWrap(inst),
+ .sub_sat => try self.airSubSat(inst),
+ .mul => try self.airMul(inst),
+ .mulwrap => try self.airMulWrap(inst),
+ .mul_sat => try self.airMulSat(inst),
+ .rem => try self.airRem(inst),
+ .mod => try self.airMod(inst),
+ .shl, .shl_exact => try self.airShl(inst),
+ .shl_sat => try self.airShlSat(inst),
+ .min => try self.airMin(inst),
+ .max => try self.airMax(inst),
+ .slice => try self.airSlice(inst),
+
+ .add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
+ .mul_with_overflow => try self.airMulWithOverflow(inst),
+ .shl_with_overflow => try self.airShlWithOverflow(inst),
+
+ .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
+
+ .cmp_lt => try self.airCmp(inst, .lt),
+ .cmp_lte => try self.airCmp(inst, .lte),
+ .cmp_eq => try self.airCmp(inst, .eq),
+ .cmp_gte => try self.airCmp(inst, .gte),
+ .cmp_gt => try self.airCmp(inst, .gt),
+ .cmp_neq => try self.airCmp(inst, .neq),
+
+ .bool_and => try self.airBoolOp(inst),
+ .bool_or => try self.airBoolOp(inst),
+ .bit_and => try self.airBitAnd(inst),
+ .bit_or => try self.airBitOr(inst),
+ .xor => try self.airXor(inst),
+ .shr => try self.airShr(inst),
+
+ .alloc => try self.airAlloc(inst),
+ .ret_ptr => try self.airRetPtr(inst),
+ .arg => try self.airArg(inst),
+ .assembly => try self.airAsm(inst),
+ .bitcast => try self.airBitCast(inst),
+ .block => try self.airBlock(inst),
+ .br => try self.airBr(inst),
+ .breakpoint => try self.airBreakpoint(),
+ .ret_addr => try self.airRetAddr(),
+ .fence => try self.airFence(),
+ .call => try self.airCall(inst),
+ .cond_br => try self.airCondBr(inst),
+ .dbg_stmt => try self.airDbgStmt(inst),
+ .fptrunc => try self.airFptrunc(inst),
+ .fpext => try self.airFpext(inst),
+ .intcast => try self.airIntCast(inst),
+ .trunc => try self.airTrunc(inst),
+ .bool_to_int => try self.airBoolToInt(inst),
+ .is_non_null => try self.airIsNonNull(inst),
+ .is_non_null_ptr => try self.airIsNonNullPtr(inst),
+ .is_null => try self.airIsNull(inst),
+ .is_null_ptr => try self.airIsNullPtr(inst),
+ .is_non_err => try self.airIsNonErr(inst),
+ .is_non_err_ptr => try self.airIsNonErrPtr(inst),
+ .is_err => try self.airIsErr(inst),
+ .is_err_ptr => try self.airIsErrPtr(inst),
+ .load => try self.airLoad(inst),
+ .loop => try self.airLoop(inst),
+ .not => try self.airNot(inst),
+ .ptrtoint => try self.airPtrToInt(inst),
+ .ret => try self.airRet(inst),
+ .ret_load => try self.airRetLoad(inst),
+ .store => try self.airStore(inst),
+ .struct_field_ptr=> try self.airStructFieldPtr(inst),
+ .struct_field_val=> try self.airStructFieldVal(inst),
+ .array_to_slice => try self.airArrayToSlice(inst),
+ .int_to_float => try self.airIntToFloat(inst),
+ .float_to_int => try self.airFloatToInt(inst),
+ .cmpxchg_strong => try self.airCmpxchg(inst),
+ .cmpxchg_weak => try self.airCmpxchg(inst),
+ .atomic_rmw => try self.airAtomicRmw(inst),
+ .atomic_load => try self.airAtomicLoad(inst),
+ .memcpy => try self.airMemcpy(inst),
+ .memset => try self.airMemset(inst),
+ .set_union_tag => try self.airSetUnionTag(inst),
+ .get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClz(inst),
+ .ctz => try self.airCtz(inst),
+ .popcount => try self.airPopcount(inst),
+ .tag_name => try self.airTagName(inst),
+
+ .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
+ .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
+ .atomic_store_release => try self.airAtomicStore(inst, .Release),
+ .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
+
+ .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+ .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+ .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+ .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
+ .switch_br => try self.airSwitch(inst),
+ .slice_ptr => try self.airSlicePtr(inst),
+ .slice_len => try self.airSliceLen(inst),
+
+ .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
+ .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
+
+ .array_elem_val => try self.airArrayElemVal(inst),
+ .slice_elem_val => try self.airSliceElemVal(inst),
+ .slice_elem_ptr => try self.airSliceElemPtr(inst),
+ .ptr_elem_val => try self.airPtrElemVal(inst),
+ .ptr_elem_ptr => try self.airPtrElemPtr(inst),
+
+ .constant => unreachable, // excluded from function bodies
+ .const_ty => unreachable, // excluded from function bodies
+ .unreach => self.finishAirBookkeeping(),
+
+ .optional_payload => try self.airOptionalPayload(inst),
+ .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
+ .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
+ .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
+ .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
+ .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
+
+ .wrap_optional => try self.airWrapOptional(inst),
+ .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
+ .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+ // zig fmt: on
}
if (std.debug.runtime_safety) {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
@@ -2546,6 +2547,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
}
+fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
+ _ = operand;
+ return self.fail("TODO implement airTagName for aarch64", .{});
+ };
+ return self.finishAir(inst, result, .{ un_op, .none, .none });
+}
+
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);
src/arch/arm/CodeGen.zig
@@ -502,133 +502,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
- .add, .ptr_add => try self.airAdd(inst),
- .addwrap => try self.airAddWrap(inst),
- .add_sat => try self.airAddSat(inst),
- .sub, .ptr_sub => try self.airSub(inst),
- .subwrap => try self.airSubWrap(inst),
- .sub_sat => try self.airSubSat(inst),
- .mul => try self.airMul(inst),
- .mulwrap => try self.airMulWrap(inst),
- .mul_sat => try self.airMulSat(inst),
- .rem => try self.airRem(inst),
- .mod => try self.airMod(inst),
- .shl, .shl_exact => try self.airShl(inst),
- .shl_sat => try self.airShlSat(inst),
- .min => try self.airMin(inst),
- .max => try self.airMax(inst),
- .slice => try self.airSlice(inst),
-
- .add_with_overflow => try self.airAddWithOverflow(inst),
- .sub_with_overflow => try self.airSubWithOverflow(inst),
- .mul_with_overflow => try self.airMulWithOverflow(inst),
- .shl_with_overflow => try self.airShlWithOverflow(inst),
-
- .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
-
- .cmp_lt => try self.airCmp(inst, .lt),
- .cmp_lte => try self.airCmp(inst, .lte),
- .cmp_eq => try self.airCmp(inst, .eq),
- .cmp_gte => try self.airCmp(inst, .gte),
- .cmp_gt => try self.airCmp(inst, .gt),
- .cmp_neq => try self.airCmp(inst, .neq),
-
- .bool_and => try self.airBoolOp(inst),
- .bool_or => try self.airBoolOp(inst),
- .bit_and => try self.airBitAnd(inst),
- .bit_or => try self.airBitOr(inst),
- .xor => try self.airXor(inst),
- .shr => try self.airShr(inst),
-
- .alloc => try self.airAlloc(inst),
- .ret_ptr => try self.airRetPtr(inst),
- .arg => try self.airArg(inst),
- .assembly => try self.airAsm(inst),
- .bitcast => try self.airBitCast(inst),
- .block => try self.airBlock(inst),
- .br => try self.airBr(inst),
- .breakpoint => try self.airBreakpoint(),
- .ret_addr => try self.airRetAddr(),
- .fence => try self.airFence(),
- .call => try self.airCall(inst),
- .cond_br => try self.airCondBr(inst),
- .dbg_stmt => try self.airDbgStmt(inst),
- .fptrunc => try self.airFptrunc(inst),
- .fpext => try self.airFpext(inst),
- .intcast => try self.airIntCast(inst),
- .trunc => try self.airTrunc(inst),
- .bool_to_int => try self.airBoolToInt(inst),
- .is_non_null => try self.airIsNonNull(inst),
- .is_non_null_ptr => try self.airIsNonNullPtr(inst),
- .is_null => try self.airIsNull(inst),
- .is_null_ptr => try self.airIsNullPtr(inst),
- .is_non_err => try self.airIsNonErr(inst),
- .is_non_err_ptr => try self.airIsNonErrPtr(inst),
- .is_err => try self.airIsErr(inst),
- .is_err_ptr => try self.airIsErrPtr(inst),
- .load => try self.airLoad(inst),
- .loop => try self.airLoop(inst),
- .not => try self.airNot(inst),
- .ptrtoint => try self.airPtrToInt(inst),
- .ret => try self.airRet(inst),
- .ret_load => try self.airRetLoad(inst),
- .store => try self.airStore(inst),
- .struct_field_ptr=> try self.airStructFieldPtr(inst),
- .struct_field_val=> try self.airStructFieldVal(inst),
- .array_to_slice => try self.airArrayToSlice(inst),
- .int_to_float => try self.airIntToFloat(inst),
- .float_to_int => try self.airFloatToInt(inst),
- .cmpxchg_strong => try self.airCmpxchg(inst),
- .cmpxchg_weak => try self.airCmpxchg(inst),
- .atomic_rmw => try self.airAtomicRmw(inst),
- .atomic_load => try self.airAtomicLoad(inst),
- .memcpy => try self.airMemcpy(inst),
- .memset => try self.airMemset(inst),
- .set_union_tag => try self.airSetUnionTag(inst),
- .get_union_tag => try self.airGetUnionTag(inst),
- .clz => try self.airClz(inst),
- .ctz => try self.airCtz(inst),
- .popcount => try self.airPopcount(inst),
-
- .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
- .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
- .atomic_store_release => try self.airAtomicStore(inst, .Release),
- .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
-
- .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
- .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
- .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
- .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
-
- .switch_br => try self.airSwitch(inst),
- .slice_ptr => try self.airSlicePtr(inst),
- .slice_len => try self.airSliceLen(inst),
-
- .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
- .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
-
- .array_elem_val => try self.airArrayElemVal(inst),
- .slice_elem_val => try self.airSliceElemVal(inst),
- .slice_elem_ptr => try self.airSliceElemPtr(inst),
- .ptr_elem_val => try self.airPtrElemVal(inst),
- .ptr_elem_ptr => try self.airPtrElemPtr(inst),
-
- .constant => unreachable, // excluded from function bodies
- .const_ty => unreachable, // excluded from function bodies
- .unreach => self.finishAirBookkeeping(),
-
- .optional_payload => try self.airOptionalPayload(inst),
- .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
- .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
- .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
- .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
- .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
- .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
-
- .wrap_optional => try self.airWrapOptional(inst),
- .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
- .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
- // zig fmt: on
+ .add, .ptr_add => try self.airAdd(inst),
+ .addwrap => try self.airAddWrap(inst),
+ .add_sat => try self.airAddSat(inst),
+ .sub, .ptr_sub => try self.airSub(inst),
+ .subwrap => try self.airSubWrap(inst),
+ .sub_sat => try self.airSubSat(inst),
+ .mul => try self.airMul(inst),
+ .mulwrap => try self.airMulWrap(inst),
+ .mul_sat => try self.airMulSat(inst),
+ .rem => try self.airRem(inst),
+ .mod => try self.airMod(inst),
+ .shl, .shl_exact => try self.airShl(inst),
+ .shl_sat => try self.airShlSat(inst),
+ .min => try self.airMin(inst),
+ .max => try self.airMax(inst),
+ .slice => try self.airSlice(inst),
+
+ .add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
+ .mul_with_overflow => try self.airMulWithOverflow(inst),
+ .shl_with_overflow => try self.airShlWithOverflow(inst),
+
+ .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
+
+ .cmp_lt => try self.airCmp(inst, .lt),
+ .cmp_lte => try self.airCmp(inst, .lte),
+ .cmp_eq => try self.airCmp(inst, .eq),
+ .cmp_gte => try self.airCmp(inst, .gte),
+ .cmp_gt => try self.airCmp(inst, .gt),
+ .cmp_neq => try self.airCmp(inst, .neq),
+
+ .bool_and => try self.airBoolOp(inst),
+ .bool_or => try self.airBoolOp(inst),
+ .bit_and => try self.airBitAnd(inst),
+ .bit_or => try self.airBitOr(inst),
+ .xor => try self.airXor(inst),
+ .shr => try self.airShr(inst),
+
+ .alloc => try self.airAlloc(inst),
+ .ret_ptr => try self.airRetPtr(inst),
+ .arg => try self.airArg(inst),
+ .assembly => try self.airAsm(inst),
+ .bitcast => try self.airBitCast(inst),
+ .block => try self.airBlock(inst),
+ .br => try self.airBr(inst),
+ .breakpoint => try self.airBreakpoint(),
+ .ret_addr => try self.airRetAddr(),
+ .fence => try self.airFence(),
+ .call => try self.airCall(inst),
+ .cond_br => try self.airCondBr(inst),
+ .dbg_stmt => try self.airDbgStmt(inst),
+ .fptrunc => try self.airFptrunc(inst),
+ .fpext => try self.airFpext(inst),
+ .intcast => try self.airIntCast(inst),
+ .trunc => try self.airTrunc(inst),
+ .bool_to_int => try self.airBoolToInt(inst),
+ .is_non_null => try self.airIsNonNull(inst),
+ .is_non_null_ptr => try self.airIsNonNullPtr(inst),
+ .is_null => try self.airIsNull(inst),
+ .is_null_ptr => try self.airIsNullPtr(inst),
+ .is_non_err => try self.airIsNonErr(inst),
+ .is_non_err_ptr => try self.airIsNonErrPtr(inst),
+ .is_err => try self.airIsErr(inst),
+ .is_err_ptr => try self.airIsErrPtr(inst),
+ .load => try self.airLoad(inst),
+ .loop => try self.airLoop(inst),
+ .not => try self.airNot(inst),
+ .ptrtoint => try self.airPtrToInt(inst),
+ .ret => try self.airRet(inst),
+ .ret_load => try self.airRetLoad(inst),
+ .store => try self.airStore(inst),
+ .struct_field_ptr=> try self.airStructFieldPtr(inst),
+ .struct_field_val=> try self.airStructFieldVal(inst),
+ .array_to_slice => try self.airArrayToSlice(inst),
+ .int_to_float => try self.airIntToFloat(inst),
+ .float_to_int => try self.airFloatToInt(inst),
+ .cmpxchg_strong => try self.airCmpxchg(inst),
+ .cmpxchg_weak => try self.airCmpxchg(inst),
+ .atomic_rmw => try self.airAtomicRmw(inst),
+ .atomic_load => try self.airAtomicLoad(inst),
+ .memcpy => try self.airMemcpy(inst),
+ .memset => try self.airMemset(inst),
+ .set_union_tag => try self.airSetUnionTag(inst),
+ .get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClz(inst),
+ .ctz => try self.airCtz(inst),
+ .popcount => try self.airPopcount(inst),
+ .tag_name => try self.airTagName(inst),
+
+ .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
+ .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
+ .atomic_store_release => try self.airAtomicStore(inst, .Release),
+ .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
+
+ .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+ .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+ .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+ .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
+ .switch_br => try self.airSwitch(inst),
+ .slice_ptr => try self.airSlicePtr(inst),
+ .slice_len => try self.airSliceLen(inst),
+
+ .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
+ .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
+
+ .array_elem_val => try self.airArrayElemVal(inst),
+ .slice_elem_val => try self.airSliceElemVal(inst),
+ .slice_elem_ptr => try self.airSliceElemPtr(inst),
+ .ptr_elem_val => try self.airPtrElemVal(inst),
+ .ptr_elem_ptr => try self.airPtrElemPtr(inst),
+
+ .constant => unreachable, // excluded from function bodies
+ .const_ty => unreachable, // excluded from function bodies
+ .unreach => self.finishAirBookkeeping(),
+
+ .optional_payload => try self.airOptionalPayload(inst),
+ .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
+ .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
+ .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
+ .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
+ .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
+
+ .wrap_optional => try self.airWrapOptional(inst),
+ .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
+ .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+ // zig fmt: on
}
if (std.debug.runtime_safety) {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
@@ -3301,6 +3302,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
}
+fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
+ _ = operand;
+ return self.fail("TODO implement airTagName for arm", .{});
+ };
+ return self.finishAir(inst, result, .{ un_op, .none, .none });
+}
+
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);
src/arch/riscv64/CodeGen.zig
@@ -483,133 +483,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
- .add, .ptr_add => try self.airAdd(inst),
- .addwrap => try self.airAddWrap(inst),
- .add_sat => try self.airAddSat(inst),
- .sub, .ptr_sub => try self.airSub(inst),
- .subwrap => try self.airSubWrap(inst),
- .sub_sat => try self.airSubSat(inst),
- .mul => try self.airMul(inst),
- .mulwrap => try self.airMulWrap(inst),
- .mul_sat => try self.airMulSat(inst),
- .rem => try self.airRem(inst),
- .mod => try self.airMod(inst),
- .shl, .shl_exact => try self.airShl(inst),
- .shl_sat => try self.airShlSat(inst),
- .min => try self.airMin(inst),
- .max => try self.airMax(inst),
- .slice => try self.airSlice(inst),
-
- .add_with_overflow => try self.airAddWithOverflow(inst),
- .sub_with_overflow => try self.airSubWithOverflow(inst),
- .mul_with_overflow => try self.airMulWithOverflow(inst),
- .shl_with_overflow => try self.airShlWithOverflow(inst),
-
- .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
-
- .cmp_lt => try self.airCmp(inst, .lt),
- .cmp_lte => try self.airCmp(inst, .lte),
- .cmp_eq => try self.airCmp(inst, .eq),
- .cmp_gte => try self.airCmp(inst, .gte),
- .cmp_gt => try self.airCmp(inst, .gt),
- .cmp_neq => try self.airCmp(inst, .neq),
-
- .bool_and => try self.airBoolOp(inst),
- .bool_or => try self.airBoolOp(inst),
- .bit_and => try self.airBitAnd(inst),
- .bit_or => try self.airBitOr(inst),
- .xor => try self.airXor(inst),
- .shr => try self.airShr(inst),
-
- .alloc => try self.airAlloc(inst),
- .ret_ptr => try self.airRetPtr(inst),
- .arg => try self.airArg(inst),
- .assembly => try self.airAsm(inst),
- .bitcast => try self.airBitCast(inst),
- .block => try self.airBlock(inst),
- .br => try self.airBr(inst),
- .breakpoint => try self.airBreakpoint(),
- .ret_addr => try self.airRetAddr(),
- .fence => try self.airFence(),
- .call => try self.airCall(inst),
- .cond_br => try self.airCondBr(inst),
- .dbg_stmt => try self.airDbgStmt(inst),
- .fptrunc => try self.airFptrunc(inst),
- .fpext => try self.airFpext(inst),
- .intcast => try self.airIntCast(inst),
- .trunc => try self.airTrunc(inst),
- .bool_to_int => try self.airBoolToInt(inst),
- .is_non_null => try self.airIsNonNull(inst),
- .is_non_null_ptr => try self.airIsNonNullPtr(inst),
- .is_null => try self.airIsNull(inst),
- .is_null_ptr => try self.airIsNullPtr(inst),
- .is_non_err => try self.airIsNonErr(inst),
- .is_non_err_ptr => try self.airIsNonErrPtr(inst),
- .is_err => try self.airIsErr(inst),
- .is_err_ptr => try self.airIsErrPtr(inst),
- .load => try self.airLoad(inst),
- .loop => try self.airLoop(inst),
- .not => try self.airNot(inst),
- .ptrtoint => try self.airPtrToInt(inst),
- .ret => try self.airRet(inst),
- .ret_load => try self.airRetLoad(inst),
- .store => try self.airStore(inst),
- .struct_field_ptr=> try self.airStructFieldPtr(inst),
- .struct_field_val=> try self.airStructFieldVal(inst),
- .array_to_slice => try self.airArrayToSlice(inst),
- .int_to_float => try self.airIntToFloat(inst),
- .float_to_int => try self.airFloatToInt(inst),
- .cmpxchg_strong => try self.airCmpxchg(inst),
- .cmpxchg_weak => try self.airCmpxchg(inst),
- .atomic_rmw => try self.airAtomicRmw(inst),
- .atomic_load => try self.airAtomicLoad(inst),
- .memcpy => try self.airMemcpy(inst),
- .memset => try self.airMemset(inst),
- .set_union_tag => try self.airSetUnionTag(inst),
- .get_union_tag => try self.airGetUnionTag(inst),
- .clz => try self.airClz(inst),
- .ctz => try self.airCtz(inst),
- .popcount => try self.airPopcount(inst),
-
- .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
- .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
- .atomic_store_release => try self.airAtomicStore(inst, .Release),
- .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
-
- .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
- .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
- .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
- .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
-
- .switch_br => try self.airSwitch(inst),
- .slice_ptr => try self.airSlicePtr(inst),
- .slice_len => try self.airSliceLen(inst),
-
- .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
- .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
-
- .array_elem_val => try self.airArrayElemVal(inst),
- .slice_elem_val => try self.airSliceElemVal(inst),
- .slice_elem_ptr => try self.airSliceElemPtr(inst),
- .ptr_elem_val => try self.airPtrElemVal(inst),
- .ptr_elem_ptr => try self.airPtrElemPtr(inst),
-
- .constant => unreachable, // excluded from function bodies
- .const_ty => unreachable, // excluded from function bodies
- .unreach => self.finishAirBookkeeping(),
-
- .optional_payload => try self.airOptionalPayload(inst),
- .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
- .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
- .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
- .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
- .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
- .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
-
- .wrap_optional => try self.airWrapOptional(inst),
- .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
- .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
- // zig fmt: on
+ .add, .ptr_add => try self.airAdd(inst),
+ .addwrap => try self.airAddWrap(inst),
+ .add_sat => try self.airAddSat(inst),
+ .sub, .ptr_sub => try self.airSub(inst),
+ .subwrap => try self.airSubWrap(inst),
+ .sub_sat => try self.airSubSat(inst),
+ .mul => try self.airMul(inst),
+ .mulwrap => try self.airMulWrap(inst),
+ .mul_sat => try self.airMulSat(inst),
+ .rem => try self.airRem(inst),
+ .mod => try self.airMod(inst),
+ .shl, .shl_exact => try self.airShl(inst),
+ .shl_sat => try self.airShlSat(inst),
+ .min => try self.airMin(inst),
+ .max => try self.airMax(inst),
+ .slice => try self.airSlice(inst),
+
+ .add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
+ .mul_with_overflow => try self.airMulWithOverflow(inst),
+ .shl_with_overflow => try self.airShlWithOverflow(inst),
+
+ .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
+
+ .cmp_lt => try self.airCmp(inst, .lt),
+ .cmp_lte => try self.airCmp(inst, .lte),
+ .cmp_eq => try self.airCmp(inst, .eq),
+ .cmp_gte => try self.airCmp(inst, .gte),
+ .cmp_gt => try self.airCmp(inst, .gt),
+ .cmp_neq => try self.airCmp(inst, .neq),
+
+ .bool_and => try self.airBoolOp(inst),
+ .bool_or => try self.airBoolOp(inst),
+ .bit_and => try self.airBitAnd(inst),
+ .bit_or => try self.airBitOr(inst),
+ .xor => try self.airXor(inst),
+ .shr => try self.airShr(inst),
+
+ .alloc => try self.airAlloc(inst),
+ .ret_ptr => try self.airRetPtr(inst),
+ .arg => try self.airArg(inst),
+ .assembly => try self.airAsm(inst),
+ .bitcast => try self.airBitCast(inst),
+ .block => try self.airBlock(inst),
+ .br => try self.airBr(inst),
+ .breakpoint => try self.airBreakpoint(),
+ .ret_addr => try self.airRetAddr(),
+ .fence => try self.airFence(),
+ .call => try self.airCall(inst),
+ .cond_br => try self.airCondBr(inst),
+ .dbg_stmt => try self.airDbgStmt(inst),
+ .fptrunc => try self.airFptrunc(inst),
+ .fpext => try self.airFpext(inst),
+ .intcast => try self.airIntCast(inst),
+ .trunc => try self.airTrunc(inst),
+ .bool_to_int => try self.airBoolToInt(inst),
+ .is_non_null => try self.airIsNonNull(inst),
+ .is_non_null_ptr => try self.airIsNonNullPtr(inst),
+ .is_null => try self.airIsNull(inst),
+ .is_null_ptr => try self.airIsNullPtr(inst),
+ .is_non_err => try self.airIsNonErr(inst),
+ .is_non_err_ptr => try self.airIsNonErrPtr(inst),
+ .is_err => try self.airIsErr(inst),
+ .is_err_ptr => try self.airIsErrPtr(inst),
+ .load => try self.airLoad(inst),
+ .loop => try self.airLoop(inst),
+ .not => try self.airNot(inst),
+ .ptrtoint => try self.airPtrToInt(inst),
+ .ret => try self.airRet(inst),
+ .ret_load => try self.airRetLoad(inst),
+ .store => try self.airStore(inst),
+ .struct_field_ptr=> try self.airStructFieldPtr(inst),
+ .struct_field_val=> try self.airStructFieldVal(inst),
+ .array_to_slice => try self.airArrayToSlice(inst),
+ .int_to_float => try self.airIntToFloat(inst),
+ .float_to_int => try self.airFloatToInt(inst),
+ .cmpxchg_strong => try self.airCmpxchg(inst),
+ .cmpxchg_weak => try self.airCmpxchg(inst),
+ .atomic_rmw => try self.airAtomicRmw(inst),
+ .atomic_load => try self.airAtomicLoad(inst),
+ .memcpy => try self.airMemcpy(inst),
+ .memset => try self.airMemset(inst),
+ .set_union_tag => try self.airSetUnionTag(inst),
+ .get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClz(inst),
+ .ctz => try self.airCtz(inst),
+ .popcount => try self.airPopcount(inst),
+ .tag_name => try self.airTagName(inst),
+
+ .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
+ .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
+ .atomic_store_release => try self.airAtomicStore(inst, .Release),
+ .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
+
+ .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+ .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+ .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+ .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
+ .switch_br => try self.airSwitch(inst),
+ .slice_ptr => try self.airSlicePtr(inst),
+ .slice_len => try self.airSliceLen(inst),
+
+ .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
+ .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
+
+ .array_elem_val => try self.airArrayElemVal(inst),
+ .slice_elem_val => try self.airSliceElemVal(inst),
+ .slice_elem_ptr => try self.airSliceElemPtr(inst),
+ .ptr_elem_val => try self.airPtrElemVal(inst),
+ .ptr_elem_ptr => try self.airPtrElemPtr(inst),
+
+ .constant => unreachable, // excluded from function bodies
+ .const_ty => unreachable, // excluded from function bodies
+ .unreach => self.finishAirBookkeeping(),
+
+ .optional_payload => try self.airOptionalPayload(inst),
+ .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
+ .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
+ .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
+ .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
+ .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
+
+ .wrap_optional => try self.airWrapOptional(inst),
+ .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
+ .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+ // zig fmt: on
}
if (std.debug.runtime_safety) {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
@@ -2045,6 +2046,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
}
+fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
+ _ = operand;
+ return self.fail("TODO implement airTagName for riscv64", .{});
+ };
+ return self.finishAir(inst, result, .{ un_op, .none, .none });
+}
+
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);
src/arch/x86_64/CodeGen.zig
@@ -538,133 +538,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
- .add, .ptr_add => try self.airAdd(inst),
- .addwrap => try self.airAddWrap(inst),
- .add_sat => try self.airAddSat(inst),
- .sub, .ptr_sub => try self.airSub(inst),
- .subwrap => try self.airSubWrap(inst),
- .sub_sat => try self.airSubSat(inst),
- .mul => try self.airMul(inst),
- .mulwrap => try self.airMulWrap(inst),
- .mul_sat => try self.airMulSat(inst),
- .rem => try self.airRem(inst),
- .mod => try self.airMod(inst),
- .shl, .shl_exact => try self.airShl(inst),
- .shl_sat => try self.airShlSat(inst),
- .min => try self.airMin(inst),
- .max => try self.airMax(inst),
- .slice => try self.airSlice(inst),
-
- .add_with_overflow => try self.airAddWithOverflow(inst),
- .sub_with_overflow => try self.airSubWithOverflow(inst),
- .mul_with_overflow => try self.airMulWithOverflow(inst),
- .shl_with_overflow => try self.airShlWithOverflow(inst),
-
- .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
-
- .cmp_lt => try self.airCmp(inst, .lt),
- .cmp_lte => try self.airCmp(inst, .lte),
- .cmp_eq => try self.airCmp(inst, .eq),
- .cmp_gte => try self.airCmp(inst, .gte),
- .cmp_gt => try self.airCmp(inst, .gt),
- .cmp_neq => try self.airCmp(inst, .neq),
-
- .bool_and => try self.airBoolOp(inst),
- .bool_or => try self.airBoolOp(inst),
- .bit_and => try self.airBitAnd(inst),
- .bit_or => try self.airBitOr(inst),
- .xor => try self.airXor(inst),
- .shr => try self.airShr(inst),
-
- .alloc => try self.airAlloc(inst),
- .ret_ptr => try self.airRetPtr(inst),
- .arg => try self.airArg(inst),
- .assembly => try self.airAsm(inst),
- .bitcast => try self.airBitCast(inst),
- .block => try self.airBlock(inst),
- .br => try self.airBr(inst),
- .breakpoint => try self.airBreakpoint(),
- .ret_addr => try self.airRetAddr(),
- .fence => try self.airFence(),
- .call => try self.airCall(inst),
- .cond_br => try self.airCondBr(inst),
- .dbg_stmt => try self.airDbgStmt(inst),
- .fptrunc => try self.airFptrunc(inst),
- .fpext => try self.airFpext(inst),
- .intcast => try self.airIntCast(inst),
- .trunc => try self.airTrunc(inst),
- .bool_to_int => try self.airBoolToInt(inst),
- .is_non_null => try self.airIsNonNull(inst),
- .is_non_null_ptr => try self.airIsNonNullPtr(inst),
- .is_null => try self.airIsNull(inst),
- .is_null_ptr => try self.airIsNullPtr(inst),
- .is_non_err => try self.airIsNonErr(inst),
- .is_non_err_ptr => try self.airIsNonErrPtr(inst),
- .is_err => try self.airIsErr(inst),
- .is_err_ptr => try self.airIsErrPtr(inst),
- .load => try self.airLoad(inst),
- .loop => try self.airLoop(inst),
- .not => try self.airNot(inst),
- .ptrtoint => try self.airPtrToInt(inst),
- .ret => try self.airRet(inst),
- .ret_load => try self.airRetLoad(inst),
- .store => try self.airStore(inst),
- .struct_field_ptr=> try self.airStructFieldPtr(inst),
- .struct_field_val=> try self.airStructFieldVal(inst),
- .array_to_slice => try self.airArrayToSlice(inst),
- .int_to_float => try self.airIntToFloat(inst),
- .float_to_int => try self.airFloatToInt(inst),
- .cmpxchg_strong => try self.airCmpxchg(inst),
- .cmpxchg_weak => try self.airCmpxchg(inst),
- .atomic_rmw => try self.airAtomicRmw(inst),
- .atomic_load => try self.airAtomicLoad(inst),
- .memcpy => try self.airMemcpy(inst),
- .memset => try self.airMemset(inst),
- .set_union_tag => try self.airSetUnionTag(inst),
- .get_union_tag => try self.airGetUnionTag(inst),
- .clz => try self.airClz(inst),
- .ctz => try self.airCtz(inst),
- .popcount => try self.airPopcount(inst),
-
- .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
- .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
- .atomic_store_release => try self.airAtomicStore(inst, .Release),
- .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
-
- .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
- .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
- .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
- .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
-
- .switch_br => try self.airSwitch(inst),
- .slice_ptr => try self.airSlicePtr(inst),
- .slice_len => try self.airSliceLen(inst),
-
- .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
- .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
-
- .array_elem_val => try self.airArrayElemVal(inst),
- .slice_elem_val => try self.airSliceElemVal(inst),
- .slice_elem_ptr => try self.airSliceElemPtr(inst),
- .ptr_elem_val => try self.airPtrElemVal(inst),
- .ptr_elem_ptr => try self.airPtrElemPtr(inst),
-
- .constant => unreachable, // excluded from function bodies
- .const_ty => unreachable, // excluded from function bodies
- .unreach => self.finishAirBookkeeping(),
-
- .optional_payload => try self.airOptionalPayload(inst),
- .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
- .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
- .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
- .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
- .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
- .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
-
- .wrap_optional => try self.airWrapOptional(inst),
- .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
- .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
- // zig fmt: on
+ .add, .ptr_add => try self.airAdd(inst),
+ .addwrap => try self.airAddWrap(inst),
+ .add_sat => try self.airAddSat(inst),
+ .sub, .ptr_sub => try self.airSub(inst),
+ .subwrap => try self.airSubWrap(inst),
+ .sub_sat => try self.airSubSat(inst),
+ .mul => try self.airMul(inst),
+ .mulwrap => try self.airMulWrap(inst),
+ .mul_sat => try self.airMulSat(inst),
+ .rem => try self.airRem(inst),
+ .mod => try self.airMod(inst),
+ .shl, .shl_exact => try self.airShl(inst),
+ .shl_sat => try self.airShlSat(inst),
+ .min => try self.airMin(inst),
+ .max => try self.airMax(inst),
+ .slice => try self.airSlice(inst),
+
+ .add_with_overflow => try self.airAddWithOverflow(inst),
+ .sub_with_overflow => try self.airSubWithOverflow(inst),
+ .mul_with_overflow => try self.airMulWithOverflow(inst),
+ .shl_with_overflow => try self.airShlWithOverflow(inst),
+
+ .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
+
+ .cmp_lt => try self.airCmp(inst, .lt),
+ .cmp_lte => try self.airCmp(inst, .lte),
+ .cmp_eq => try self.airCmp(inst, .eq),
+ .cmp_gte => try self.airCmp(inst, .gte),
+ .cmp_gt => try self.airCmp(inst, .gt),
+ .cmp_neq => try self.airCmp(inst, .neq),
+
+ .bool_and => try self.airBoolOp(inst),
+ .bool_or => try self.airBoolOp(inst),
+ .bit_and => try self.airBitAnd(inst),
+ .bit_or => try self.airBitOr(inst),
+ .xor => try self.airXor(inst),
+ .shr => try self.airShr(inst),
+
+ .alloc => try self.airAlloc(inst),
+ .ret_ptr => try self.airRetPtr(inst),
+ .arg => try self.airArg(inst),
+ .assembly => try self.airAsm(inst),
+ .bitcast => try self.airBitCast(inst),
+ .block => try self.airBlock(inst),
+ .br => try self.airBr(inst),
+ .breakpoint => try self.airBreakpoint(),
+ .ret_addr => try self.airRetAddr(),
+ .fence => try self.airFence(),
+ .call => try self.airCall(inst),
+ .cond_br => try self.airCondBr(inst),
+ .dbg_stmt => try self.airDbgStmt(inst),
+ .fptrunc => try self.airFptrunc(inst),
+ .fpext => try self.airFpext(inst),
+ .intcast => try self.airIntCast(inst),
+ .trunc => try self.airTrunc(inst),
+ .bool_to_int => try self.airBoolToInt(inst),
+ .is_non_null => try self.airIsNonNull(inst),
+ .is_non_null_ptr => try self.airIsNonNullPtr(inst),
+ .is_null => try self.airIsNull(inst),
+ .is_null_ptr => try self.airIsNullPtr(inst),
+ .is_non_err => try self.airIsNonErr(inst),
+ .is_non_err_ptr => try self.airIsNonErrPtr(inst),
+ .is_err => try self.airIsErr(inst),
+ .is_err_ptr => try self.airIsErrPtr(inst),
+ .load => try self.airLoad(inst),
+ .loop => try self.airLoop(inst),
+ .not => try self.airNot(inst),
+ .ptrtoint => try self.airPtrToInt(inst),
+ .ret => try self.airRet(inst),
+ .ret_load => try self.airRetLoad(inst),
+ .store => try self.airStore(inst),
+ .struct_field_ptr=> try self.airStructFieldPtr(inst),
+ .struct_field_val=> try self.airStructFieldVal(inst),
+ .array_to_slice => try self.airArrayToSlice(inst),
+ .int_to_float => try self.airIntToFloat(inst),
+ .float_to_int => try self.airFloatToInt(inst),
+ .cmpxchg_strong => try self.airCmpxchg(inst),
+ .cmpxchg_weak => try self.airCmpxchg(inst),
+ .atomic_rmw => try self.airAtomicRmw(inst),
+ .atomic_load => try self.airAtomicLoad(inst),
+ .memcpy => try self.airMemcpy(inst),
+ .memset => try self.airMemset(inst),
+ .set_union_tag => try self.airSetUnionTag(inst),
+ .get_union_tag => try self.airGetUnionTag(inst),
+ .clz => try self.airClz(inst),
+ .ctz => try self.airCtz(inst),
+ .popcount => try self.airPopcount(inst),
+ .tag_name => try self.airTagName(inst),
+
+ .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
+ .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
+ .atomic_store_release => try self.airAtomicStore(inst, .Release),
+ .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
+
+ .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+ .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+ .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+ .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
+ .switch_br => try self.airSwitch(inst),
+ .slice_ptr => try self.airSlicePtr(inst),
+ .slice_len => try self.airSliceLen(inst),
+
+ .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
+ .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
+
+ .array_elem_val => try self.airArrayElemVal(inst),
+ .slice_elem_val => try self.airSliceElemVal(inst),
+ .slice_elem_ptr => try self.airSliceElemPtr(inst),
+ .ptr_elem_val => try self.airPtrElemVal(inst),
+ .ptr_elem_ptr => try self.airPtrElemPtr(inst),
+
+ .constant => unreachable, // excluded from function bodies
+ .const_ty => unreachable, // excluded from function bodies
+ .unreach => self.finishAirBookkeeping(),
+
+ .optional_payload => try self.airOptionalPayload(inst),
+ .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
+ .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
+ .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
+ .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
+ .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
+
+ .wrap_optional => try self.airWrapOptional(inst),
+ .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
+ .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+ // zig fmt: on
}
if (std.debug.runtime_safety) {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
@@ -3174,6 +3175,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
}
+fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
+ _ = operand;
+ return self.fail("TODO implement airTagName for x86_64", .{});
+ };
+ return self.finishAir(inst, result, .{ un_op, .none, .none });
+}
+
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);
src/codegen/llvm/bindings.zig
@@ -785,8 +785,23 @@ pub const Builder = opaque {
pub const buildExactSDiv = LLVMBuildExactSDiv;
extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const zigSetCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
+ extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void;
+
+ pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
+ extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;
+
+ pub const getCurrentDebugLocation2 = LLVMGetCurrentDebugLocation2;
+ extern fn LLVMGetCurrentDebugLocation2(Builder: *const Builder) *Metadata;
+
+ pub const setCurrentDebugLocation2 = LLVMSetCurrentDebugLocation2;
+ extern fn LLVMSetCurrentDebugLocation2(Builder: *const Builder, Loc: *Metadata) void;
};
+pub const DIScope = opaque {};
+pub const Metadata = opaque {};
+
pub const IntPredicate = enum(c_uint) {
EQ = 32,
NE = 33,
src/codegen/c.zig
@@ -1230,6 +1230,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.clz => try airBuiltinCall(f, inst, "clz"),
.ctz => try airBuiltinCall(f, inst, "ctz"),
.popcount => try airBuiltinCall(f, inst, "popcount"),
+ .tag_name => try airTagName(f, inst),
.int_to_float,
.float_to_int,
@@ -2914,6 +2915,24 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
+fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
+ const un_op = f.air.instructions.items(.data)[inst].un_op;
+ const writer = f.object.writer();
+ const inst_ty = f.air.typeOfIndex(inst);
+ const operand = try f.resolveInst(un_op);
+ const local = try f.allocLocal(inst_ty, .Const);
+
+ try writer.writeAll(" = ");
+
+ _ = operand;
+ _ = local;
+ return f.fail("TODO: C backend: implement airTagName", .{});
+ //try writer.writeAll(";\n");
+ //return local;
+}
+
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
return switch (order) {
.Unordered => "memory_order_relaxed",
src/codegen/llvm.zig
@@ -636,15 +636,6 @@ pub const DeclGen = struct {
llvm_param_i += 1;
}
- if (dg.module.comp.bin_file.options.skip_linker_dependencies) {
- // The intent here is for compiler-rt and libc functions to not generate
- // infinite recursion. For example, if we are compiling the memcpy function,
- // and llvm detects that the body is equivalent to memcpy, it may replace the
- // body of memcpy with a call to memcpy, which would then cause a stack
- // overflow instead of performing memcpy.
- dg.addFnAttr(llvm_fn, "nobuiltin");
- }
-
// TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
if (fn_info.cc == .Naked) {
dg.addFnAttr(llvm_fn, "naked");
@@ -653,6 +644,16 @@ pub const DeclGen = struct {
}
// Function attributes that are independent of analysis results of the function body.
+ dg.addCommonFnAttributes(llvm_fn);
+
+ if (return_type.isNoReturn()) {
+ dg.addFnAttr(llvm_fn, "noreturn");
+ }
+
+ return llvm_fn;
+ }
+
+ fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *const llvm.Value) void {
if (!dg.module.comp.bin_file.options.red_zone) {
dg.addFnAttr(llvm_fn, "noredzone");
}
@@ -665,6 +666,14 @@ pub const DeclGen = struct {
if (dg.module.comp.unwind_tables) {
dg.addFnAttr(llvm_fn, "uwtable");
}
+ if (dg.module.comp.bin_file.options.skip_linker_dependencies) {
+ // The intent here is for compiler-rt and libc functions to not generate
+ // infinite recursion. For example, if we are compiling the memcpy function,
+ // and llvm detects that the body is equivalent to memcpy, it may replace the
+ // body of memcpy with a call to memcpy, which would then cause a stack
+ // overflow instead of performing memcpy.
+ dg.addFnAttr(llvm_fn, "nobuiltin");
+ }
if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) {
dg.addFnAttr(llvm_fn, "minsize");
dg.addFnAttr(llvm_fn, "optsize");
@@ -673,11 +682,6 @@ pub const DeclGen = struct {
dg.addFnAttr(llvm_fn, "sanitize_thread");
}
// TODO add target-cpu and target-features fn attributes
- if (return_type.isNoReturn()) {
- dg.addFnAttr(llvm_fn, "noreturn");
- }
-
- return llvm_fn;
}
fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value {
@@ -1958,6 +1962,7 @@ pub const FuncGen = struct {
.clz => try self.airClzCtz(inst, "ctlz"),
.ctz => try self.airClzCtz(inst, "cttz"),
.popcount => try self.airPopCount(inst, "ctpop"),
+ .tag_name => try self.airTagName(inst),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -4093,6 +4098,119 @@ pub const FuncGen = struct {
}
}
+ fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
+ defer arena_allocator.deinit();
+ const arena = arena_allocator.allocator();
+
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = try self.resolveInst(un_op);
+ const enum_ty = self.air.typeOf(un_op);
+
+ const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{
+ try enum_ty.getOwnerDecl().getFullyQualifiedName(arena),
+ });
+
+ const llvm_fn = try self.getEnumTagNameFunction(enum_ty, llvm_fn_name);
+ const params = [_]*const llvm.Value{operand};
+ return self.builder.buildCall(llvm_fn, ¶ms, params.len, .Fast, .Auto, "");
+ }
+
+ fn getEnumTagNameFunction(
+ self: *FuncGen,
+ enum_ty: Type,
+ llvm_fn_name: [:0]const u8,
+ ) !*const llvm.Value {
+ // TODO: detect when the type changes and re-emit this function.
+ if (self.dg.object.llvm_module.getNamedFunction(llvm_fn_name)) |llvm_fn| {
+ return llvm_fn;
+ }
+
+ const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
+ const llvm_ret_ty = try self.dg.llvmType(slice_ty);
+ const usize_llvm_ty = try self.dg.llvmType(Type.usize);
+ const target = self.dg.module.getTarget();
+ const slice_alignment = slice_ty.abiAlignment(target);
+
+ var int_tag_type_buffer: Type.Payload.Bits = undefined;
+ const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
+ const param_types = [_]*const llvm.Type{try self.dg.llvmType(int_tag_ty)};
+
+ const fn_type = llvm.functionType(llvm_ret_ty, ¶m_types, param_types.len, .False);
+ const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
+ fn_val.setLinkage(.Internal);
+ fn_val.setFunctionCallConv(.Fast);
+ self.dg.addCommonFnAttributes(fn_val);
+
+ const prev_block = self.builder.getInsertBlock();
+ const prev_debug_location = self.builder.getCurrentDebugLocation2();
+ defer {
+ self.builder.positionBuilderAtEnd(prev_block);
+ if (!self.dg.module.comp.bin_file.options.strip) {
+ self.builder.setCurrentDebugLocation2(prev_debug_location);
+ }
+ }
+
+ const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry");
+ self.builder.positionBuilderAtEnd(entry_block);
+ self.builder.clearCurrentDebugLocation();
+
+ const fields = enum_ty.enumFields();
+ const bad_value_block = self.dg.context.appendBasicBlock(fn_val, "BadValue");
+ const tag_int_value = fn_val.getParam(0);
+ const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count()));
+
+ const array_ptr_indices = [_]*const llvm.Value{
+ usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
+ };
+
+ for (fields.keys()) |name, field_index| {
+ const str_init = self.dg.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
+ const str_global = self.dg.object.llvm_module.addGlobal(str_init.typeOf(), "");
+ str_global.setInitializer(str_init);
+ str_global.setLinkage(.Private);
+ str_global.setGlobalConstant(.True);
+ str_global.setUnnamedAddr(.True);
+ str_global.setAlignment(1);
+
+ const slice_fields = [_]*const llvm.Value{
+ str_global.constInBoundsGEP(&array_ptr_indices, array_ptr_indices.len),
+ usize_llvm_ty.constInt(name.len, .False),
+ };
+ const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);
+ const slice_global = self.dg.object.llvm_module.addGlobal(slice_init.typeOf(), "");
+ slice_global.setInitializer(slice_init);
+ slice_global.setLinkage(.Private);
+ slice_global.setGlobalConstant(.True);
+ slice_global.setUnnamedAddr(.True);
+ slice_global.setAlignment(slice_alignment);
+
+ const return_block = self.dg.context.appendBasicBlock(fn_val, "Name");
+ const this_tag_int_value = int: {
+ var tag_val_payload: Value.Payload.U32 = .{
+ .base = .{ .tag = .enum_field_index },
+ .data = @intCast(u32, field_index),
+ };
+ break :int try self.dg.genTypedValue(.{
+ .ty = enum_ty,
+ .val = Value.initPayload(&tag_val_payload.base),
+ });
+ };
+ switch_instr.addCase(this_tag_int_value, return_block);
+
+ self.builder.positionBuilderAtEnd(return_block);
+ const loaded = self.builder.buildLoad(slice_global, "");
+ loaded.setAlignment(slice_alignment);
+ _ = self.builder.buildRet(loaded);
+ }
+
+ self.builder.positionBuilderAtEnd(bad_value_block);
+ _ = self.builder.buildUnreachable();
+ return fn_val;
+ }
+
/// Assumes the optional is not pointer-like and payload has bits.
fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
if (is_by_ref) {
src/Air.zig
@@ -496,6 +496,11 @@ pub const Inst = struct {
/// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
atomic_rmw,
+ /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive.
+ /// Result type is always `[:0]const u8`.
+ /// Uses the `un_op` field.
+ tag_name,
+
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
return switch (op) {
.lt => .cmp_lt,
@@ -811,6 +816,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.bool_to_int => return Type.initTag(.u1),
+ .tag_name => return Type.initTag(.const_slice_u8_sentinel_0),
+
.call => {
const callee_ty = air.typeOf(datas[inst].pl_op.operand);
switch (callee_ty.zigTypeTag()) {
src/Liveness.zig
@@ -333,6 +333,7 @@ fn analyzeInst(
.bool_to_int,
.ret,
.ret_load,
+ .tag_name,
=> {
const operand = inst_datas[inst].un_op;
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/print_air.zig
@@ -155,6 +155,7 @@ const Writer = struct {
.bool_to_int,
.ret,
.ret_load,
+ .tag_name,
=> try w.writeUnOp(s, inst),
.breakpoint,
src/Sema.zig
@@ -2804,8 +2804,11 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const tracy = trace(@src());
defer tracy.end();
- const zir_bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
+ const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
+ return sema.addStrLit(block, bytes);
+}
+fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref {
// `zir_bytes` references memory inside the ZIR module, which can get deallocated
// after semantic analysis is complete, for example in the case of the initialization
// expression of a variable declaration. We need the memory to be in the new
@@ -10045,8 +10048,50 @@ fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const src = inst_data.src();
- return sema.fail(block, src, "TODO: Sema.zirTagName", .{});
+ const operand = sema.resolveInst(inst_data.operand);
+ const operand_ty = sema.typeOf(operand);
+
+ const enum_ty = switch (operand_ty.zigTypeTag()) {
+ .Enum => operand_ty,
+ .Union => operand_ty.unionTagType() orelse {
+ const decl = operand_ty.getOwnerDecl();
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "union '{s}' is untagged", .{
+ decl.name,
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ },
+ else => return sema.fail(block, operand_src, "expected enum or union; found {}", .{
+ operand_ty,
+ }),
+ };
+ const enum_decl = enum_ty.getOwnerDecl();
+ const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
+ if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
+ const field_index = enum_ty.enumTagFieldIndex(val) orelse {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "no field with value {} in enum '{s}'", .{
+ casted_operand, enum_decl.name,
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ };
+ const field_name = enum_ty.enumFieldName(field_index);
+ return sema.addStrLit(block, field_name);
+ }
+ // In case the value is runtime-known, we have an AIR instruction for this instead
+ // of trying to lower it in Sema because an optimization pass may result in the operand
+ // being comptime-known, which would let us elide the `tag_name` AIR instruction.
+ return block.addUnOp(.tag_name, casted_operand);
}
fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -15339,6 +15384,7 @@ fn typeHasOnePossibleValue(
.array_sentinel,
.array_u8_sentinel_0,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.const_slice,
.mut_slice,
.anyopaque,
@@ -15356,6 +15402,7 @@ fn typeHasOnePossibleValue(
.var_args_param,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
src/type.zig
@@ -94,6 +94,7 @@ pub const Type = extern union {
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -107,6 +108,7 @@ pub const Type = extern union {
.inferred_alloc_mut,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> return .Pointer,
.optional,
@@ -254,6 +256,7 @@ pub const Type = extern union {
.optional_single_mut_pointer,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> self.cast(Payload.ElemType),
.inferred_alloc_const => unreachable,
@@ -275,9 +278,11 @@ pub const Type = extern union {
return switch (ty.tag()) {
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.single_const_pointer,
.many_const_pointer,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.c_const_pointer,
.const_slice,
=> false,
@@ -330,6 +335,18 @@ pub const Type = extern union {
.@"volatile" = false,
.size = .Slice,
} },
+ .const_slice_u8_sentinel_0 => return .{ .data = .{
+ .pointee_type = Type.initTag(.u8),
+ .sentinel = Value.zero,
+ .@"align" = 0,
+ .@"addrspace" = .generic,
+ .bit_offset = 0,
+ .host_size = 0,
+ .@"allowzero" = false,
+ .mutable = false,
+ .@"volatile" = false,
+ .size = .Slice,
+ } },
.single_const_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
@@ -378,6 +395,18 @@ pub const Type = extern union {
.@"volatile" = false,
.size = .Many,
} },
+ .manyptr_const_u8_sentinel_0 => return .{ .data = .{
+ .pointee_type = Type.initTag(.u8),
+ .sentinel = Value.zero,
+ .@"align" = 0,
+ .@"addrspace" = .generic,
+ .bit_offset = 0,
+ .host_size = 0,
+ .@"allowzero" = false,
+ .mutable = false,
+ .@"volatile" = false,
+ .size = .Many,
+ } },
.many_mut_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
@@ -784,6 +813,7 @@ pub const Type = extern union {
.fn_ccc_void_no_args,
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.enum_literal,
.anyerror_void_error_union,
.inferred_alloc_const,
@@ -792,6 +822,7 @@ pub const Type = extern union {
.empty_struct_literal,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
@@ -1016,6 +1047,7 @@ pub const Type = extern union {
.anyerror_void_error_union => return writer.writeAll("anyerror!void"),
.const_slice_u8 => return writer.writeAll("[]const u8"),
+ .const_slice_u8_sentinel_0 => return writer.writeAll("[:0]const u8"),
.fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
.fn_void_no_args => return writer.writeAll("fn() void"),
.fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
@@ -1023,6 +1055,7 @@ pub const Type = extern union {
.single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
.manyptr_u8 => return writer.writeAll("[*]u8"),
.manyptr_const_u8 => return writer.writeAll("[*]const u8"),
+ .manyptr_const_u8_sentinel_0 => return writer.writeAll("[*:0]const u8"),
.atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
.atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
.calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
@@ -1308,6 +1341,7 @@ pub const Type = extern union {
.anyerror_void_error_union => return "anyerror!void",
.const_slice_u8 => return "[]const u8",
+ .const_slice_u8_sentinel_0 => return "[:0]const u8",
.fn_noreturn_no_args => return "fn() noreturn",
.fn_void_no_args => return "fn() void",
.fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
@@ -1315,6 +1349,7 @@ pub const Type = extern union {
.single_const_pointer_to_comptime_int => return "*const comptime_int",
.manyptr_u8 => return "[*]u8",
.manyptr_const_u8 => return "[*]const u8",
+ .manyptr_const_u8_sentinel_0 => return "[*:0]const u8",
.atomic_order => return "AtomicOrder",
.atomic_rmw_op => return "AtomicRmwOp",
.calling_convention => return "CallingConvention",
@@ -1386,11 +1421,13 @@ pub const Type = extern union {
.extern_options,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.fn_noreturn_no_args,
.fn_void_no_args,
.fn_naked_noreturn_no_args,
.fn_ccc_void_no_args,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.anyerror_void_error_union,
.empty_struct_literal,
.function,
@@ -1498,9 +1535,11 @@ pub const Type = extern union {
.fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
+ .const_slice_u8_sentinel_0 => return Value.initTag(.const_slice_u8_sentinel_0_type),
.enum_literal => return Value.initTag(.enum_literal_type),
.manyptr_u8 => return Value.initTag(.manyptr_u8_type),
.manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type),
+ .manyptr_const_u8_sentinel_0 => return Value.initTag(.manyptr_const_u8_sentinel_0_type),
.atomic_order => return Value.initTag(.atomic_order_type),
.atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
.calling_convention => return Value.initTag(.calling_convention_type),
@@ -1550,6 +1589,7 @@ pub const Type = extern union {
.anyerror,
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.array_u8_sentinel_0,
.optional,
.optional_single_mut_pointer,
@@ -1561,6 +1601,7 @@ pub const Type = extern union {
.error_set_merged,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
@@ -1703,7 +1744,9 @@ pub const Type = extern union {
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
=> return 1,
.pointer => {
@@ -1723,6 +1766,7 @@ pub const Type = extern union {
return switch (self.tag()) {
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -1735,6 +1779,7 @@ pub const Type = extern union {
.inferred_alloc_mut,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> .generic,
.pointer => self.castTag(.pointer).?.data.@"addrspace",
@@ -1785,6 +1830,7 @@ pub const Type = extern union {
.usize,
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -1798,6 +1844,7 @@ pub const Type = extern union {
.pointer,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.@"anyframe",
.anyframe_T,
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
@@ -2050,7 +2097,9 @@ pub const Type = extern union {
if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
},
- .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
+ .const_slice_u8,
+ .const_slice_u8_sentinel_0,
+ => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
.optional_single_const_pointer,
.optional_single_mut_pointer,
@@ -2068,6 +2117,7 @@ pub const Type = extern union {
.pointer,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
.c_short => return @divExact(CType.short.sizeInBits(target), 8),
@@ -2223,7 +2273,9 @@ pub const Type = extern union {
return target.cpu.arch.ptrBitWidth();
}
},
- .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2,
+ .const_slice_u8,
+ .const_slice_u8_sentinel_0,
+ => target.cpu.arch.ptrBitWidth() * 2,
.optional_single_const_pointer,
.optional_single_mut_pointer,
@@ -2252,6 +2304,7 @@ pub const Type = extern union {
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> return target.cpu.arch.ptrBitWidth(),
.c_short => return CType.short.sizeInBits(target),
@@ -2337,12 +2390,14 @@ pub const Type = extern union {
.const_slice,
.mut_slice,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
=> .Slice,
.many_const_pointer,
.many_mut_pointer,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> .Many,
.c_const_pointer,
@@ -2367,6 +2422,7 @@ pub const Type = extern union {
.const_slice,
.mut_slice,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
=> true,
.pointer => self.castTag(.pointer).?.data.size == .Slice,
@@ -2383,6 +2439,7 @@ pub const Type = extern union {
pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {
switch (self.tag()) {
.const_slice_u8 => return Type.initTag(.manyptr_const_u8),
+ .const_slice_u8_sentinel_0 => return Type.initTag(.manyptr_const_u8_sentinel_0),
.const_slice => {
const elem_type = self.castTag(.const_slice).?.data;
@@ -2464,8 +2521,10 @@ pub const Type = extern union {
.c_const_pointer,
.single_const_pointer_to_comptime_int,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.const_slice,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
=> true,
.pointer => !self.castTag(.pointer).?.data.mutable,
@@ -2513,6 +2572,7 @@ pub const Type = extern union {
.many_const_pointer,
.many_mut_pointer,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.manyptr_u8,
.optional_single_const_pointer,
.optional_single_mut_pointer,
@@ -2648,9 +2708,11 @@ pub const Type = extern union {
.array_u8,
.array_u8_sentinel_0,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.manyptr_u8,
.manyptr_const_u8,
- => Type.initTag(.u8),
+ .manyptr_const_u8_sentinel_0,
+ => Type.u8,
.single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
.pointer => ty.castTag(.pointer).?.data.pointee_type,
@@ -2690,9 +2752,11 @@ pub const Type = extern union {
.array_u8,
.array_u8_sentinel_0,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.manyptr_u8,
.manyptr_const_u8,
- => Type.initTag(.u8),
+ .manyptr_const_u8_sentinel_0,
+ => Type.u8,
.single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
.pointer => {
@@ -2937,7 +3001,11 @@ pub const Type = extern union {
.pointer => return self.castTag(.pointer).?.data.sentinel,
.array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
- .array_u8_sentinel_0 => return Value.zero,
+
+ .array_u8_sentinel_0,
+ .const_slice_u8_sentinel_0,
+ .manyptr_const_u8_sentinel_0,
+ => return Value.zero,
else => unreachable,
};
@@ -3309,6 +3377,7 @@ pub const Type = extern union {
.array_sentinel,
.array_u8_sentinel_0,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.const_slice,
.mut_slice,
.anyopaque,
@@ -3326,6 +3395,7 @@ pub const Type = extern union {
.var_args_param,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
@@ -3956,12 +4026,14 @@ pub const Type = extern union {
type_info,
manyptr_u8,
manyptr_const_u8,
+ manyptr_const_u8_sentinel_0,
fn_noreturn_no_args,
fn_void_no_args,
fn_naked_noreturn_no_args,
fn_ccc_void_no_args,
single_const_pointer_to_comptime_int,
const_slice_u8,
+ const_slice_u8_sentinel_0,
anyerror_void_error_union,
generic_poison,
/// This is a special type for variadic parameters of a function call.
@@ -4064,6 +4136,7 @@ pub const Type = extern union {
.single_const_pointer_to_comptime_int,
.anyerror_void_error_union,
.const_slice_u8,
+ .const_slice_u8_sentinel_0,
.generic_poison,
.inferred_alloc_const,
.inferred_alloc_mut,
@@ -4071,6 +4144,7 @@ pub const Type = extern union {
.empty_struct_literal,
.manyptr_u8,
.manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
@@ -4322,36 +4396,55 @@ pub const Type = extern union {
pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type {
assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);
+ if (d.size == .C) {
+ assert(d.@"allowzero"); // All C pointers must set allowzero to true.
+ }
- if (d.sentinel != null or d.@"align" != 0 or d.@"addrspace" != .generic or
- d.bit_offset != 0 or d.host_size != 0 or d.@"allowzero" or d.@"volatile")
+ if (d.@"align" == 0 and d.@"addrspace" == .generic and
+ d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile")
{
- if (d.size == .C) {
- assert(d.@"allowzero"); // All C pointers must set allowzero to true.
+ if (d.sentinel) |sent| {
+ if (!d.mutable and d.pointee_type.eql(Type.u8)) {
+ switch (d.size) {
+ .Slice => {
+ if (sent.compareWithZero(.eq)) {
+ return Type.initTag(.const_slice_u8_sentinel_0);
+ }
+ },
+ .Many => {
+ if (sent.compareWithZero(.eq)) {
+ return Type.initTag(.manyptr_const_u8_sentinel_0);
+ }
+ },
+ else => {},
+ }
+ }
+ } else if (!d.mutable and d.pointee_type.eql(Type.u8)) {
+ switch (d.size) {
+ .Slice => return Type.initTag(.const_slice_u8),
+ .Many => return Type.initTag(.manyptr_const_u8),
+ else => {},
+ }
+ } else {
+ // TODO stage1 type inference bug
+ const T = Type.Tag;
+
+ const type_payload = try arena.create(Type.Payload.ElemType);
+ type_payload.* = .{
+ .base = .{
+ .tag = switch (d.size) {
+ .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer,
+ .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer,
+ .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer,
+ .Slice => if (d.mutable) T.mut_slice else T.const_slice,
+ },
+ },
+ .data = d.pointee_type,
+ };
+ return Type.initPayload(&type_payload.base);
}
- return Type.Tag.pointer.create(arena, d);
- }
-
- if (!d.mutable and d.size == .Slice and d.pointee_type.eql(Type.initTag(.u8))) {
- return Type.initTag(.const_slice_u8);
}
-
- // TODO stage1 type inference bug
- const T = Type.Tag;
-
- const type_payload = try arena.create(Type.Payload.ElemType);
- type_payload.* = .{
- .base = .{
- .tag = switch (d.size) {
- .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer,
- .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer,
- .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer,
- .Slice => if (d.mutable) T.mut_slice else T.const_slice,
- },
- },
- .data = d.pointee_type,
- };
- return Type.initPayload(&type_payload.base);
+ return Type.Tag.pointer.create(arena, d);
}
pub fn array(
src/value.zig
@@ -73,12 +73,14 @@ pub const Value = extern union {
type_info_type,
manyptr_u8_type,
manyptr_const_u8_type,
+ manyptr_const_u8_sentinel_0_type,
fn_noreturn_no_args_type,
fn_void_no_args_type,
fn_naked_noreturn_no_args_type,
fn_ccc_void_no_args_type,
single_const_pointer_to_comptime_int_type,
const_slice_u8_type,
+ const_slice_u8_sentinel_0_type,
anyerror_void_error_union_type,
generic_poison_type,
@@ -221,6 +223,7 @@ pub const Value = extern union {
.single_const_pointer_to_comptime_int_type,
.anyframe_type,
.const_slice_u8_type,
+ .const_slice_u8_sentinel_0_type,
.anyerror_void_error_union_type,
.generic_poison_type,
.enum_literal_type,
@@ -238,6 +241,7 @@ pub const Value = extern union {
.abi_align_default,
.manyptr_u8_type,
.manyptr_const_u8_type,
+ .manyptr_const_u8_sentinel_0_type,
.atomic_order_type,
.atomic_rmw_op_type,
.calling_convention_type,
@@ -412,6 +416,7 @@ pub const Value = extern union {
.single_const_pointer_to_comptime_int_type,
.anyframe_type,
.const_slice_u8_type,
+ .const_slice_u8_sentinel_0_type,
.anyerror_void_error_union_type,
.generic_poison_type,
.enum_literal_type,
@@ -429,6 +434,7 @@ pub const Value = extern union {
.abi_align_default,
.manyptr_u8_type,
.manyptr_const_u8_type,
+ .manyptr_const_u8_sentinel_0_type,
.atomic_order_type,
.atomic_rmw_op_type,
.calling_convention_type,
@@ -642,12 +648,14 @@ pub const Value = extern union {
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
.anyframe_type => return out_stream.writeAll("anyframe"),
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
+ .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"),
.anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),
.generic_poison_type => return out_stream.writeAll("(generic poison type)"),
.generic_poison => return out_stream.writeAll("(generic poison)"),
.enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
.manyptr_u8_type => return out_stream.writeAll("[*]u8"),
.manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
+ .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"),
.atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
.atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
.calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
@@ -821,11 +829,13 @@ pub const Value = extern union {
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
.anyframe_type => Type.initTag(.@"anyframe"),
.const_slice_u8_type => Type.initTag(.const_slice_u8),
+ .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0),
.anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),
.generic_poison_type => Type.initTag(.generic_poison),
.enum_literal_type => Type.initTag(.enum_literal),
.manyptr_u8_type => Type.initTag(.manyptr_u8),
.manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
+ .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0),
.atomic_order_type => Type.initTag(.atomic_order),
.atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
.calling_convention_type => Type.initTag(.calling_convention),
test/behavior/enum.zig
@@ -699,3 +699,126 @@ test "single field non-exhaustive enum" {
try S.doTheTest(23);
comptime try S.doTheTest(23);
}
+
+const EnumWithTagValues = enum(u4) {
+ A = 1 << 0,
+ B = 1 << 1,
+ C = 1 << 2,
+ D = 1 << 3,
+};
+test "enum with tag values don't require parens" {
+ try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
+}
+
+const MultipleChoice2 = enum(u32) {
+ Unspecified1,
+ A = 20,
+ Unspecified2,
+ B = 40,
+ Unspecified3,
+ C = 60,
+ Unspecified4,
+ D = 1000,
+ Unspecified5,
+};
+
+test "cast integer literal to enum" {
+ try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
+ try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
+}
+
+test "enum with specified and unspecified tag values" {
+ try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+ comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
+ try expect(@enumToInt(x) == 1000);
+ try expect(1234 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => 3,
+ MultipleChoice2.D => @as(u32, 1234),
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
+
+const Small2 = enum(u2) { One, Two };
+const Small = enum(u2) { One, Two, Three, Four };
+
+test "set enum tag type" {
+ {
+ var x = Small.One;
+ x = Small.Two;
+ comptime try expect(Tag(Small) == u2);
+ }
+ {
+ var x = Small2.One;
+ x = Small2.Two;
+ comptime try expect(Tag(Small2) == u2);
+ }
+}
+
+test "casting enum to its tag type" {
+ try testCastEnumTag(Small2.Two);
+ comptime try testCastEnumTag(Small2.Two);
+}
+
+fn testCastEnumTag(value: Small2) !void {
+ try expect(@enumToInt(value) == 1);
+}
+
+test "enum with 1 field but explicit tag type should still have the tag type" {
+ const Enum = enum(u8) {
+ B = 2,
+ };
+ comptime try expect(@sizeOf(Enum) == @sizeOf(u8));
+}
+
+test "signed integer as enum tag" {
+ const SignedEnum = enum(i2) {
+ A0 = -1,
+ A1 = 0,
+ A2 = 1,
+ };
+
+ try expect(@enumToInt(SignedEnum.A0) == -1);
+ try expect(@enumToInt(SignedEnum.A1) == 0);
+ try expect(@enumToInt(SignedEnum.A2) == 1);
+}
+
+test "enum with one member and custom tag type" {
+ const E = enum(u2) {
+ One,
+ };
+ try expect(@enumToInt(E.One) == 0);
+ const E2 = enum(u2) {
+ One = 2,
+ };
+ try expect(@enumToInt(E2.One) == 2);
+}
+
+test "enum with one member and u1 tag type @enumToInt" {
+ const Enum = enum(u1) {
+ Test,
+ };
+ try expect(@enumToInt(Enum.Test) == 0);
+}
+
+test "enum with comptime_int tag type" {
+ const Enum = enum(comptime_int) {
+ One = 3,
+ Two = 2,
+ Three = 1,
+ };
+ comptime try expect(Tag(Enum) == comptime_int);
+}
+
+test "enum with one member default to u0 tag type" {
+ const E0 = enum { X };
+ comptime try expect(Tag(E0) == u0);
+}
test/behavior/enum_llvm.zig
@@ -0,0 +1,49 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const mem = std.mem;
+const Tag = std.meta.Tag;
+
+test "@tagName" {
+ try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+ comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+}
+
+fn testEnumTagNameBare(n: anytype) []const u8 {
+ return @tagName(n);
+}
+
+const BareNumber = enum { One, Two, Three };
+
+test "@tagName non-exhaustive enum" {
+ try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
+ comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
+}
+const NonExhaustive = enum(u8) { A, B, _ };
+
+test "@tagName is null-terminated" {
+ const S = struct {
+ fn doTheTest(n: BareNumber) !void {
+ try expect(@tagName(n)[3] == 0);
+ }
+ };
+ try S.doTheTest(.Two);
+ try comptime S.doTheTest(.Two);
+}
+
+test "tag name with assigned enum values" {
+ const LocalFoo = enum(u8) {
+ A = 1,
+ B = 0,
+ };
+ var b = LocalFoo.B;
+ try expect(mem.eql(u8, @tagName(b), "B"));
+}
+
+const Bar = enum { A, B, C, D };
+
+test "enum literal casting to optional" {
+ var bar: ?Bar = undefined;
+ bar = .B;
+
+ try expect(bar.? == Bar.B);
+}
test/behavior/enum_stage1.zig
@@ -2,47 +2,7 @@ const expect = @import("std").testing.expect;
const mem = @import("std").mem;
const Tag = @import("std").meta.Tag;
-test "@tagName" {
- try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
- comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
-}
-
-test "@tagName non-exhaustive enum" {
- try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
- comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
-}
-
-test "@tagName is null-terminated" {
- const S = struct {
- fn doTheTest(n: BareNumber) !void {
- try expect(@tagName(n)[3] == 0);
- }
- };
- try S.doTheTest(.Two);
- try comptime S.doTheTest(.Two);
-}
-
-fn testEnumTagNameBare(n: anytype) []const u8 {
- return @tagName(n);
-}
-
-const BareNumber = enum { One, Two, Three };
-const NonExhaustive = enum(u8) { A, B, _ };
const Small2 = enum(u2) { One, Two };
-const Small = enum(u2) { One, Two, Three, Four };
-
-test "set enum tag type" {
- {
- var x = Small.One;
- x = Small.Two;
- comptime try expect(Tag(Small) == u2);
- }
- {
- var x = Small2.One;
- x = Small2.Two;
- comptime try expect(Tag(Small2) == u2);
- }
-}
const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
@@ -87,15 +47,6 @@ fn getC(data: *const BitFieldOfEnums) C {
return data.c;
}
-test "casting enum to its tag type" {
- try testCastEnumTag(Small2.Two);
- comptime try testCastEnumTag(Small2.Two);
-}
-
-fn testCastEnumTag(value: Small2) !void {
- try expect(@enumToInt(value) == 1);
-}
-
const MultipleChoice2 = enum(u32) {
Unspecified1,
A = 20,
@@ -108,31 +59,6 @@ const MultipleChoice2 = enum(u32) {
Unspecified5,
};
-test "enum with specified and unspecified tag values" {
- try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
- comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
- try expect(@enumToInt(x) == 1000);
- try expect(1234 == switch (x) {
- MultipleChoice2.A => 1,
- MultipleChoice2.B => 2,
- MultipleChoice2.C => 3,
- MultipleChoice2.D => @as(u32, 1234),
- MultipleChoice2.Unspecified1 => 5,
- MultipleChoice2.Unspecified2 => 6,
- MultipleChoice2.Unspecified3 => 7,
- MultipleChoice2.Unspecified4 => 8,
- MultipleChoice2.Unspecified5 => 9,
- });
-}
-
-test "cast integer literal to enum" {
- try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
- try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
-}
-
const EnumWithOneMember = enum { Eof };
fn doALoopThing(id: EnumWithOneMember) void {
@@ -157,32 +83,6 @@ test "switch on enum with one member is comptime known" {
@compileError("analysis should not reach here");
}
-const EnumWithTagValues = enum(u4) {
- A = 1 << 0,
- B = 1 << 1,
- C = 1 << 2,
- D = 1 << 3,
-};
-test "enum with tag values don't require parens" {
- try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
-}
-
-test "enum with 1 field but explicit tag type should still have the tag type" {
- const Enum = enum(u8) {
- B = 2,
- };
- comptime try expect(@sizeOf(Enum) == @sizeOf(u8));
-}
-
-test "tag name with assigned enum values" {
- const LocalFoo = enum(u8) {
- A = 1,
- B = 0,
- };
- var b = LocalFoo.B;
- try expect(mem.eql(u8, @tagName(b), "B"));
-}
-
test "enum literal in array literal" {
const Items = enum { one, two };
const array = [_]Items{ .one, .two };
@@ -191,18 +91,6 @@ test "enum literal in array literal" {
try expect(array[1] == .two);
}
-test "signed integer as enum tag" {
- const SignedEnum = enum(i2) {
- A0 = -1,
- A1 = 0,
- A2 = 1,
- };
-
- try expect(@enumToInt(SignedEnum.A0) == -1);
- try expect(@enumToInt(SignedEnum.A1) == 0);
- try expect(@enumToInt(SignedEnum.A2) == 1);
-}
-
test "enum value allocation" {
const LargeEnum = enum(u32) {
A0 = 0x80000000,
@@ -235,26 +123,8 @@ test "enum literal casting to tagged union" {
}
}
-test "enum with one member and custom tag type" {
- const E = enum(u2) {
- One,
- };
- try expect(@enumToInt(E.One) == 0);
- const E2 = enum(u2) {
- One = 2,
- };
- try expect(@enumToInt(E2.One) == 2);
-}
-
const Bar = enum { A, B, C, D };
-test "enum literal casting to optional" {
- var bar: ?Bar = undefined;
- bar = .B;
-
- try expect(bar.? == Bar.B);
-}
-
test "enum literal casting to error union with payload enum" {
var bar: error{B}!Bar = undefined;
bar = .B; // should never cast to the error set
@@ -262,27 +132,6 @@ test "enum literal casting to error union with payload enum" {
try expect((try bar) == Bar.B);
}
-test "enum with one member and u1 tag type @enumToInt" {
- const Enum = enum(u1) {
- Test,
- };
- try expect(@enumToInt(Enum.Test) == 0);
-}
-
-test "enum with comptime_int tag type" {
- const Enum = enum(comptime_int) {
- One = 3,
- Two = 2,
- Three = 1,
- };
- comptime try expect(Tag(Enum) == comptime_int);
-}
-
-test "enum with one member default to u0 tag type" {
- const E0 = enum { X };
- comptime try expect(Tag(E0) == u0);
-}
-
test "tagName on enum literals" {
try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
test/behavior.zig
@@ -75,6 +75,7 @@ test {
_ = @import("behavior/bugs/3112.zig");
_ = @import("behavior/bugs/7250.zig");
_ = @import("behavior/cast_llvm.zig");
+ _ = @import("behavior/enum_llvm.zig");
_ = @import("behavior/eval.zig");
_ = @import("behavior/floatop.zig");
_ = @import("behavior/fn.zig");